From c8498cc2c27b699436c5f3d3759695926ee0c825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 27 May 2016 19:05:22 -0700 Subject: [PATCH 001/768] Specific error message for missplaced doc comments Identify when documetation comments have been missplaced in the following places: * After a struct element: ```rust // file.rs: struct X { a: u8 /** document a */, } ``` ```bash $ rustc file.rs file.rs:2:11: 2:28 error: found documentation comment that doesn't document anything file.rs:2 a: u8 /** document a */, ^~~~~~~~~~~~~~~~~ file.rs:2:11: 2:28 help: doc comments must come before what they document, maybe a comment was intended with `//`? ``` * As the last line of a struct: ```rust // file.rs: struct X { a: u8, /// incorrect documentation } ``` ```bash $ rustc file.rs file.rs:3:5: 3:27 error: found a documentation comment that doesn't document anything file.rs:3 /// incorrect documentation ^~~~~~~~~~~~~~~~~~~~~~ file.rs:3:5: 3:27 help: doc comments must come before what they document, maybe a comment was intended with `//`? ``` * As the last line of a `fn`: ```rust // file.rs: fn main() { let x = 1; /// incorrect documentation } ``` ```bash $ rustc file.rs file.rs:3:5: 3:27 error: found a documentation comment that doesn't document anything file.rs:3 /// incorrect documentation ^~~~~~~~~~~~~~~~~~~~~~ file.rs:3:5: 3:27 help: doc comments must come before what they document, maybe a comment was intended with `//`? ``` Fix #27429, #30322 --- src/librustc_errors/lib.rs | 9 ++++ src/libsyntax/parse/parser.rs | 52 +++++++++++++------ src/libsyntax/parse/token.rs | 10 +++- src/test/parse-fail/doc-after-struct-field.rs | 20 +++++++ .../parse-fail/doc-before-extern-rbrace.rs | 2 +- src/test/parse-fail/doc-before-fn-rbrace.rs | 16 ++++++ src/test/parse-fail/doc-before-identifier.rs | 18 +++++++ src/test/parse-fail/doc-before-mod-rbrace.rs | 15 ++++++ src/test/parse-fail/doc-before-rbrace.rs | 3 +- src/test/parse-fail/doc-before-semi.rs | 3 +- .../parse-fail/doc-before-struct-rbrace-1.rs | 21 ++++++++ .../parse-fail/doc-before-struct-rbrace-2.rs | 20 +++++++ 12 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 src/test/parse-fail/doc-after-struct-field.rs create mode 100644 src/test/parse-fail/doc-before-fn-rbrace.rs create mode 100644 src/test/parse-fail/doc-before-identifier.rs create mode 100644 src/test/parse-fail/doc-before-mod-rbrace.rs create mode 100644 src/test/parse-fail/doc-before-struct-rbrace-1.rs create mode 100644 src/test/parse-fail/doc-before-struct-rbrace-2.rs diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 18fc826f9aa4b..1d0f185c60ada 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -564,6 +564,15 @@ impl Handler { self.bump_err_count(); self.panic_if_treat_err_as_bug(); } + pub fn mut_span_err<'a, S: Into>(&'a self, + sp: S, + msg: &str) + -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(self, Level::Error, msg); + result.set_span(sp); + self.bump_err_count(); + result + } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { self.emit_with_code(&sp.into(), msg, code, Error); self.bump_err_count(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6fa95afd9fb22..027b78c17d3d1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -578,12 +578,21 @@ impl<'a> Parser<'a> { self.bug("ident interpolation not converted to real token"); } _ => { - let mut err = self.fatal(&format!("expected identifier, found `{}`", - self.this_token_to_string())); - if self.token == token::Underscore { - err.note("`_` is a wildcard pattern, not an identifier"); - } - Err(err) + let last_token = self.last_token.clone().map(|t| *t); + Err(match last_token { + Some(token::DocComment(_)) => self.span_fatal_help(self.last_span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a comment was \ + intended with `//`?"), + _ => { + let mut err = self.fatal(&format!("expected identifier, found `{}`", + self.this_token_to_string())); + if self.token == token::Underscore { + err.note("`_` is a wildcard pattern, not an identifier"); + } + err + } + }) } } } @@ -985,6 +994,7 @@ impl<'a> Parser<'a> { // Stash token for error recovery (sometimes; clone is not necessarily cheap). self.last_token = if self.token.is_ident() || self.token.is_path() || + self.token.is_doc_comment() || self.token == token::Comma { Some(Box::new(self.token.clone())) } else { @@ -1076,6 +1086,11 @@ impl<'a> Parser<'a> { pub fn span_err(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } + pub fn span_err_help(&self, sp: Span, m: &str, h: &str) { + let mut err = self.sess.span_diagnostic.mut_span_err(sp, m); + err.help(h); + err.emit(); + } pub fn span_bug(&self, sp: Span, m: &str) -> ! { self.sess.span_diagnostic.span_bug(sp, m) } @@ -4029,8 +4044,14 @@ impl<'a> Parser<'a> { None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { - s.span_err(s.span, - "expected statement after outer attribute"); + let last_token = s.last_token.clone().map(|t| *t); + match last_token { + Some(token::DocComment(_)) => s.span_err_help(s.last_span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a \ + comment was intended with `//`?"), + _ => s.span_err(s.span, "expected statement after outer attribute"), + } } }; @@ -5198,14 +5219,13 @@ impl<'a> Parser<'a> { self.bump(); } token::CloseDelim(token::Brace) => {} - _ => { - let span = self.span; - let token_str = self.this_token_to_string(); - return Err(self.span_fatal_help(span, - &format!("expected `,`, or `}}`, found `{}`", - token_str), - "struct fields should be separated by commas")) - } + token::DocComment(_) => return Err(self.span_fatal_help(self.span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a comment was \ + intended with `//`?")), + _ => return Err(self.span_fatal_help(self.span, + &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()), + "struct fields should be separated by commas")), } Ok(a_var) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 8376d28164dee..3f78dffd31c2d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -202,7 +202,7 @@ impl Token { pub fn is_lit(&self) -> bool { match *self { Literal(_, _) => true, - _ => false, + _ => false, } } @@ -214,6 +214,14 @@ impl Token { } } + /// Returns `true` if the token is a documentation comment. + pub fn is_doc_comment(&self) -> bool { + match *self { + DocComment(..) => true, + _ => false, + } + } + /// Returns `true` if the token is interpolated. pub fn is_interpolated(&self) -> bool { match *self { diff --git a/src/test/parse-fail/doc-after-struct-field.rs b/src/test/parse-fail/doc-after-struct-field.rs new file mode 100644 index 0000000000000..1aa6af5b78f5b --- /dev/null +++ b/src/test/parse-fail/doc-after-struct-field.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: -Z continue-parse-after-error +struct X { + a: u8 /** document a */, + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + +fn main() { + let y = X {a = 1}; +} diff --git a/src/test/parse-fail/doc-before-extern-rbrace.rs b/src/test/parse-fail/doc-before-extern-rbrace.rs index 9e825193dc0d8..70da47ba9b4f0 100644 --- a/src/test/parse-fail/doc-before-extern-rbrace.rs +++ b/src/test/parse-fail/doc-before-extern-rbrace.rs @@ -12,5 +12,5 @@ extern { /// hi + //~^ ERROR expected item after doc comment } -//~^^ ERROR expected item after doc comment diff --git a/src/test/parse-fail/doc-before-fn-rbrace.rs b/src/test/parse-fail/doc-before-fn-rbrace.rs new file mode 100644 index 0000000000000..bcf32612c8f4c --- /dev/null +++ b/src/test/parse-fail/doc-before-fn-rbrace.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. + +// compile-flags: -Z continue-parse-after-error +fn main() { + /// document + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} diff --git a/src/test/parse-fail/doc-before-identifier.rs b/src/test/parse-fail/doc-before-identifier.rs new file mode 100644 index 0000000000000..8f1fad91b1f99 --- /dev/null +++ b/src/test/parse-fail/doc-before-identifier.rs @@ -0,0 +1,18 @@ +// 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: -Z continue-parse-after-error +fn /// document +foo() {} +//~^^ ERROR expected identifier, found `/// document` + +fn main() { + foo(); +} diff --git a/src/test/parse-fail/doc-before-mod-rbrace.rs b/src/test/parse-fail/doc-before-mod-rbrace.rs new file mode 100644 index 0000000000000..d38d1876384a8 --- /dev/null +++ b/src/test/parse-fail/doc-before-mod-rbrace.rs @@ -0,0 +1,15 @@ +// 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: -Z continue-parse-after-error +mod Foo { + /// document + //~^ ERROR expected item after doc comment +} diff --git a/src/test/parse-fail/doc-before-rbrace.rs b/src/test/parse-fail/doc-before-rbrace.rs index 295d5ae432ecb..48ea2b5aea12c 100644 --- a/src/test/parse-fail/doc-before-rbrace.rs +++ b/src/test/parse-fail/doc-before-rbrace.rs @@ -12,5 +12,6 @@ fn main() { println!("Hi"); /// hi + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended } -//~^ ERROR expected statement diff --git a/src/test/parse-fail/doc-before-semi.rs b/src/test/parse-fail/doc-before-semi.rs index 6a8906953be09..71104b8caae19 100644 --- a/src/test/parse-fail/doc-before-semi.rs +++ b/src/test/parse-fail/doc-before-semi.rs @@ -12,6 +12,7 @@ fn main() { /// hi + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended ; - //~^ ERROR expected statement } diff --git a/src/test/parse-fail/doc-before-struct-rbrace-1.rs b/src/test/parse-fail/doc-before-struct-rbrace-1.rs new file mode 100644 index 0000000000000..5ba83190c8e50 --- /dev/null +++ b/src/test/parse-fail/doc-before-struct-rbrace-1.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +struct X { + a: u8, + /// document + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + +fn main() { + let y = X {a = 1}; +} diff --git a/src/test/parse-fail/doc-before-struct-rbrace-2.rs b/src/test/parse-fail/doc-before-struct-rbrace-2.rs new file mode 100644 index 0000000000000..643e4aa17a1ac --- /dev/null +++ b/src/test/parse-fail/doc-before-struct-rbrace-2.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: -Z continue-parse-after-error +struct X { + a: u8 /// document + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + +fn main() { + let y = X {a = 1}; +} From 7de83f085856eda5e54bd02713267101ac015c1a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 19 Jul 2016 20:55:46 +0300 Subject: [PATCH 002/768] Deny (by default) transmuting from fn item types to pointer-sized types. --- src/librustc/lint/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 3230a08c27630..8db1fd92530d3 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -157,7 +157,7 @@ declare_lint! { declare_lint! { pub TRANSMUTE_FROM_FN_ITEM_TYPES, - Warn, + Deny, "transmute from function item type to pointer-sized type erroneously allowed" } From 8ec47261e193b1f983b898a0d985b85e7fcb0668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 26 Jul 2016 15:18:44 +0200 Subject: [PATCH 003/768] Use monotonic time with condition variables. Configure condition variables to use monotonic time using pthread_condattr_setclock on systems where this is possible. This fixes the issue when thread waiting on condition variable is woken up too late when system time is moved backwards. --- src/libstd/sync/condvar.rs | 6 ++- src/libstd/sys/common/condvar.rs | 7 ++++ src/libstd/sys/unix/condvar.rs | 67 +++++++++++++++++++++++++++---- src/libstd/sys/windows/condvar.rs | 3 ++ 4 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 3c52ebc72f2cb..ca1a9905ebe67 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -82,10 +82,14 @@ impl Condvar { /// notified. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Condvar { - Condvar { + let mut c = Condvar { inner: box sys::Condvar::new(), mutex: AtomicUsize::new(0), + }; + unsafe { + c.inner.init(); } + c } /// Blocks the current thread until this condition variable receives a diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys/common/condvar.rs index 33734a88cf32b..b6f29dd5fc3d3 100644 --- a/src/libstd/sys/common/condvar.rs +++ b/src/libstd/sys/common/condvar.rs @@ -27,6 +27,13 @@ impl Condvar { /// first used with any of the functions below. pub const fn new() -> Condvar { Condvar(imp::Condvar::new()) } + /// Prepares the condition variable for use. + /// + /// This should be called once the condition variable is at a stable memory + /// address. + #[inline] + pub unsafe fn init(&mut self) { self.0.init() } + /// Signals one waiter on this condition variable to wake up. #[inline] pub unsafe fn notify_one(&self) { self.0.notify_one() } diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 2e1c1900b46b3..725a071a4f9fe 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -10,15 +10,19 @@ use cell::UnsafeCell; use libc; -use ptr; use sys::mutex::{self, Mutex}; -use time::{Instant, Duration}; +use time::Duration; pub struct Condvar { inner: UnsafeCell } unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} +const TIMESPEC_MAX: libc::timespec = libc::timespec { + tv_sec: ::max_value(), + tv_nsec: 1_000_000_000 - 1, +}; + impl Condvar { pub const fn new() -> Condvar { // Might be moved and address is changing it is better to avoid @@ -26,6 +30,23 @@ impl Condvar { Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } } + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub unsafe fn init(&mut self) {} + + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + pub unsafe fn init(&mut self) { + use mem; + let mut attr: libc::pthread_condattr_t = mem::uninitialized(); + let r = libc::pthread_condattr_init(&mut attr); + assert_eq!(r, 0); + let r = libc::pthread_condattr_setclock(&mut attr, libc::CLOCK_MONOTONIC); + assert_eq!(r, 0); + let r = libc::pthread_cond_init(self.inner.get(), &attr); + assert_eq!(r, 0); + let r = libc::pthread_condattr_destroy(&mut attr); + assert_eq!(r, 0); + } + #[inline] pub unsafe fn notify_one(&self) { let r = libc::pthread_cond_signal(self.inner.get()); @@ -44,10 +65,45 @@ impl Condvar { debug_assert_eq!(r, 0); } + // This implementation is used on systems that support pthread_condattr_setclock + // where we configure condition variable to use monotonic clock (instead of + // default system clock). This approach avoids all problems that result + // from changes made to the system time. + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + use mem; + + let mut now: libc::timespec = mem::zeroed(); + let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); + assert_eq!(r, 0); + + // Nanosecond calculations can't overflow because both values are below 1e9. + let nsec = dur.subsec_nanos() as libc::c_long + now.tv_nsec as libc::c_long; + // FIXME: Casting u64 into time_t could truncate the value. + let sec = (dur.as_secs() as libc::time_t) + .checked_add((nsec / 1_000_000_000) as libc::time_t) + .and_then(|s| s.checked_add(now.tv_sec)); + let nsec = nsec % 1_000_000_000; + + let timeout = sec.map(|s| { + libc::timespec { tv_sec: s, tv_nsec: nsec } + }).unwrap_or(TIMESPEC_MAX); + + let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), + &timeout); + assert!(r == libc::ETIMEDOUT || r == 0); + r == 0 + } + + // This implementation is modeled after libcxx's condition_variable // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 + #[cfg(any(target_os = "macos", target_os = "ios"))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + use ptr; + use time::Instant; + // First, figure out what time it currently is, in both system and // stable time. pthread_cond_timedwait uses system time, but we want to // report timeout based on stable time. @@ -66,12 +122,7 @@ impl Condvar { s.checked_add(seconds) }).map(|s| { libc::timespec { tv_sec: s, tv_nsec: nsec } - }).unwrap_or_else(|| { - libc::timespec { - tv_sec: ::max_value(), - tv_nsec: 1_000_000_000 - 1, - } - }); + }).unwrap_or(TIMESPEC_MAX); // And wait! let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs index 8075374d42bdd..d708b327c55cb 100644 --- a/src/libstd/sys/windows/condvar.rs +++ b/src/libstd/sys/windows/condvar.rs @@ -24,6 +24,9 @@ impl Condvar { Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } + #[inline] + pub unsafe fn init(&mut self) {} + #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { let r = c::SleepConditionVariableSRW(self.inner.get(), From bf592cefde313aed68bccc91c053f5912350249b Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Thu, 4 Aug 2016 21:33:57 -0700 Subject: [PATCH 004/768] Made vec_deque::Drain, hash_map::Drain, and hash_set::Drain covariant --- src/libcollections/vec_deque.rs | 7 ++++--- src/libcollectionstest/vec_deque.rs | 6 ++++++ src/libstd/collections/hash/map.rs | 2 ++ src/libstd/collections/hash/set.rs | 1 + src/libstd/collections/hash/table.rs | 16 ++++++++++------ 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 9c3792afa2f1c..812a67a7e78ed 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -24,6 +24,7 @@ use core::iter::{repeat, FromIterator}; use core::mem; use core::ops::{Index, IndexMut}; use core::ptr; +use core::ptr::Shared; use core::slice; use core::hash::{Hash, Hasher}; @@ -903,7 +904,7 @@ impl VecDeque { self.head = drain_tail; Drain { - deque: self as *mut _, + deque: unsafe { Shared::new(self as *mut _) }, after_tail: drain_head, after_head: head, iter: Iter { @@ -1985,7 +1986,7 @@ pub struct Drain<'a, T: 'a> { after_tail: usize, after_head: usize, iter: Iter<'a, T>, - deque: *mut VecDeque, + deque: Shared>, } #[stable(feature = "drain", since = "1.6.0")] @@ -1998,7 +1999,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { for _ in self.by_ref() {} - let source_deque = unsafe { &mut *self.deque }; + let source_deque = unsafe { &mut **self.deque }; // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head // diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index a02666a50c225..5e8633a974824 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -10,6 +10,7 @@ use std::collections::VecDeque; use std::fmt::Debug; +use std::collections::vec_deque::Drain; use test; @@ -999,3 +1000,8 @@ fn test_contains() { assert!(!v.contains(&3)); } + +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } +} diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fd7b0a2e6bbf6..e30cf638c6d38 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2036,6 +2036,8 @@ fn assert_covariance() { fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { v } fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { v } fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { v } + fn drain<'new>(d: Drain<'static, &'static str, &'static str>) + -> Drain<'new, &'new str, &'new str> { d } } #[cfg(test)] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e4ef3fca55dc7..837c5d8b8e18c 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1036,6 +1036,7 @@ fn assert_covariance() { -> Intersection<'a, &'new str, RandomState> { v } fn union<'a, 'new>(v: Union<'a, &'static str, RandomState>) -> Union<'a, &'new str, RandomState> { v } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } } #[cfg(test)] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index c4c4cb453134f..02931e5e3890d 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -17,7 +17,7 @@ use marker; use mem::{align_of, size_of}; use mem; use ops::{Deref, DerefMut}; -use ptr::{self, Unique}; +use ptr::{self, Unique, Shared}; use self::BucketState::*; @@ -754,7 +754,8 @@ impl RawTable { hashes_end: hashes_end, marker: marker::PhantomData, }, - table: self, + table: unsafe { Shared::new(self) }, + marker: marker::PhantomData, } } @@ -897,8 +898,9 @@ unsafe impl Send for IntoIter {} /// Iterator over the entries in a table, clearing the table. pub struct Drain<'a, K: 'a, V: 'a> { - table: &'a mut RawTable, + table: Shared>, iter: RawBuckets<'static, K, V>, + marker: marker::PhantomData<&'a RawTable>, } unsafe impl<'a, K: Sync, V: Sync> Sync for Drain<'a, K, V> {} @@ -973,8 +975,8 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { self.iter.next().map(|bucket| { - self.table.size -= 1; unsafe { + (**self.table).size -= 1; (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, ptr::read(bucket.key), ptr::read(bucket.val)) @@ -983,13 +985,15 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { } fn size_hint(&self) -> (usize, Option) { - let size = self.table.size(); + let size = unsafe { (**self.table).size() }; (size, Some(size)) } } impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - self.table.size() + unsafe { + (**self.table).size() + } } } From 9926b33276cb3a349952d8d47a5d8b17bbb3cbdf Mon Sep 17 00:00:00 2001 From: Caleb Jones Date: Wed, 20 Jul 2016 18:23:52 -0400 Subject: [PATCH 005/768] Fix overflow checking in unsigned pow() The pow() method for unsigned integers produced 0 instead of trapping overflow for certain inputs. Calls such as 2u32.pow(1024) produced 0 when they should trap an overflow. This also adds tests for the correctly handling overflow in unsigned pow(). For issue number #34913 --- src/libcore/num/mod.rs | 26 ++++++++----------- ...owing-pow.rs => overflowing-pow-signed.rs} | 0 src/test/run-fail/overflowing-pow-unsigned.rs | 16 ++++++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) rename src/test/run-fail/{overflowing-pow.rs => overflowing-pow-signed.rs} (100%) create mode 100644 src/test/run-fail/overflowing-pow-unsigned.rs diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4636811aa46da..1032826a09353 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2217,25 +2217,21 @@ macro_rules! uint_impl { let mut base = self; let mut acc = 1; - let mut prev_base = self; - let mut base_oflo = false; - while exp > 0 { + while exp > 1 { if (exp & 1) == 1 { - if base_oflo { - // ensure overflow occurs in the same manner it - // would have otherwise (i.e. signal any exception - // it would have otherwise). - acc = acc * (prev_base * prev_base); - } else { - acc = acc * base; - } + acc = acc * base; } - prev_base = base; - let (new_base, new_base_oflo) = base.overflowing_mul(base); - base = new_base; - base_oflo = new_base_oflo; exp /= 2; + base = base * base; } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc * base; + } + acc } diff --git a/src/test/run-fail/overflowing-pow.rs b/src/test/run-fail/overflowing-pow-signed.rs similarity index 100% rename from src/test/run-fail/overflowing-pow.rs rename to src/test/run-fail/overflowing-pow-signed.rs diff --git a/src/test/run-fail/overflowing-pow-unsigned.rs b/src/test/run-fail/overflowing-pow-unsigned.rs new file mode 100644 index 0000000000000..5dca7795462eb --- /dev/null +++ b/src/test/run-fail/overflowing-pow-unsigned.rs @@ -0,0 +1,16 @@ +// 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. + +// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// compile-flags: -C debug-assertions + +fn main() { + let _x = 2u32.pow(1024); +} From b8c4e9c235db5f67129abdae8f336e06bf2bc8ba Mon Sep 17 00:00:00 2001 From: Caleb Jones Date: Sat, 6 Aug 2016 23:58:16 -0400 Subject: [PATCH 006/768] Change the expected panic message for unsigned --- src/test/run-fail/overflowing-pow-unsigned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-fail/overflowing-pow-unsigned.rs b/src/test/run-fail/overflowing-pow-unsigned.rs index 5dca7795462eb..d3e7035279fbe 100644 --- a/src/test/run-fail/overflowing-pow-unsigned.rs +++ b/src/test/run-fail/overflowing-pow-unsigned.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions fn main() { From 127489a89636898bf40101e39faaf91f2f0a308f Mon Sep 17 00:00:00 2001 From: DarkEld3r Date: Tue, 9 Aug 2016 13:13:04 +0300 Subject: [PATCH 007/768] Update compiler error 0093 to use new error format --- src/librustc_typeck/check/intrinsic.rs | 7 +++++-- src/test/compile-fail/E0093.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 8a53c59b4c7fa..33452b441ca81 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -297,8 +297,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { } ref other => { - span_err!(tcx.sess, it.span, E0093, - "unrecognized intrinsic function: `{}`", *other); + struct_span_err!(tcx.sess, it.span, E0093, + "unrecognized intrinsic function: `{}`", + *other) + .span_label(it.span, &format!("unrecognized intrinsic")) + .emit(); return; } }; diff --git a/src/test/compile-fail/E0093.rs b/src/test/compile-fail/E0093.rs index 9b23f6d984ee1..fdc48455a679c 100644 --- a/src/test/compile-fail/E0093.rs +++ b/src/test/compile-fail/E0093.rs @@ -10,7 +10,9 @@ #![feature(intrinsics)] extern "rust-intrinsic" { - fn foo(); //~ ERROR E0093 + fn foo(); + //~^ ERROR E0093 + //~| NOTE unrecognized intrinsic } fn main() { From 471407205b0f0daccc57fe20e5260c0b199aa464 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Wed, 10 Aug 2016 20:11:03 -0400 Subject: [PATCH 008/768] gdb: Fix pretty-printing special-cased Rust types gdb trunk now reports fully qualified type names, just like lldb. Move lldb code for extracting unqualified names to shared file. --- src/etc/debugger_pretty_printers_common.py | 17 +++++++++++++++++ src/etc/gdb_rust_pretty_printing.py | 2 +- src/etc/lldb_rust_formatters.py | 21 ++------------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py index b2bb7859661ab..e713c7c8387fc 100644 --- a/src/etc/debugger_pretty_printers_common.py +++ b/src/etc/debugger_pretty_printers_common.py @@ -324,3 +324,20 @@ def extract_length_and_ptr_from_slice(slice_val): assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR return (length, data_ptr) + +UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"]) + +def extract_type_name(qualified_type_name): + '''Extracts the type name from a fully qualified path''' + if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS: + return qualified_type_name + + end_of_search = qualified_type_name.find("<") + if end_of_search < 0: + end_of_search = len(qualified_type_name) + + index = qualified_type_name.rfind("::", 0, end_of_search) + if index < 0: + return qualified_type_name + else: + return qualified_type_name[index + 2:] diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 554ab66bc563d..d083558d23cd8 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -36,7 +36,7 @@ def get_unqualified_type_name(self): if tag is None: return tag - return tag.replace("&'static ", "&") + return rustpp.extract_type_name(tag).replace("&'static ", "&") def get_dwarf_type_kind(self): if self.ty.code == gdb.TYPE_CODE_STRUCT: diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py index c22a60abf3f76..c0a4c3e9ece93 100644 --- a/src/etc/lldb_rust_formatters.py +++ b/src/etc/lldb_rust_formatters.py @@ -29,7 +29,7 @@ def get_unqualified_type_name(self): if qualified_name is None: return qualified_name - return extract_type_name(qualified_name).replace("&'static ", "&") + return rustpp.extract_type_name(qualified_name).replace("&'static ", "&") def get_dwarf_type_kind(self): type_class = self.ty.GetTypeClass() @@ -204,7 +204,7 @@ def render_child(child_index): # LLDB is not good at handling zero-sized values, so we have to help # it a little if field.GetType().GetByteSize() == 0: - return this + extract_type_name(field.GetType().GetName()) + return this + rustpp.extract_type_name(field.GetType().GetName()) else: return this + "" @@ -274,23 +274,6 @@ def print_std_string_val(val, internal_dict): # Helper Functions #=-------------------------------------------------------------------------------------------------- -UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"]) - -def extract_type_name(qualified_type_name): - '''Extracts the type name from a fully qualified path''' - if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS: - return qualified_type_name - - end_of_search = qualified_type_name.find("<") - if end_of_search < 0: - end_of_search = len(qualified_type_name) - - index = qualified_type_name.rfind("::", 0, end_of_search) - if index < 0: - return qualified_type_name - else: - return qualified_type_name[index + 2:] - def print_array_of_values(array_name, data_ptr_val, length, internal_dict): '''Prints a contigous memory range, interpreting it as values of the pointee-type of data_ptr_val.''' From b9762f8b8c5576fec873132876c4ea0f624e486c Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Mon, 8 Aug 2016 16:37:44 -0400 Subject: [PATCH 009/768] Update E0033 to the new error format --- src/librustc_typeck/check/_match.rs | 8 +++++--- src/test/compile-fail/E0033.rs | 6 +++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5f255cc1fb730..db161379920e3 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -347,9 +347,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let ty::TyTrait(..) = mt.ty.sty { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. - span_err!(self.tcx.sess, span, E0033, - "type `{}` cannot be dereferenced", - self.ty_to_string(expected)); + let type_str = self.ty_to_string(expected); + struct_span_err!(self.tcx.sess, span, E0033, + "type `{}` cannot be dereferenced", type_str) + .span_label(span, &format!("type `{}` cannot be dereferenced", type_str)) + .emit(); return false } } diff --git a/src/test/compile-fail/E0033.rs b/src/test/compile-fail/E0033.rs index 946600013f33d..fe75b6b1f0f1b 100644 --- a/src/test/compile-fail/E0033.rs +++ b/src/test/compile-fail/E0033.rs @@ -15,5 +15,9 @@ trait SomeTrait { fn main() { let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425 //~^ ERROR E0038 - let &invalid = trait_obj; //~ ERROR E0033 + //~| method `foo` has no receiver + + let &invalid = trait_obj; + //~^ ERROR E0033 + //~| NOTE type `&SomeTrait` cannot be dereferenced } From 80beeb35744f97d65759fec662043cbe34857e8b Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Thu, 11 Aug 2016 14:03:38 -0400 Subject: [PATCH 010/768] Add additional error note --- src/test/compile-fail/E0033.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/E0033.rs b/src/test/compile-fail/E0033.rs index fe75b6b1f0f1b..8a1cd2ef4b71c 100644 --- a/src/test/compile-fail/E0033.rs +++ b/src/test/compile-fail/E0033.rs @@ -16,6 +16,7 @@ fn main() { let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425 //~^ ERROR E0038 //~| method `foo` has no receiver + //~| NOTE the trait `SomeTrait` cannot be made into an object let &invalid = trait_obj; //~^ ERROR E0033 From 2ed052d82ffdeb57c479d78a00f680fb4fef9732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20H=C3=BCgel?= Date: Thu, 11 Aug 2016 20:05:05 +0200 Subject: [PATCH 011/768] Clarify type declaration language --- src/doc/book/associated-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/associated-types.md b/src/doc/book/associated-types.md index cb54ac2419ecd..d64a4beacdd8f 100644 --- a/src/doc/book/associated-types.md +++ b/src/doc/book/associated-types.md @@ -67,7 +67,7 @@ trait Graph { Simple enough. Associated types use the `type` keyword, and go inside the body of the trait, with the functions. -These `type` declarations can have all the same thing as functions do. For example, +These `type` declarations work in the same way as those for functions do. For example, if we wanted our `N` type to implement `Display`, so we can print the nodes out, we could do this: From 31da7f6f25946e2962df78920727d3d593346cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20H=C3=BCgel?= Date: Thu, 11 Aug 2016 20:37:26 +0200 Subject: [PATCH 012/768] More clarification --- src/doc/book/associated-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/associated-types.md b/src/doc/book/associated-types.md index d64a4beacdd8f..0998a88c4d241 100644 --- a/src/doc/book/associated-types.md +++ b/src/doc/book/associated-types.md @@ -67,7 +67,7 @@ trait Graph { Simple enough. Associated types use the `type` keyword, and go inside the body of the trait, with the functions. -These `type` declarations work in the same way as those for functions do. For example, +These type declarations work the same way as those for functions. For example, if we wanted our `N` type to implement `Display`, so we can print the nodes out, we could do this: From 5be8df95c74514ade77c81a7afff1f4df3208bbd Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 11 Aug 2016 15:42:41 -0600 Subject: [PATCH 013/768] Fix language in documentation comment. --- src/librustc_bitflags/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_bitflags/lib.rs b/src/librustc_bitflags/lib.rs index afc2e04d446a1..7e96adfc4bdbc 100644 --- a/src/librustc_bitflags/lib.rs +++ b/src/librustc_bitflags/lib.rs @@ -201,7 +201,7 @@ macro_rules! bitflags { !(*self & other).is_empty() } - /// Returns `true` all of the flags in `other` are contained within `self`. + /// Returns `true` if all of the flags in `other` are contained within `self`. #[inline] pub fn contains(&self, other: $BitFlags) -> bool { (*self & other) == other From 91a2c25e2e8dc641decb04aba4e0338f199c8785 Mon Sep 17 00:00:00 2001 From: JessRudder Date: Thu, 11 Aug 2016 18:44:19 -0400 Subject: [PATCH 014/768] Add note to docs for &str that example is to demo internals only --- src/libstd/primitive_docs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index de891ea89189a..6a470a52aa66c 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -385,6 +385,9 @@ mod prim_slice { } /// /// [`.as_ptr()`]: #method.as_ptr /// [`len()`]: #method.len +/// +/// Note: This example shows the internals of `&str`. `unsafe` should not be +/// used to get a string slice under normal circumstances. mod prim_str { } #[doc(primitive = "tuple")] From d6526395244f533fd8cfd3bc1a86e2b5da963860 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 6 Jun 2016 20:22:48 +0530 Subject: [PATCH 015/768] run rustfmt on libsyntax_ext folder --- src/libsyntax_ext/asm.rs | 78 ++++++----- src/libsyntax_ext/cfg.rs | 2 +- src/libsyntax_ext/concat.rs | 8 +- src/libsyntax_ext/concat_idents.rs | 34 +++-- src/libsyntax_ext/deriving/generic/ty.rs | 133 ++++++++++--------- src/libsyntax_ext/deriving/mod.rs | 12 +- src/libsyntax_ext/env.rs | 80 ++++++------ src/libsyntax_ext/format.rs | 157 +++++++++++++---------- src/libsyntax_ext/lib.rs | 12 +- src/libsyntax_ext/log_syntax.rs | 2 +- src/libsyntax_ext/trace_macros.rs | 2 +- 11 files changed, 273 insertions(+), 247 deletions(-) diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 9cf456062385f..6f368e1bc6f06 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/* - * Inline assembly support. - */ +// Inline assembly support. +// use self::State::*; use syntax::ast; @@ -31,43 +30,48 @@ enum State { Inputs, Clobbers, Options, - StateNone + StateNone, } impl State { fn next(&self) -> State { match *self { - Asm => Outputs, - Outputs => Inputs, - Inputs => Clobbers, - Clobbers => Options, - Options => StateNone, - StateNone => StateNone + Asm => Outputs, + Outputs => Inputs, + Inputs => Clobbers, + Clobbers => Options, + Options => StateNone, + StateNone => StateNone, } } } const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; -pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) - -> Box { +pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) + -> Box { if !cx.ecfg.enable_asm() { - feature_gate::emit_feature_err( - &cx.parse_sess.span_diagnostic, "asm", sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_ASM); + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "asm", + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_ASM); return DummyResult::expr(sp); } // Split the tts before the first colon, to avoid `asm!("x": y)` being // parsed as `asm!(z)` with `z = "x": y` which is type ascription. - let first_colon = tts.iter().position(|tt| { - match *tt { - tokenstream::TokenTree::Token(_, token::Colon) | - tokenstream::TokenTree::Token(_, token::ModSep) => true, - _ => false - } - }).unwrap_or(tts.len()); + let first_colon = tts.iter() + .position(|tt| { + match *tt { + tokenstream::TokenTree::Token(_, token::Colon) | + tokenstream::TokenTree::Token(_, token::ModSep) => true, + _ => false, + } + }) + .unwrap_or(tts.len()); let mut p = cx.new_parser_from_tts(&tts[first_colon..]); let mut asm = token::InternedString::new(""); let mut asm_str_style = None; @@ -91,8 +95,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token } // Nested parser, stop before the first colon (see above). let mut p2 = cx.new_parser_from_tts(&tts[..first_colon]); - let (s, style) = match expr_to_string(cx, panictry!(p2.parse_expr()), - "inline assembly must be a string literal") { + let (s, style) = match expr_to_string(cx, + panictry!(p2.parse_expr()), + "inline assembly must be a string literal") { Some((s, st)) => (s, st), // let compilation continue None => return DummyResult::expr(sp), @@ -109,9 +114,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token asm_str_style = Some(style); } Outputs => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { + while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep { if !outputs.is_empty() { p.eat(&token::Comma); @@ -136,8 +139,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token let output = match ch.next() { Some('=') => None, Some('+') => { - Some(token::intern_and_get_ident(&format!( - "={}", ch.as_str()))) + Some(token::intern_and_get_ident(&format!("={}", ch.as_str()))) } _ => { cx.span_err(span, "output operand constraint lacks '=' or '+'"); @@ -156,9 +158,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token } } Inputs => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { + while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep { if !inputs.is_empty() { p.eat(&token::Comma); @@ -180,9 +180,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token } } Clobbers => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { + while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep { if !clobs.is_empty() { p.eat(&token::Comma); @@ -218,25 +216,25 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token p.eat(&token::Comma); } } - StateNone => () + StateNone => (), } loop { // MOD_SEP is a double colon '::' without space in between. // When encountered, the state must be advanced twice. match (&p.token, state.next(), state.next().next()) { - (&token::Colon, StateNone, _) | + (&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => { p.bump(); break 'statement; } - (&token::Colon, st, _) | + (&token::Colon, st, _) | (&token::ModSep, _, st) => { p.bump(); state = st; } (&token::Eof, _, _) => break 'statement, - _ => break + _ => break, } } } diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index dbf23328f41fe..169ef9ab7d635 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -23,7 +23,7 @@ use syntax_pos::Span; pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) - -> Box { + -> Box { let mut p = cx.new_parser_from_tts(tts); let cfg = panictry!(p.parse_meta_item()); diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 22c4aeefbd169..02b44f2d012ea 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -20,10 +20,10 @@ use std::string::String; pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, sp: syntax_pos::Span, tts: &[tokenstream::TokenTree]) - -> Box { + -> Box { let es = match base::get_exprs_from_tts(cx, sp, tts) { Some(e) => e, - None => return base::DummyResult::expr(sp) + None => return base::DummyResult::expr(sp), }; let mut accumulator = String::new(); for e in es { @@ -57,7 +57,5 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, } } } - base::MacEager::expr(cx.expr_str( - sp, - token::intern_and_get_ident(&accumulator[..]))) + base::MacEager::expr(cx.expr_str(sp, token::intern_and_get_ident(&accumulator[..]))) } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 870413a7f61b0..15aaf3c78237f 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -18,8 +18,10 @@ use syntax::ptr::P; use syntax_pos::Span; use syntax::tokenstream::TokenTree; -pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box { +pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[TokenTree]) + -> Box { if !cx.ecfg.enable_concat_idents() { feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, "concat_idents", @@ -33,35 +35,40 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) for (i, e) in tts.iter().enumerate() { if i & 1 == 1 { match *e { - TokenTree::Token(_, token::Comma) => {}, + TokenTree::Token(_, token::Comma) => {} _ => { cx.span_err(sp, "concat_idents! expecting comma."); return DummyResult::expr(sp); - }, + } } } else { match *e { - TokenTree::Token(_, token::Ident(ident)) => { - res_str.push_str(&ident.name.as_str()) - }, + TokenTree::Token(_, token::Ident(ident)) => res_str.push_str(&ident.name.as_str()), _ => { cx.span_err(sp, "concat_idents! requires ident args."); return DummyResult::expr(sp); - }, + } } } } let res = str_to_ident(&res_str); - struct Result { ident: ast::Ident, span: Span }; + struct Result { + ident: ast::Ident, + span: Span, + }; impl Result { fn path(&self) -> ast::Path { let segment = ast::PathSegment { identifier: self.ident, - parameters: ast::PathParameters::none() + parameters: ast::PathParameters::none(), }; - ast::Path { span: self.span, global: false, segments: vec![segment] } + ast::Path { + span: self.span, + global: false, + segments: vec![segment], + } } } @@ -84,5 +91,8 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) } } - Box::new(Result { ident: res, span: sp }) + Box::new(Result { + ident: res, + span: sp, + }) } diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 626fbaada5cbf..356c54fcf3120 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -36,20 +36,20 @@ pub enum PtrTy<'a> { /// for type parameters and a lifetime. #[derive(Clone, Eq, PartialEq)] pub struct Path<'a> { - pub path: Vec<&'a str> , + pub path: Vec<&'a str>, pub lifetime: Option<&'a str>, pub params: Vec>>, pub global: bool, } impl<'a> Path<'a> { - pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> { + pub fn new<'r>(path: Vec<&'r str>) -> Path<'r> { Path::new_(path, None, Vec::new(), true) } pub fn new_local<'r>(path: &'r str) -> Path<'r> { - Path::new_(vec!( path ), None, Vec::new(), false) + Path::new_(vec![path], None, Vec::new(), false) } - pub fn new_<'r>(path: Vec<&'r str> , + pub fn new_<'r>(path: Vec<&'r str>, lifetime: Option<&'r str>, params: Vec>>, global: bool) @@ -58,7 +58,7 @@ impl<'a> Path<'a> { path: path, lifetime: lifetime, params: params, - global: global + global: global, } } @@ -94,7 +94,7 @@ pub enum Ty<'a> { /// parameter, and things like `i32` Literal(Path<'a>), /// includes unit - Tuple(Vec> ) + Tuple(Vec>), } pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { @@ -119,14 +119,14 @@ pub fn nil_ty<'r>() -> Ty<'r> { fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option { match *lt { Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)), - None => None + None => None, } } fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec { match *lt { - Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)), - None => vec!() + Some(ref s) => vec![cx.lifetime(span, cx.ident_of(*s).name)], + None => vec![], } } @@ -145,13 +145,11 @@ impl<'a> Ty<'a> { let lt = mk_lifetime(cx, span, lt); cx.ty_rptr(span, raw_ty, lt, mutbl) } - Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl) + Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl), } } - Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } - Self_ => { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } + Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics), + Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), Tuple(ref fields) => { let ty = ast::TyKind::Tup(fields.iter() .map(|f| f.to_ty(cx, span, self_ty, self_generics)) @@ -169,20 +167,25 @@ impl<'a> Ty<'a> { -> ast::Path { match *self { Self_ => { - let self_params = self_generics.ty_params.iter().map(|ty_param| { - cx.ty_ident(span, ty_param.ident) - }).collect(); - let lifetimes = self_generics.lifetimes.iter() - .map(|d| d.lifetime) - .collect(); + let self_params = self_generics.ty_params + .iter() + .map(|ty_param| cx.ty_ident(span, ty_param.ident)) + .collect(); + let lifetimes = self_generics.lifetimes + .iter() + .map(|d| d.lifetime) + .collect(); - cx.path_all(span, false, vec![self_ty], lifetimes, self_params, Vec::new()) - } - Literal(ref p) => { - p.to_path(cx, span, self_ty, self_generics) + cx.path_all(span, + false, + vec![self_ty], + lifetimes, + self_params, + Vec::new()) } - Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `derive`") } - Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `derive`") } + Literal(ref p) => p.to_path(cx, span, self_ty, self_generics), + Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"), + Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"), } } } @@ -195,16 +198,16 @@ fn mk_ty_param(cx: &ExtCtxt, self_ident: Ident, self_generics: &Generics) -> ast::TyParam { - let bounds = - bounds.iter().map(|b| { + let bounds = bounds.iter() + .map(|b| { let path = b.to_path(cx, span, self_ident, self_generics); cx.typarambound(path) - }).collect(); + }) + .collect(); cx.typaram(span, cx.ident_of(name), bounds, None) } -fn mk_generics(lifetimes: Vec, ty_params: Vec) - -> Generics { +fn mk_generics(lifetimes: Vec, ty_params: Vec) -> Generics { Generics { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), @@ -225,7 +228,8 @@ pub struct LifetimeBounds<'a> { impl<'a> LifetimeBounds<'a> { pub fn empty() -> LifetimeBounds<'a> { LifetimeBounds { - lifetimes: Vec::new(), bounds: Vec::new() + lifetimes: Vec::new(), + bounds: Vec::new(), } } pub fn to_generics(&self, @@ -234,46 +238,49 @@ impl<'a> LifetimeBounds<'a> { self_ty: Ident, self_generics: &Generics) -> Generics { - let lifetimes = self.lifetimes.iter().map(|&(ref lt, ref bounds)| { - let bounds = - bounds.iter().map( - |b| cx.lifetime(span, cx.ident_of(*b).name)).collect(); - cx.lifetime_def(span, cx.ident_of(*lt).name, bounds) - }).collect(); - let ty_params = self.bounds.iter().map(|t| { - match *t { - (ref name, ref bounds) => { - mk_ty_param(cx, - span, - *name, - bounds, - self_ty, - self_generics) + let lifetimes = self.lifetimes + .iter() + .map(|&(ref lt, ref bounds)| { + let bounds = bounds.iter() + .map(|b| cx.lifetime(span, cx.ident_of(*b).name)) + .collect(); + cx.lifetime_def(span, cx.ident_of(*lt).name, bounds) + }) + .collect(); + let ty_params = self.bounds + .iter() + .map(|t| { + match *t { + (ref name, ref bounds) => { + mk_ty_param(cx, span, *name, bounds, self_ty, self_generics) + } } - } - }).collect(); + }) + .collect(); mk_generics(lifetimes, ty_params) } } -pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) - -> (P, ast::ExplicitSelf) { +pub fn get_explicit_self(cx: &ExtCtxt, + span: Span, + self_ptr: &Option) + -> (P, ast::ExplicitSelf) { // this constructs a fresh `self` path let self_path = cx.expr_self(span); match *self_ptr { - None => { - (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))) - } + None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))), Some(ref ptr) => { - let self_ty = respan( - span, - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); - SelfKind::Region(lt, mutbl) - } - Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition") - }); + let self_ty = + respan(span, + match *ptr { + Borrowed(ref lt, mutbl) => { + let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); + SelfKind::Region(lt, mutbl) + } + Raw(_) => { + cx.span_bug(span, "attempted to use *self in deriving definition") + } + }); let self_expr = cx.expr_deref(span, self_path); (self_expr, self_ty) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index e09a64e73449b..aee86b246b985 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -10,7 +10,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. -use syntax::ast::{MetaItem, self}; +use syntax::ast::{self, MetaItem}; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; @@ -99,11 +99,11 @@ fn expand_derive(cx: &mut ExtCtxt, for titem in traits.iter().rev() { let tname = if titem.is_word() { - titem.name() } - else { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - }; + titem.name() + } else { + cx.span_err(titem.span, "malformed `derive` entry"); + continue; + }; if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) { feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index c6c4b6135c681..5c081b98962e3 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/* - * The compiler code necessary to support the env! extension. Eventually this - * should all get sucked into either the compiler syntax extension plugin - * interface. - */ +// The compiler code necessary to support the env! extension. Eventually this +// should all get sucked into either the compiler syntax extension plugin +// interface. +// use syntax::ast; use syntax::ext::base::*; @@ -24,66 +23,61 @@ use syntax::tokenstream; use std::env; -pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) - -> Box { +pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) + -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { None => return DummyResult::expr(sp), - Some(v) => v + Some(v) => v, }; let e = match env::var(&var[..]) { - Err(..) => { - cx.expr_path(cx.path_all(sp, - true, - cx.std_path(&["option", "Option", "None"]), - Vec::new(), - vec!(cx.ty_rptr(sp, - cx.ty_ident(sp, - cx.ident_of("str")), - Some(cx.lifetime(sp, - cx.ident_of( - "'static").name)), - ast::Mutability::Immutable)), - Vec::new())) - } - Ok(s) => { - cx.expr_call_global(sp, - cx.std_path(&["option", "Option", "Some"]), - vec!(cx.expr_str(sp, - token::intern_and_get_ident( - &s[..])))) - } + Err(..) => { + cx.expr_path(cx.path_all(sp, + true, + cx.std_path(&["option", "Option", "None"]), + Vec::new(), + vec![cx.ty_rptr(sp, + cx.ty_ident(sp, cx.ident_of("str")), + Some(cx.lifetime(sp, + cx.ident_of("'static") + .name)), + ast::Mutability::Immutable)], + Vec::new())) + } + Ok(s) => { + cx.expr_call_global(sp, + cx.std_path(&["option", "Option", "Some"]), + vec![cx.expr_str(sp, token::intern_and_get_ident(&s[..]))]) + } }; MacEager::expr(e) } -pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) - -> Box { +pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) + -> Box { let mut exprs = match get_exprs_from_tts(cx, sp, tts) { Some(ref exprs) if exprs.is_empty() => { cx.span_err(sp, "env! takes 1 or 2 arguments"); return DummyResult::expr(sp); } None => return DummyResult::expr(sp), - Some(exprs) => exprs.into_iter() + Some(exprs) => exprs.into_iter(), }; - let var = match expr_to_string(cx, - exprs.next().unwrap(), - "expected string literal") { + let var = match expr_to_string(cx, exprs.next().unwrap(), "expected string literal") { None => return DummyResult::expr(sp), - Some((v, _style)) => v + Some((v, _style)) => v, }; let msg = match exprs.next() { - None => { - token::intern_and_get_ident(&format!("environment variable `{}` \ - not defined", - var)) - } + None => token::intern_and_get_ident(&format!("environment variable `{}` not defined", var)), Some(second) => { match expr_to_string(cx, second, "expected string literal") { None => return DummyResult::expr(sp), - Some((s, _style)) => s + Some((s, _style)) => s, } } }; @@ -98,7 +92,7 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token cx.span_err(sp, &msg); cx.expr_usize(sp, 0) } - Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s)) + Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s)), }; MacEager::expr(e) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 1f6f57c70f72f..06b16095d1963 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -37,7 +37,7 @@ enum Position { Named(String), } -struct Context<'a, 'b:'a> { +struct Context<'a, 'b: 'a> { ecx: &'a mut ExtCtxt<'b>, /// The macro's call site. References to unstable formatting internals must /// use this span to pass the stability checker. @@ -120,7 +120,9 @@ struct Context<'a, 'b:'a> { /// ```ignore /// Some((fmtstr, parsed arguments, index map for named arguments)) /// ``` -fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) +fn parse_args(ecx: &mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) -> Option<(P, Vec>, HashMap)> { let mut args = Vec::>::new(); let mut names = HashMap::::new(); @@ -138,7 +140,9 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) ecx.span_err(sp, "expected token: `,`"); return None; } - if p.token == token::Eof { break } // accept trailing commas + if p.token == token::Eof { + break; + } // accept trailing commas if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) { named = true; let ident = match p.token { @@ -155,7 +159,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) _ => { ecx.span_err(p.span, &format!("expected ident for named argument, found `{}`", - p.this_token_to_string())); + p.this_token_to_string())); return None; } }; @@ -164,9 +168,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) panictry!(p.expect(&token::Eq)); let e = panictry!(p.parse_expr()); if let Some(prev) = names.get(name) { - ecx.struct_span_err(e.span, - &format!("duplicate argument named `{}`", - name)) + ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name)) .span_note(args[*prev].span, "previously here") .emit(); continue; @@ -235,7 +237,8 @@ impl<'a, 'b> Context<'a, 'b> { fn verify_count(&mut self, c: parse::Count) { match c { - parse::CountImplied | parse::CountIs(..) => {} + parse::CountImplied | + parse::CountIs(..) => {} parse::CountIsParam(i) => { self.verify_arg_type(Exact(i), Count); } @@ -260,7 +263,8 @@ impl<'a, 'b> Context<'a, 'b> { Exact(arg) => { if self.args.len() <= arg { let msg = format!("invalid reference to argument `{}` ({})", - arg, self.describe_num_args()); + arg, + self.describe_num_args()); self.ecx.span_err(self.fmtsp, &msg[..]); return; @@ -394,9 +398,7 @@ impl<'a, 'b> Context<'a, 'b> { let arg = self.ecx.expr_usize(sp, i); self.ecx.expr_call_global(sp, path, vec![arg]) } - None => { - self.ecx.expr_path(self.ecx.path_global(sp, path)) - } + None => self.ecx.expr_path(self.ecx.path_global(sp, path)), } }; match arg.position { @@ -436,11 +438,14 @@ impl<'a, 'b> Context<'a, 'b> { flags: 0, precision: parse::CountImplied, width: parse::CountImplied, - ty: arg.format.ty - } + ty: arg.format.ty, + }, }; - let fill = match arg.format.fill { Some(c) => c, None => ' ' }; + let fill = match arg.format.fill { + Some(c) => c, + None => ' ', + }; if *arg != simple_arg || fill != ' ' { self.all_pieces_simple = false; @@ -464,17 +469,33 @@ impl<'a, 'b> Context<'a, 'b> { let prec = self.trans_count(arg.format.precision); let width = self.trans_count(arg.format.width); let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec")); - let fmt = self.ecx.expr_struct(sp, path, vec!( - self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), - self.ecx.field_imm(sp, self.ecx.ident_of("align"), align), - self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags), - self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec), - self.ecx.field_imm(sp, self.ecx.ident_of("width"), width))); + let fmt = + self.ecx.expr_struct(sp, + path, + vec![self.ecx + .field_imm(sp, self.ecx.ident_of("fill"), fill), + self.ecx.field_imm(sp, + self.ecx.ident_of("align"), + align), + self.ecx.field_imm(sp, + self.ecx.ident_of("flags"), + flags), + self.ecx.field_imm(sp, + self.ecx.ident_of("precision"), + prec), + self.ecx.field_imm(sp, + self.ecx.ident_of("width"), + width)]); let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument")); - Some(self.ecx.expr_struct(sp, path, vec!( - self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), - self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt)))) + Some(self.ecx.expr_struct(sp, + path, + vec![self.ecx.field_imm(sp, + self.ecx.ident_of("position"), + pos), + self.ecx.field_imm(sp, + self.ecx.ident_of("format"), + fmt)])) } } } @@ -486,9 +507,9 @@ impl<'a, 'b> Context<'a, 'b> { -> P { let sp = piece_ty.span; let ty = ecx.ty_rptr(sp, - ecx.ty(sp, ast::TyKind::Vec(piece_ty)), - Some(ecx.lifetime(sp, keywords::StaticLifetime.name())), - ast::Mutability::Immutable); + ecx.ty(sp, ast::TyKind::Vec(piece_ty)), + Some(ecx.lifetime(sp, keywords::StaticLifetime.name())), + ast::Mutability::Immutable); let slice = ecx.expr_vec_slice(sp, pieces); // static instead of const to speed up codegen by not requiring this to be inlined let st = ast::ItemKind::Static(ty, ast::Mutability::Immutable, slice); @@ -516,15 +537,11 @@ impl<'a, 'b> Context<'a, 'b> { // First, build up the static array which will become our precompiled // format "string" let static_lifetime = self.ecx.lifetime(self.fmtsp, keywords::StaticLifetime.name()); - let piece_ty = self.ecx.ty_rptr( - self.fmtsp, - self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")), - Some(static_lifetime), - ast::Mutability::Immutable); - let pieces = Context::static_array(self.ecx, - "__STATIC_FMTSTR", - piece_ty, - self.str_pieces); + let piece_ty = self.ecx.ty_rptr(self.fmtsp, + self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")), + Some(static_lifetime), + ast::Mutability::Immutable); + let pieces = Context::static_array(self.ecx, "__STATIC_FMTSTR", piece_ty, self.str_pieces); // Before consuming the expressions, we have to remember spans for // count arguments as they are now generated separate from other @@ -542,7 +559,10 @@ impl<'a, 'b> Context<'a, 'b> { let name = self.ecx.ident_of(&format!("__arg{}", i)); pats.push(self.ecx.pat_ident(DUMMY_SP, name)); for ref arg_ty in self.arg_unique_types[i].iter() { - locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, + locals.push(Context::format_arg(self.ecx, + self.macsp, + e.span, + arg_ty, self.ecx.expr_ident(e.span, name))); } heads.push(self.ecx.expr_addr_of(e.span, e)); @@ -556,7 +576,10 @@ impl<'a, 'b> Context<'a, 'b> { Exact(i) => spans_pos[i], _ => panic!("should never happen"), }; - counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, + counts.push(Context::format_arg(self.ecx, + self.macsp, + span, + &Count, self.ecx.expr_ident(span, name))); } @@ -593,9 +616,9 @@ impl<'a, 'b> Context<'a, 'b> { // But the nested match expression is proved to perform not as well // as series of let's; the first approach does. let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, vec!(pat), args_array); + let arm = self.ecx.arm(self.fmtsp, vec![pat], args_array); let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads)); - let result = self.ecx.expr_match(self.fmtsp, head, vec!(arm)); + let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]); let args_slice = self.ecx.expr_addr_of(self.fmtsp, result); @@ -605,13 +628,9 @@ impl<'a, 'b> Context<'a, 'b> { } else { // Build up the static array which will store our precompiled // nonstandard placeholders, if there are any. - let piece_ty = self.ecx.ty_path(self.ecx.path_global( - self.macsp, - Context::rtpath(self.ecx, "Argument"))); - let fmt = Context::static_array(self.ecx, - "__STATIC_FMTARGS", - piece_ty, - self.pieces); + let piece_ty = self.ecx + .ty_path(self.ecx.path_global(self.macsp, Context::rtpath(self.ecx, "Argument"))); + let fmt = Context::static_array(self.ecx, "__STATIC_FMTARGS", piece_ty, self.pieces); ("new_v1_formatted", vec![pieces, args_slice, fmt]) }; @@ -620,13 +639,16 @@ impl<'a, 'b> Context<'a, 'b> { self.ecx.expr_call_global(self.macsp, path, fn_args) } - fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span, - ty: &ArgumentType, arg: P) + fn format_arg(ecx: &ExtCtxt, + macsp: Span, + sp: Span, + ty: &ArgumentType, + arg: P) -> P { let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { - "" => "Display", + "" => "Display", "?" => "Debug", "e" => "LowerExp", "E" => "UpperExp", @@ -636,16 +658,14 @@ impl<'a, 'b> Context<'a, 'b> { "x" => "LowerHex", "X" => "UpperHex", _ => { - ecx.span_err(sp, - &format!("unknown format trait `{}`", - *tyname)); + ecx.span_err(sp, &format!("unknown format trait `{}`", *tyname)); "Dummy" } } } Count => { let path = ecx.std_path(&["fmt", "ArgumentV1", "from_usize"]); - return ecx.expr_call_global(macsp, path, vec![arg]) + return ecx.expr_call_global(macsp, path, vec![arg]); } }; @@ -656,22 +676,23 @@ impl<'a, 'b> Context<'a, 'b> { } } -pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, +pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, + sp: Span, tts: &[tokenstream::TokenTree]) - -> Box { + -> Box { match parse_args(ecx, sp, tts) { Some((efmt, args, names)) => { - MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, - args, names)) + MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names)) } - None => DummyResult::expr(sp) + None => DummyResult::expr(sp), } } /// Take the various parts of `format_args!(efmt, args..., name=names...)` /// and construct the appropriate formatting expression. -pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, +pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, + sp: Span, efmt: P, args: Vec>, names: HashMap) @@ -704,11 +725,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, macsp: macsp, fmtsp: efmt.span, }; - let fmt = match expr_to_string(cx.ecx, - efmt, - "format argument must be a string literal.") { + let fmt = match expr_to_string(cx.ecx, efmt, "format argument must be a string literal.") { Some((fmt, _)) => fmt, - None => return DummyResult::raw_expr(sp) + None => return DummyResult::raw_expr(sp), }; let mut parser = parse::Parser::new(&fmt); @@ -717,12 +736,14 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, loop { match parser.next() { Some(mut piece) => { - if !parser.errors.is_empty() { break } + if !parser.errors.is_empty() { + break; + } cx.verify_piece(&piece); cx.resolve_name_inplace(&mut piece); pieces.push(piece); } - None => break + None => break, } } @@ -738,8 +759,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, } if !parser.errors.is_empty() { - cx.ecx.span_err(cx.fmtsp, &format!("invalid format string: {}", - parser.errors.remove(0))); + cx.ecx.span_err(cx.fmtsp, + &format!("invalid format string: {}", parser.errors.remove(0))); return DummyResult::raw_expr(sp); } if !cx.literal.is_empty() { diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 17b200bac58c5..3aa62339b477e 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -23,7 +23,8 @@ #![feature(staged_api)] extern crate fmt_macros; -#[macro_use] extern crate log; +#[macro_use] +extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; @@ -52,16 +53,13 @@ pub fn register_builtins(env: &mut SyntaxEnv) { NormalTT(Box::new(f), None, false) } - env.insert(intern("asm"), - builtin_normal_expander(asm::expand_asm)); - env.insert(intern("cfg"), - builtin_normal_expander(cfg::expand_cfg)); + env.insert(intern("asm"), builtin_normal_expander(asm::expand_asm)); + env.insert(intern("cfg"), builtin_normal_expander(cfg::expand_cfg)); env.insert(intern("concat"), builtin_normal_expander(concat::expand_syntax_ext)); env.insert(intern("concat_idents"), builtin_normal_expander(concat_idents::expand_syntax_ext)); - env.insert(intern("env"), - builtin_normal_expander(env::expand_env)); + env.insert(intern("env"), builtin_normal_expander(env::expand_env)); env.insert(intern("option_env"), builtin_normal_expander(env::expand_option_env)); env.insert(intern("format_args"), diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs index 9645c5bb42723..7242b9865a92c 100644 --- a/src/libsyntax_ext/log_syntax.rs +++ b/src/libsyntax_ext/log_syntax.rs @@ -17,7 +17,7 @@ use syntax_pos; pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, sp: syntax_pos::Span, tts: &[tokenstream::TokenTree]) - -> Box { + -> Box { if !cx.ecfg.enable_log_syntax() { feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, "log_syntax", diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs index ad396d38de9f5..794169ae3429c 100644 --- a/src/libsyntax_ext/trace_macros.rs +++ b/src/libsyntax_ext/trace_macros.rs @@ -18,7 +18,7 @@ use syntax::tokenstream::TokenTree; pub fn expand_trace_macros(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) - -> Box { + -> Box { if !cx.ecfg.enable_trace_macros() { feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, "trace_macros", From 4e4d8baf7b99028a03280b90135117581c15d874 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 12 Aug 2016 09:08:37 -0400 Subject: [PATCH 016/768] Add doc example for `std::ffi::CString::from_vec_unchecked`. --- src/libstd/ffi/c_str.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 77b90c0846bbe..18a7c7c845704 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -211,6 +211,17 @@ impl CString { /// This method is equivalent to `new` except that no runtime assertion /// is made that `v` contains no 0 bytes, and it requires an actual /// byte vector, not anything that can be converted to one with Into. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let raw = b"foo".to_vec(); + /// unsafe { + /// let c_string = CString::from_vec_unchecked(raw); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { v.push(0); From 758aff7883b846a9ea01ee6c810f77a4a08c8a48 Mon Sep 17 00:00:00 2001 From: JessRudder Date: Fri, 12 Aug 2016 10:39:40 -0400 Subject: [PATCH 017/768] Update note to include recommendation to use `.as_slice()` --- src/libstd/primitive_docs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 6a470a52aa66c..84618ba2593a8 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -387,7 +387,8 @@ mod prim_slice { } /// [`len()`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. +/// used to get a string slice under normal circumstances. Use `.as_slice()` +/// instead. mod prim_str { } #[doc(primitive = "tuple")] From e173ead68458da5c4cb241f3d105abc87c529071 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 11 Aug 2016 19:42:17 -0400 Subject: [PATCH 018/768] provide additional justification for array interface design Explain why Rust does not implement traits for large arrays. Explain why most methods are implemented on slices rather than arrays. --- src/libstd/primitive_docs.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index de891ea89189a..fc83876832213 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -269,13 +269,18 @@ mod prim_pointer { } /// - `Borrow`, `BorrowMut` /// - `Default` /// +/// This limitation to `N in 0..33` exists because Rust does not yet support +/// generics over the size of an array type. `[Foo; 3]` and `[Bar; 3]` are +/// instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are +/// entirely different types. As a stopgap, trait implementations are +/// statically generated for `N in 0..33`. +/// /// Arrays coerce to [slices (`[T]`)][slice], so their methods can be called on -/// arrays. +/// arrays. Slices are dynamic and do not coerce to arrays; consequently more +/// methods are defined on `slice` where they support both types. /// /// [slice]: primitive.slice.html /// -/// Rust does not currently support generics over the size of an array type. -/// /// # Examples /// /// ``` From db16909ae341f7e2de29e0e458d945fd0cdec8aa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 12 Aug 2016 21:15:42 -0500 Subject: [PATCH 019/768] exclude `#![no_builtins]` crates from LTO this prevents intrinsics like `memcpy` from being mis-optimized to infinite recursive calls when LTO is used. fixes #31544 closes #35540 --- src/librustc_trans/back/link.rs | 28 ++++++++++++++++++---------- src/librustc_trans/back/lto.rs | 11 ++++++++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index a9f3d2f8a1754..d17da74c87f39 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -42,7 +42,7 @@ use std::process::Command; use std::str; use flate; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{self, AttrMetaMethods}; use syntax_pos::Span; // RLIB LLVM-BYTECODE OBJECT LAYOUT @@ -938,8 +938,10 @@ fn add_upstream_rust_crates(cmd: &mut Linker, Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { + let is_a_no_builtins_crate = + attr::contains_name(&sess.cstore.crate_attrs(cnum), "no_builtins"); add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0) + &src.rlib.unwrap().0, is_a_no_builtins_crate) } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) @@ -963,12 +965,16 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // * For LTO, we remove upstream object files. // * For dylibs we remove metadata and bytecode from upstream rlibs // - // When performing LTO, all of the bytecode from the upstream libraries has - // already been included in our object file output. As a result we need to - // remove the object files in the upstream libraries so the linker doesn't - // try to include them twice (or whine about duplicate symbols). We must - // continue to include the rest of the rlib, however, as it may contain - // static native libraries which must be linked in. + // When performing LTO, almost(*) all of the bytecode from the upstream + // libraries has already been included in our object file output. As a + // result we need to remove the object files in the upstream libraries so + // the linker doesn't try to include them twice (or whine about duplicate + // symbols). We must continue to include the rest of the rlib, however, as + // it may contain static native libraries which must be linked in. + // + // (*) Crates marked with `#![no_builtins]` don't participate in LTO and + // their bytecode wasn't included. The object files in those libraries must + // still be passed to the linker. // // When making a dynamic library, linkers by default don't include any // object files in an archive if they're not necessary to resolve the link. @@ -988,7 +994,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, tmpdir: &Path, crate_type: config::CrateType, - cratepath: &Path) { + cratepath: &Path, + is_a_no_builtins_crate: bool) { if !sess.lto() && crate_type != config::CrateTypeDylib { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return @@ -1012,7 +1019,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } let canonical = f.replace("-", "_"); let canonical_name = name.replace("-", "_"); - if sess.lto() && canonical.starts_with(&canonical_name) && + if sess.lto() && !is_a_no_builtins_crate && + canonical.starts_with(&canonical_name) && canonical.ends_with(".o") { let num = &f[name.len()..f.len() - 2]; if num.len() > 0 && num[1..].parse::().is_ok() { diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 69e4a50804fad..016eb7c0cfb3c 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -17,6 +17,7 @@ use llvm::{ModuleRef, TargetMachineRef, True, False}; use rustc::util::common::time; use rustc::util::common::path2cstr; use back::write::{ModuleConfig, with_llvm_pmb}; +use syntax::attr; use libc; use flate; @@ -52,7 +53,15 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // For each of our upstream dependencies, find the corresponding rlib and // load the bitcode from the archive. Then merge it into the current LLVM // module that we've got. - link::each_linked_rlib(sess, &mut |_, path| { + link::each_linked_rlib(sess, &mut |cnum, path| { + let is_a_no_builtins_crate = + attr::contains_name(&sess.cstore.crate_attrs(cnum), "no_builtins"); + + // `#![no_builtins]` crates don't participate in LTO. + if is_a_no_builtins_crate { + return; + } + let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { child.ok().and_then(|c| c.name().map(|name| (name, c))) From 5940150841fab50c3a178b5ccc33ceff0b0b4545 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 13 Aug 2016 15:48:38 +0100 Subject: [PATCH 020/768] rustdoc: Fix links to static items in the search results --- src/librustdoc/html/static/main.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 68035e5abe4c2..0223475be4eb6 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -577,10 +577,6 @@ displayPath = item.path + '::'; href = rootPath + item.path.replace(/::/g, '/') + '/' + name + '/index.html'; - } else if (type === 'static' || type === 'reexport') { - displayPath = item.path + '::'; - href = rootPath + item.path.replace(/::/g, '/') + - '/index.html'; } else if (type === "primitive") { displayPath = ""; href = rootPath + item.path.replace(/::/g, '/') + From 616b101e3fe8f66a70dd45248da5a3ab0b942ae6 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 13 Aug 2016 15:54:14 +0100 Subject: [PATCH 021/768] rustdoc: Don't include the path for primitive methods in the search results Displaying `std::u32::max_value` is misleading so just display `u32::max_value`. --- src/librustdoc/html/static/main.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 0223475be4eb6..de7e4d2483b43 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -587,9 +587,14 @@ } else if (item.parent !== undefined) { var myparent = item.parent; var anchor = '#' + type + '.' + name; - displayPath = item.path + '::' + myparent.name + '::'; + var parentType = itemTypes[myparent.ty]; + if (parentType === "primitive") { + displayPath = myparent.name + '::'; + } else { + displayPath = item.path + '::' + myparent.name + '::'; + } href = rootPath + item.path.replace(/::/g, '/') + - '/' + itemTypes[myparent.ty] + + '/' + parentType + '.' + myparent.name + '.html' + anchor; } else { From 19a33371eb0dca0e53c7332e87e728e19e5206ac Mon Sep 17 00:00:00 2001 From: Terry Sun Date: Sat, 13 Aug 2016 21:57:13 -0400 Subject: [PATCH 022/768] Update E0207 label to report parameter type Fixes #35642. --- src/librustc_typeck/collect.rs | 3 +-- src/test/compile-fail/E0207.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 75bfad053a328..bc755821fba46 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2323,7 +2323,6 @@ fn report_unused_parameter(ccx: &CrateCtxt, "the {} parameter `{}` is not constrained by the \ impl trait, self type, or predicates", kind, name) - .span_label(span, &format!("unconstrained lifetime parameter")) + .span_label(span, &format!("unconstrained {} parameter", kind)) .emit(); - } diff --git a/src/test/compile-fail/E0207.rs b/src/test/compile-fail/E0207.rs index 43ff085a4fa8e..fbddb81d7c70b 100644 --- a/src/test/compile-fail/E0207.rs +++ b/src/test/compile-fail/E0207.rs @@ -11,7 +11,7 @@ struct Foo; impl Foo { //~ ERROR E0207 - //~| NOTE unconstrained lifetime parameter + //~| NOTE unconstrained type parameter fn get(&self) -> T { ::default() } From e586d2174bd732bcc4a430266f371fbb82b39398 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Sun, 14 Aug 2016 13:33:53 +0200 Subject: [PATCH 023/768] Improve `No stdlib` and related Documentation --- src/doc/book/lang-items.md | 8 ++++---- src/doc/book/no-stdlib.md | 33 +++++++++++++++++++++++++-------- src/libcore/lib.rs | 5 +++++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index 72a3c08225d03..de7dbab3f12ea 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -57,8 +57,8 @@ fn main(argc: isize, argv: *const *const u8) -> isize { 0 } -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +#[lang = "eh_personality"] extern fn rust_eh_personality() {} +#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { loop {} } # #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} # #[no_mangle] pub extern fn rust_eh_register_frames () {} # #[no_mangle] pub extern fn rust_eh_unregister_frames () {} @@ -73,8 +73,8 @@ Other features provided by lang items include: `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all marked with lang items; those specific four are `eq`, `ord`, `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, `fail` - and `fail_bounds_checks` lang items. +- stack unwinding and general failure; the `eh_personality`, + `eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items. - the traits in `std::marker` used to indicate types of various kinds; lang items `send`, `sync` and `copy`. - the marker types and variance indicators found in diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md index 6fd7cf66920d4..2604ca8d4cab7 100644 --- a/src/doc/book/no-stdlib.md +++ b/src/doc/book/no-stdlib.md @@ -55,7 +55,13 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { // provided by libstd. #[lang = "eh_personality"] #[no_mangle] -pub extern fn eh_personality() { +pub extern fn rust_eh_personality() { +} + +// This function may be needed based on the compilation target. +#[lang = "eh_unwind_resume"] +#[no_mangle] +pub extern fn rust_eh_unwind_resume() { } #[lang = "panic_fmt"] @@ -87,12 +93,18 @@ pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { 0 } -// These functions and traits are used by the compiler, but not +// These functions are used by the compiler, but not // for a bare-bones hello world. These are normally // provided by libstd. #[lang = "eh_personality"] #[no_mangle] -pub extern fn eh_personality() { +pub extern fn rust_eh_personality() { +} + +// This function may be needed based on the compilation target. +#[lang = "eh_unwind_resume"] +#[no_mangle] +pub extern fn rust_eh_unwind_resume() { } #[lang = "panic_fmt"] @@ -104,7 +116,7 @@ pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, } ``` -## More about the langauge items +## More about the language items The compiler currently makes a few assumptions about symbols which are available in the executable to call. Normally these functions are provided by @@ -112,15 +124,20 @@ the standard library, but without it you must define your own. These symbols are called "language items", and they each have an internal name, and then a signature that an implementation must conform to. -The first of these two functions, `eh_personality`, is used by the failure +The first of these functions, `rust_eh_personality`, is used by the failure mechanisms of the compiler. This is often mapped to GCC's personality function (see the [libstd implementation][unwind] for more information), but crates which do not trigger a panic can be assured that this function is never -called. Both the language item and the symbol name are `eh_personality`. - +called. The language item's name is `eh_personality`. + [unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs -The second function, `panic_fmt`, is also used by the failure mechanisms of the +The second function, `rust_begin_panic`, is also used by the failure mechanisms of the compiler. When a panic happens, this controls the message that's displayed on the screen. While the language item's name is `panic_fmt`, the symbol name is `rust_begin_panic`. + +A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume` +flag is set in the options of the compilation target. It allows customizing the +process of resuming unwind at the end of the landing pads. The language item's name +is `eh_unwind_resume`. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fabb3900ec648..4949e66de54c9 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -42,6 +42,11 @@ //! line. It is up to consumers of this core library to define this panic //! function; it is only required to never return. This requires a `lang` //! attribute named `panic_fmt`. +//! +//! * `rust_eh_personality` - is used by the failure mechanisms of the +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. // Since libcore defines many fundamental lang items, all tests live in a // separate crate, libcoretest, to avoid bizarre issues. From 5286a5a0f84c5fcc697cfb43728751751af1833d Mon Sep 17 00:00:00 2001 From: Yossi Konstantinovsky Date: Sun, 14 Aug 2016 21:57:33 +0300 Subject: [PATCH 024/768] Update E0322 to new format --- src/librustc_typeck/coherence/orphan.rs | 6 ++++-- src/test/compile-fail/coherence-impls-sized.rs | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 15d4026254fa5..e950af5c13389 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -331,8 +331,10 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // Disallow *all* explicit impls of `Sized` and `Unsize` for now. if Some(trait_def_id) == self.tcx.lang_items.sized_trait() { - span_err!(self.tcx.sess, item.span, E0322, - "explicit impls for the `Sized` trait are not permitted"); + struct_span_err!(self.tcx.sess, item.span, E0322, + "explicit impls for the `Sized` trait are not permitted") + .span_label(item.span, &format!("impl of 'Sized' not allowed")) + .emit(); return; } if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs index 167067cb5fc0a..79767e5157b14 100644 --- a/src/test/compile-fail/coherence-impls-sized.rs +++ b/src/test/compile-fail/coherence-impls-sized.rs @@ -22,12 +22,15 @@ struct NotSync; impl !Sync for NotSync {} impl Sized for TestE {} //~ ERROR E0322 +//~^ impl of 'Sized' not allowed impl Sized for MyType {} //~ ERROR E0322 +//~^ impl of 'Sized' not allowed impl Sized for (MyType, MyType) {} //~ ERROR E0117 impl Sized for &'static NotSync {} //~ ERROR E0322 +//~^ impl of 'Sized' not allowed impl Sized for [MyType] {} //~ ERROR E0117 From a026e2c727312fc47b111cc29e684adec7caf341 Mon Sep 17 00:00:00 2001 From: Alexandre Oliveira Date: Sun, 14 Aug 2016 16:30:50 -0300 Subject: [PATCH 025/768] Update error E0365 to new format --- src/librustc_resolve/resolve_imports.rs | 12 ++++++------ src/test/compile-fail/E0365.rs | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 6986f99926e1e..67588912014ae 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -582,12 +582,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { source); self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); } else { - let msg = format!("`{}` is private, and cannot be reexported", source); - let note_msg = - format!("consider declaring type or module `{}` with `pub`", source); - struct_span_err!(self.session, directive.span, E0365, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); + let mut err = struct_span_err!(self.session, directive.span, E0365, + "`{}` is private, and cannot be reexported", + source); + err.span_label(directive.span, &format!("reexport of private `{}`", source)); + err.note(&format!("consider declaring type or module `{}` with `pub`", source)); + err.emit(); } } diff --git a/src/test/compile-fail/E0365.rs b/src/test/compile-fail/E0365.rs index 7b0fbcc6203d7..ea5fd6ed4772f 100644 --- a/src/test/compile-fail/E0365.rs +++ b/src/test/compile-fail/E0365.rs @@ -12,6 +12,9 @@ mod foo { pub const X: u32 = 1; } -pub use foo as foo2; //~ ERROR E0365 +pub use foo as foo2; +//~^ ERROR `foo` is private, and cannot be reexported [E0365] +//~| NOTE reexport of private `foo` +//~| NOTE consider declaring type or module `foo` with `pub` fn main() {} From 6d998d664bb51f6f28f55dba3b68ff6434b3435a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 15 Aug 2016 00:12:42 +0300 Subject: [PATCH 026/768] Update E0392 to new error format --- src/librustc_typeck/check/wfcheck.rs | 6 ++++-- src/test/compile-fail/E0392.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e2080906ca242..628cb203ec7d1 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -653,8 +653,10 @@ fn error_380(ccx: &CrateCtxt, span: Span) { fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'tcx> { - struct_span_err!(ccx.tcx.sess, span, E0392, - "parameter `{}` is never used", param_name) + let mut err = struct_span_err!(ccx.tcx.sess, span, E0392, + "parameter `{}` is never used", param_name); + err.span_label(span, &format!("unused type parameter")); + err } fn error_194(tcx: TyCtxt, span: Span, name: ast::Name) { diff --git a/src/test/compile-fail/E0392.rs b/src/test/compile-fail/E0392.rs index 4c3efcf4e8d75..a21e500e519bb 100644 --- a/src/test/compile-fail/E0392.rs +++ b/src/test/compile-fail/E0392.rs @@ -9,6 +9,7 @@ // except according to those terms. enum Foo { Bar } //~ ERROR E0392 + //~| NOTE unused type parameter fn main() { } From a37e90a8c9945083f58e608ebe9414e5fdb53333 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Sun, 14 Aug 2016 19:48:55 -0400 Subject: [PATCH 027/768] Make E0033 tests fit in 100 cols --- src/test/compile-fail/E0033.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/E0033.rs b/src/test/compile-fail/E0033.rs index 8a1cd2ef4b71c..d320bcd4d0f55 100644 --- a/src/test/compile-fail/E0033.rs +++ b/src/test/compile-fail/E0033.rs @@ -13,10 +13,11 @@ trait SomeTrait { } fn main() { - let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425 - //~^ ERROR E0038 - //~| method `foo` has no receiver - //~| NOTE the trait `SomeTrait` cannot be made into an object + let trait_obj: &SomeTrait = SomeTrait; + //~^ ERROR E0425 + //~| ERROR E0038 + //~| method `foo` has no receiver + //~| NOTE the trait `SomeTrait` cannot be made into an object let &invalid = trait_obj; //~^ ERROR E0033 From 1fd791ad62a4bb901be465997d9efbf4090819f0 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Fri, 12 Aug 2016 18:10:34 -0400 Subject: [PATCH 028/768] Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}` --- src/libcore/cell.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 17ec325e257b0..0a1fe3dbd7730 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -337,6 +337,9 @@ impl From for Cell { } } +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U> CoerceUnsized> for Cell {} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](index.html) for more. @@ -757,6 +760,9 @@ impl From for RefCell { } } +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U> CoerceUnsized> for RefCell {} + struct BorrowRef<'b> { borrow: &'b Cell, } @@ -1086,3 +1092,13 @@ impl From for UnsafeCell { UnsafeCell::new(t) } } + +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U> CoerceUnsized> for UnsafeCell {} + +#[allow(unused)] +fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) { + let _: UnsafeCell<&Send> = a; + let _: Cell<&Send> = b; + let _: RefCell<&Send> = c; +} From 35eba85c3d63579bbe0929dc880caf2be906b767 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 14 Aug 2016 21:56:26 -0500 Subject: [PATCH 029/768] refactor: use CStore::is_no_builtins --- src/librustc/middle/cstore.rs | 2 ++ src/librustc_metadata/csearch.rs | 4 ++++ src/librustc_trans/back/link.rs | 6 ++---- src/librustc_trans/back/lto.rs | 6 +----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index f1bb3a37e3c27..05cd822c6d635 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -227,6 +227,7 @@ pub trait CrateStore<'tcx> { fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option; fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>; fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; + fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool; // resolve fn def_index_for_def_key(&self, @@ -428,6 +429,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)> { bug!("native_libraries") } fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec { bug!("reachable_ids") } + fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_no_builtins") } // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 7ee6e54a666d6..2cdbd1b86012d 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -409,6 +409,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_reachable_ids(&cdata) } + fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool { + attr::contains_name(&self.crate_attrs(cnum), "no_builtins") + } + fn def_index_for_def_key(&self, cnum: ast::CrateNum, def: DefKey) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index d17da74c87f39..e7ee952129466 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -42,7 +42,7 @@ use std::process::Command; use std::str; use flate; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax_pos::Span; // RLIB LLVM-BYTECODE OBJECT LAYOUT @@ -938,10 +938,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - let is_a_no_builtins_crate = - attr::contains_name(&sess.cstore.crate_attrs(cnum), "no_builtins"); add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, is_a_no_builtins_crate) + &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 016eb7c0cfb3c..522864c6ec3a4 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -17,7 +17,6 @@ use llvm::{ModuleRef, TargetMachineRef, True, False}; use rustc::util::common::time; use rustc::util::common::path2cstr; use back::write::{ModuleConfig, with_llvm_pmb}; -use syntax::attr; use libc; use flate; @@ -54,11 +53,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // load the bitcode from the archive. Then merge it into the current LLVM // module that we've got. link::each_linked_rlib(sess, &mut |cnum, path| { - let is_a_no_builtins_crate = - attr::contains_name(&sess.cstore.crate_attrs(cnum), "no_builtins"); - // `#![no_builtins]` crates don't participate in LTO. - if is_a_no_builtins_crate { + if sess.cstore.is_no_builtins(cnum) { return; } From fa61f82bf20bfdc6a890aee18d8130906a25d226 Mon Sep 17 00:00:00 2001 From: silenuss Date: Mon, 15 Aug 2016 00:21:13 -0600 Subject: [PATCH 030/768] Update compiler error 0030 to use new error format. --- src/librustc_passes/consts.rs | 8 ++++---- src/test/compile-fail/E0030.rs | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 37e42cdea1bf8..52c452c7af933 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -283,10 +283,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { Ok(Ordering::Less) | Ok(Ordering::Equal) => {} Ok(Ordering::Greater) => { - span_err!(self.tcx.sess, - start.span, - E0030, - "lower range bound must be less than or equal to upper"); + struct_span_err!(self.tcx.sess, start.span, E0030, + "lower range bound must be less than or equal to upper") + .span_label(start.span, &format!("lower bound larger than upper bound")) + .emit(); } Err(ErrorReported) => {} } diff --git a/src/test/compile-fail/E0030.rs b/src/test/compile-fail/E0030.rs index 7f26f6cdb84af..74e827b3379a7 100644 --- a/src/test/compile-fail/E0030.rs +++ b/src/test/compile-fail/E0030.rs @@ -11,6 +11,8 @@ fn main() { match 5u32 { - 1000 ... 5 => {} //~ ERROR E0030 + 1000 ... 5 => {} + //~^ ERROR lower range bound must be less than or equal to upper + //~| NOTE lower bound larger than upper bound } } From 9e3986188d9c8f2702476a330892f7874055c30f Mon Sep 17 00:00:00 2001 From: Phil Ruffwind Date: Mon, 11 Jul 2016 15:25:12 -0400 Subject: [PATCH 031/768] Fix spacing in code of closures.md The spacing seems inconsistent with existing style conventions. --- src/doc/book/closures.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index 1470eac98295e..d332cac7d8d16 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -262,7 +262,7 @@ the result: ```rust fn call_with_one(some_closure: F) -> i32 - where F : Fn(i32) -> i32 { + where F: Fn(i32) -> i32 { some_closure(1) } @@ -279,7 +279,7 @@ Let’s examine the signature of `call_with_one` in more depth: ```rust fn call_with_one(some_closure: F) -> i32 -# where F : Fn(i32) -> i32 { +# where F: Fn(i32) -> i32 { # some_closure(1) } ``` @@ -288,7 +288,7 @@ isn’t interesting. The next part is: ```rust # fn call_with_one(some_closure: F) -> i32 - where F : Fn(i32) -> i32 { + where F: Fn(i32) -> i32 { # some_closure(1) } ``` From 85bbbad5926ab93c4c41c47eb11faffb4c8aeb5f Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sun, 19 Jun 2016 16:27:37 -0400 Subject: [PATCH 032/768] A disclaimer about keywords. Some people cite this list as "zomg Rust has so many keywords," so make it clear that these aren't all used by the language today. --- src/doc/grammar.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/doc/grammar.md b/src/doc/grammar.md index fac488d9c4aa3..be64379b516e7 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -172,6 +172,11 @@ token : simple_token | ident | literal | symbol | whitespace token ; Each of these keywords has special meaning in its grammar, and all of them are excluded from the `ident` rule. +Not all of these keywords are used by the language. Some of them were used +before Rust 1.0, and were left reserved once their implementations were +removed. Some of them were reserved before 1.0 to make space for possible +future features. + ### Literals ```antlr From 349f10a15daee7b952889f6a88ea09be76711702 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Mon, 15 Aug 2016 20:37:03 +0300 Subject: [PATCH 033/768] update E0375 to new format --- src/librustc_typeck/coherence/mod.rs | 26 +++++++++++++++++++------- src/test/compile-fail/E0375.rs | 8 +++++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 13deac57330e3..f33fb299cacc1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -458,13 +458,25 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { being coerced, none found"); return; } else if diff_fields.len() > 1 { - span_err!(tcx.sess, span, E0375, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures with one field \ - being coerced, but {} fields need coercions: {}", - diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| { - format!("{} ({} to {})", fields[i].name, a, b) - }).collect::>().join(", ")); + let item = tcx.map.expect_item(impl_node_id); + let span = if let ItemImpl(_, _, _, Some(ref t), _, _) = item.node { + t.path.span + } else { + tcx.map.span(impl_node_id) + }; + + let mut err = struct_span_err!(tcx.sess, span, E0375, + "implementing the trait `CoerceUnsized` \ + requires multiple coercions"); + err.note("`CoerceUnsized` may only be implemented for \ + a coercion between structures with one field being coerced"); + err.note(&format!("currently, {} fields need coercions: {}", + diff_fields.len(), + diff_fields.iter().map(|&(i, a, b)| { + format!("{} ({} to {})", fields[i].name, a, b) + }).collect::>().join(", ") )); + err.span_label(span, &format!("requires multiple coercions")); + err.emit(); return; } diff --git a/src/test/compile-fail/E0375.rs b/src/test/compile-fail/E0375.rs index c6db7b8b64e66..29d8e920c4ce7 100644 --- a/src/test/compile-fail/E0375.rs +++ b/src/test/compile-fail/E0375.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + #![feature(coerce_unsized)] use std::ops::CoerceUnsized; @@ -17,6 +19,10 @@ struct Foo { c: U, } -impl CoerceUnsized> for Foo {} //~ ERROR E0375 +impl CoerceUnsized> for Foo {} +//~^ ERROR E0375 +//~| NOTE requires multiple coercions +//~| NOTE `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced +//~| NOTE currently, 2 fields need coercions: b (T to U), c (U to T) fn main() {} From 18edae42379da4ffd0df5a4e9c3d69f383451c91 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Mon, 15 Aug 2016 15:34:02 -0400 Subject: [PATCH 034/768] expound on limitations of Rust's trait-based operator overloading Part of #29330 --- src/libcore/ops.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..4ac1b8394f450 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -10,11 +10,16 @@ //! Overloadable operators. //! -//! Implementing these traits allows you to get an effect similar to -//! overloading operators. +//! Implementing these traits allows you to overload certain operators. //! //! Some of these traits are imported by the prelude, so they are available in -//! every Rust program. +//! every Rust program. Only operators backed by traits can be overloaded. For +//! example, the addition operator (`+`) can be overloaded through the `Add` +//! trait, but since the assignment operator (`=`) has no backing trait, there +//! is no way of overloading its semantics. Additionally, this module does not +//! provide any mechanism to create new operators. If traitless overloading or +//! custom operators are required, you should look toward macros or compiler +//! plugins to extend Rust's syntax. //! //! Many of the operators take their operands by value. In non-generic //! contexts involving built-in types, this is usually not a problem. From c9f20551103cfbe51bdd859f5eb3554f7bed72e8 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Mon, 15 Aug 2016 18:03:11 -0400 Subject: [PATCH 035/768] accumulate into vector and assert, instead of printing I'm only making this change in one place so that people can express their preferences for this stylistic change. If/when this change is approved I'll go ahead and translate the rest of the `std::ops` examples. --- src/libcore/iter/range.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index c234ef21db6d1..c4b0794d1e898 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,20 +295,8 @@ impl ops::Range { /// /// ``` /// #![feature(step_by)] - /// - /// for i in (0..10).step_by(2) { - /// println!("{}", i); - /// } - /// ``` - /// - /// This prints: - /// - /// ```text - /// 0 - /// 2 - /// 4 - /// 6 - /// 8 + /// let result: Vec<_> = (0..10).step_by(2).take(10).collect(); + /// assert_eq!(result, vec![0, 2, 4, 6, 8]); /// ``` #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] @@ -650,4 +638,3 @@ impl DoubleEndedIterator for ops::RangeInclusive where n } } - From 2c9a1d9c4aca14ddca4a9b6bd4631b04ade43497 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Mon, 15 Aug 2016 18:30:25 -0400 Subject: [PATCH 036/768] remove `.take(10)` from `Range` example --- src/libcore/iter/range.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index c4b0794d1e898..079dfe2a81f80 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,7 +295,7 @@ impl ops::Range { /// /// ``` /// #![feature(step_by)] - /// let result: Vec<_> = (0..10).step_by(2).take(10).collect(); + /// let result: Vec<_> = (0..10).step_by(2).collect(); /// assert_eq!(result, vec![0, 2, 4, 6, 8]); /// ``` #[unstable(feature = "step_by", reason = "recent addition", From 377ae44cf276599a5b7a21e545d83372067db754 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Mon, 15 Aug 2016 18:46:19 -0400 Subject: [PATCH 037/768] explicitly show how iterating over `..` fails I've also removed the `main()` wrapper, which I believe is extraneous. LMK if that's incorrect. --- src/libcore/ops.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..558b78a2fbfaa 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1463,15 +1463,17 @@ pub trait IndexMut: Index { /// # Examples /// /// ``` -/// fn main() { -/// assert_eq!((..), std::ops::RangeFull); +/// assert_eq!((..), std::ops::RangeFull); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); -/// } +/// // for i in .. { +/// // println!("This errors because .. has no Iterator impl"); +/// // } +/// +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] From e9964056964706fa3746c7e1135c34a45f2f467f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 14 Aug 2016 21:56:48 -0500 Subject: [PATCH 038/768] test that a no_builtins crate is passed to the linker --- src/test/run-make/no-builtins-lto/Makefile | 9 +++++++++ src/test/run-make/no-builtins-lto/main.rs | 13 +++++++++++++ src/test/run-make/no-builtins-lto/no_builtins.rs | 12 ++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/test/run-make/no-builtins-lto/Makefile create mode 100644 src/test/run-make/no-builtins-lto/main.rs create mode 100644 src/test/run-make/no-builtins-lto/no_builtins.rs diff --git a/src/test/run-make/no-builtins-lto/Makefile b/src/test/run-make/no-builtins-lto/Makefile new file mode 100644 index 0000000000000..3f70de5f76c3b --- /dev/null +++ b/src/test/run-make/no-builtins-lto/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +all: + # Compile a `#![no_builtins]` rlib crate + $(RUSTC) no_builtins.rs + # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't + # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by + # grepping the linker arguments. + $(RUSTC) main.rs -C lto -Z print-link-args | grep 'libno_builtins.rlib' diff --git a/src/test/run-make/no-builtins-lto/main.rs b/src/test/run-make/no-builtins-lto/main.rs new file mode 100644 index 0000000000000..e960c726a98cc --- /dev/null +++ b/src/test/run-make/no-builtins-lto/main.rs @@ -0,0 +1,13 @@ +// 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. + +extern crate no_builtins; + +fn main() {} diff --git a/src/test/run-make/no-builtins-lto/no_builtins.rs b/src/test/run-make/no-builtins-lto/no_builtins.rs new file mode 100644 index 0000000000000..be95e7c5521ee --- /dev/null +++ b/src/test/run-make/no-builtins-lto/no_builtins.rs @@ -0,0 +1,12 @@ +// 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. + +#![crate_type = "lib"] +#![no_builtins] From bc52bdcedcb34e303d2a3a450b541dfbf002281e Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 15 Aug 2016 23:45:12 -0400 Subject: [PATCH 039/768] Implement `Debug` for `std::vec::IntoIter`. Display all the remaining items of the iterator, similar to the `Debug` implementation for `core::slice::Iter`: https://github.com/rust-lang/rust/blob/f0bab98695f0a4877daabad9a5b0ba3e66121392/src/libcore/slice.rs#L930-L937 Using the `as_slice` method that was added in: https://github.com/rust-lang/rust/pull/35447 --- src/libcollections/vec.rs | 9 +++++++++ src/libcollectionstest/vec.rs | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a6f817a89624c..7008411d0f812 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1713,6 +1713,15 @@ pub struct IntoIter { end: *const T, } +#[stable(feature = "vec_intoiter_debug", since = "")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IntoIter") + .field(&self.as_slice()) + .finish() + } +} + impl IntoIter { /// Returns the remaining items of this iterator as a slice. /// diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 9556174bd2294..86f4bbd3c4d38 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -501,6 +501,14 @@ fn test_into_iter_as_mut_slice() { assert_eq!(into_iter.as_slice(), &['y', 'c']); } +#[test] +fn test_into_iter_debug() { + let vec = vec!['a', 'b', 'c']; + let into_iter = vec.into_iter(); + let debug = format!("{:?}", into_iter); + assert_eq!(debug, "IntoIter(['a', 'b', 'c'])"); +} + #[test] fn test_into_iter_count() { assert_eq!(vec![1, 2, 3].into_iter().count(), 3); From d52eb1ab0ce5a8a1c5e86b7d606c4eac5d4447ea Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 16 Aug 2016 16:52:30 +0900 Subject: [PATCH 040/768] RUST_NEW_ERROR_FORMAT is no more --- src/test/ui/codemap_tests/empty_span.rs | 1 - src/test/ui/codemap_tests/empty_span.stderr | 4 ++-- .../ui/codemap_tests/huge_multispan_highlight.rs | 7 ++----- .../ui/codemap_tests/huge_multispan_highlight.stderr | 2 +- src/test/ui/codemap_tests/issue-11715.rs | 5 +---- src/test/ui/codemap_tests/one_line.rs | 2 -- src/test/ui/codemap_tests/one_line.stderr | 4 ++-- src/test/ui/codemap_tests/overlapping_spans.rs | 1 - src/test/ui/codemap_tests/overlapping_spans.stderr | 4 ++-- src/test/ui/codemap_tests/tab.rs | 3 +-- src/test/ui/codemap_tests/two_files.rs | 1 - src/test/ui/codemap_tests/two_files.stderr | 4 ++-- src/test/ui/codemap_tests/two_files_data.rs | 3 +-- src/test/ui/codemap_tests/unicode.rs | 1 - src/test/ui/codemap_tests/unicode.stderr | 4 ++-- src/test/ui/mismatched_types/issue-26480.rs | 1 - src/test/ui/mismatched_types/issue-26480.stderr | 12 ++++++------ src/test/ui/mismatched_types/main.rs | 2 -- src/test/ui/mismatched_types/main.stderr | 4 ++-- 19 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/test/ui/codemap_tests/empty_span.rs b/src/test/ui/codemap_tests/empty_span.rs index c78a586763429..2cf3b66dd77c8 100644 --- a/src/test/ui/codemap_tests/empty_span.rs +++ b/src/test/ui/codemap_tests/empty_span.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT #![feature(optin_builtin_traits)] fn main() { struct Foo; diff --git a/src/test/ui/codemap_tests/empty_span.stderr b/src/test/ui/codemap_tests/empty_span.stderr index f3e04ef02409b..b33dee6b4a472 100644 --- a/src/test/ui/codemap_tests/empty_span.stderr +++ b/src/test/ui/codemap_tests/empty_span.stderr @@ -1,7 +1,7 @@ error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static main::Foo` - --> $DIR/empty_span.rs:18:5 + --> $DIR/empty_span.rs:17:5 | -18 | unsafe impl Send for &'static Foo { } +17 | unsafe impl Send for &'static Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.rs b/src/test/ui/codemap_tests/huge_multispan_highlight.rs index b06832c7628ed..5a058d483915a 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.rs +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT - fn main() { let x = "foo"; @@ -96,9 +94,8 @@ fn main() { - - let y = &mut x; -} + let y = &mut x; +} diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr index 6a898a434778e..edbfd72df615f 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr @@ -1,7 +1,7 @@ error: cannot borrow immutable local variable `x` as mutable --> $DIR/huge_multispan_highlight.rs:100:18 | -14 | let x = "foo"; +12 | let x = "foo"; | - use `mut x` here to make mutable ... 100 | let y = &mut x; diff --git a/src/test/ui/codemap_tests/issue-11715.rs b/src/test/ui/codemap_tests/issue-11715.rs index 7ea497a25c832..ba1ce6abcd3d4 100644 --- a/src/test/ui/codemap_tests/issue-11715.rs +++ b/src/test/ui/codemap_tests/issue-11715.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT + @@ -99,6 +99,3 @@ fn main() { let y = &mut x; let z = &mut x; } - - - diff --git a/src/test/ui/codemap_tests/one_line.rs b/src/test/ui/codemap_tests/one_line.rs index 2a5ee6f8711ef..e50091d560622 100644 --- a/src/test/ui/codemap_tests/one_line.rs +++ b/src/test/ui/codemap_tests/one_line.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT - fn main() { let mut v = vec![Some("foo"), Some("bar")]; v.push(v.pop().unwrap()); diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr index 8f80489ea1aeb..a73575a8d57f1 100644 --- a/src/test/ui/codemap_tests/one_line.stderr +++ b/src/test/ui/codemap_tests/one_line.stderr @@ -1,7 +1,7 @@ error[E0499]: cannot borrow `v` as mutable more than once at a time - --> $DIR/one_line.rs:15:12 + --> $DIR/one_line.rs:13:12 | -15 | v.push(v.pop().unwrap()); +13 | v.push(v.pop().unwrap()); | - ^ - first borrow ends here | | | | | second mutable borrow occurs here diff --git a/src/test/ui/codemap_tests/overlapping_spans.rs b/src/test/ui/codemap_tests/overlapping_spans.rs index 5a90852392c08..7c1f0db16dd09 100644 --- a/src/test/ui/codemap_tests/overlapping_spans.rs +++ b/src/test/ui/codemap_tests/overlapping_spans.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT #[derive(Debug)] struct Foo { } diff --git a/src/test/ui/codemap_tests/overlapping_spans.stderr b/src/test/ui/codemap_tests/overlapping_spans.stderr index cbcf154eaba50..d32b18d670308 100644 --- a/src/test/ui/codemap_tests/overlapping_spans.stderr +++ b/src/test/ui/codemap_tests/overlapping_spans.stderr @@ -1,7 +1,7 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/overlapping_spans.rs:22:9 + --> $DIR/overlapping_spans.rs:21:9 | -22 | S {f:_s} => {} +21 | S {f:_s} => {} | ^^^^^--^ | | | | | hint: to prevent move, use `ref _s` or `ref mut _s` diff --git a/src/test/ui/codemap_tests/tab.rs b/src/test/ui/codemap_tests/tab.rs index aaaee8c5577fe..0672b5508b607 100644 --- a/src/test/ui/codemap_tests/tab.rs +++ b/src/test/ui/codemap_tests/tab.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT // ignore-tidy-tab + fn main() { bar; } - diff --git a/src/test/ui/codemap_tests/two_files.rs b/src/test/ui/codemap_tests/two_files.rs index 53e240e8c4738..fe5eba93b2331 100644 --- a/src/test/ui/codemap_tests/two_files.rs +++ b/src/test/ui/codemap_tests/two_files.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT include!("two_files_data.rs"); struct Baz { } diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index 6956017434616..d58e7148f6104 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -1,7 +1,7 @@ error[E0404]: `Bar` is not a trait - --> $DIR/two_files.rs:16:6 + --> $DIR/two_files.rs:15:6 | -16 | impl Bar for Baz { } +15 | impl Bar for Baz { } | ^^^ not a trait | = note: type aliases cannot be used for traits diff --git a/src/test/ui/codemap_tests/two_files_data.rs b/src/test/ui/codemap_tests/two_files_data.rs index 412c40f8e811b..a3dcea0546d38 100644 --- a/src/test/ui/codemap_tests/two_files_data.rs +++ b/src/test/ui/codemap_tests/two_files_data.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT // ignore-test + trait Foo { } type Bar = Foo; - diff --git a/src/test/ui/codemap_tests/unicode.rs b/src/test/ui/codemap_tests/unicode.rs index 19660133d6222..b206722d4f368 100644 --- a/src/test/ui/codemap_tests/unicode.rs +++ b/src/test/ui/codemap_tests/unicode.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT extern "路濫狼á́́" fn foo() {} fn main() { } diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 178bee7b7f3ab..aa42ae341c545 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,7 +1,7 @@ error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` - --> $DIR/unicode.rs:12:8 + --> $DIR/unicode.rs:11:8 | -12 | extern "路濫狼á́́" fn foo() {} +11 | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-26480.rs b/src/test/ui/mismatched_types/issue-26480.rs index 96db31f4b116f..f842627e76fee 100644 --- a/src/test/ui/mismatched_types/issue-26480.rs +++ b/src/test/ui/mismatched_types/issue-26480.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; } diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 45638a65915c4..13f23a5d01ac1 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -1,16 +1,16 @@ error[E0308]: mismatched types - --> $DIR/issue-26480.rs:27:19 + --> $DIR/issue-26480.rs:26:19 | -27 | $arr.len() * size_of($arr[0])); +26 | $arr.len() * size_of($arr[0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize -$DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) +$DIR/issue-26480.rs:37:5: 37:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) error: non-scalar cast: `{integer}` as `()` - --> $DIR/issue-26480.rs:33:19 + --> $DIR/issue-26480.rs:32:19 | -33 | ($x:expr) => ($x as ()) +32 | ($x:expr) => ($x as ()) | ^^^^^^^^ -$DIR/issue-26480.rs:39:5: 39:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs) +$DIR/issue-26480.rs:38:5: 38:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs) error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/main.rs b/src/test/ui/mismatched_types/main.rs index 85d9fa53fcf00..f7f1c78c3ba0d 100644 --- a/src/test/ui/mismatched_types/main.rs +++ b/src/test/ui/mismatched_types/main.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustc-env:RUST_NEW_ERROR_FORMAT - fn main() { let x: u32 = ( ); diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 2903aa08c0a91..9e26be6fdddeb 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types - --> $DIR/main.rs:14:18 + --> $DIR/main.rs:12:18 | -14 | let x: u32 = ( +12 | let x: u32 = ( | ^ expected u32, found () | = note: expected type `u32` From c186da706dda6ddaa4df20691702249c4ef0d2dc Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Tue, 16 Aug 2016 06:54:45 -0400 Subject: [PATCH 041/768] RangeFull for-loop iteration fails because of IntoIterator Saying that "[for-loop iteration] fails because .. has no IntoIterator impl" is more direct than saying "...no Iterator impl" because for loops sugar into IntoIterator invocations. It just happens that the other Range* operators implement Iterator and rely on the fact that `IntoIterator` is implemented for `T: Iterator`. --- src/libcore/ops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 558b78a2fbfaa..cee374ccc7bc5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1466,7 +1466,7 @@ pub trait IndexMut: Index { /// assert_eq!((..), std::ops::RangeFull); /// /// // for i in .. { -/// // println!("This errors because .. has no Iterator impl"); +/// // println!("This errors because .. has no IntoIterator impl"); /// // } /// /// let arr = [0, 1, 2, 3]; From 3aa63400a27cbfefa3984aad5b52580e53b8f02d Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 16 Aug 2016 20:14:41 +0900 Subject: [PATCH 042/768] Use UI test to test spans, instead of forced line break --- .../move-closure-span.rs => ui/span/move-closure.rs} | 5 ++--- src/test/ui/span/move-closure.stderr | 11 +++++++++++ .../ty_binding_span.rs => ui/span/type-binding.rs} | 8 +++----- src/test/ui/span/type-binding.stderr | 8 ++++++++ 4 files changed, 24 insertions(+), 8 deletions(-) rename src/test/{compile-fail/move-closure-span.rs => ui/span/move-closure.rs} (89%) create mode 100644 src/test/ui/span/move-closure.stderr rename src/test/{compile-fail/ty_binding_span.rs => ui/span/type-binding.rs} (85%) create mode 100644 src/test/ui/span/type-binding.stderr diff --git a/src/test/compile-fail/move-closure-span.rs b/src/test/ui/span/move-closure.rs similarity index 89% rename from src/test/compile-fail/move-closure-span.rs rename to src/test/ui/span/move-closure.rs index 3c590e892cc42..e11ef0dddaa94 100644 --- a/src/test/compile-fail/move-closure-span.rs +++ b/src/test/ui/span/move-closure.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Regression test for issue #24986 // Make sure that the span of a closure marked `move` begins at the `move` keyword. fn main() { - let x: () = - move //~ ERROR mismatched types - || (); + let x: () = move || (); } diff --git a/src/test/ui/span/move-closure.stderr b/src/test/ui/span/move-closure.stderr new file mode 100644 index 0000000000000..251feded167d8 --- /dev/null +++ b/src/test/ui/span/move-closure.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/move-closure.rs:15:17 + | +15 | let x: () = move || (); + | ^^^^^^^^^^ expected (), found closure + | + = note: expected type `()` + = note: found type `[closure@$DIR/move-closure.rs:15:17: 15:27]` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/ty_binding_span.rs b/src/test/ui/span/type-binding.rs similarity index 85% rename from src/test/compile-fail/ty_binding_span.rs rename to src/test/ui/span/type-binding.rs index dd56ce5b3dd7f..05285c732f414 100644 --- a/src/test/compile-fail/ty_binding_span.rs +++ b/src/test/ui/span/type-binding.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Regression test for issue #28158 // Test the type binding span doesn't include >> use std::ops::Deref; -fn homura>(_: T) { } +fn homura>(_: T) {} - -fn main() { -} +fn main() {} diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr new file mode 100644 index 0000000000000..3cd1791a34ff7 --- /dev/null +++ b/src/test/ui/span/type-binding.stderr @@ -0,0 +1,8 @@ +error[E0220]: associated type `Trget` not found for `std::ops::Deref` + --> $DIR/type-binding.rs:16:20 + | +16 | fn homura>(_: T) {} + | ^^^^^^^^^^^ + +error: aborting due to previous error + From 3808dc3560ed15c83f92a0c309d44864f53e968b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 9 Aug 2016 20:49:41 -0400 Subject: [PATCH 043/768] Implement `AsRef<[T]>` for `std::slice::Iter`. `AsRef` is designed for conversions that are "cheap" (as per the API docs). It is the case that retrieving the underlying data of `std::slice::Iter` is cheap. In my opinion, there's no ambiguity about what slice data will be returned, otherwise, I would be more cautious about implementing `AsRef`. --- src/libcollectionstest/slice.rs | 9 +++++++++ src/libcore/slice.rs | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 71416f2069fa0..cb3579f0680f8 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -645,6 +645,15 @@ fn test_iter_size_hints() { assert_eq!(xs.iter_mut().size_hint(), (5, Some(5))); } +#[test] +fn test_iter_as_ref() { + let xs = [1, 2, 5, 10, 11]; + let mut iter = xs.iter(); + assert_eq!(iter.as_ref(), &[1, 2, 5, 10, 11]); + iter.next(); + assert_eq!(iter.as_ref(), &[2, 5, 10, 11]); +} + #[test] fn test_iter_clone() { let xs = [1, 2, 5]; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 3141c289e931c..3a820a14f1214 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -37,6 +37,7 @@ use clone::Clone; use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord}; use cmp::Ordering::{Less, Equal, Greater}; use cmp; +use convert::AsRef; use default::Default; use fmt; use intrinsics::assume; @@ -996,6 +997,13 @@ impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } } } +#[stable(feature = "slice_iter_as_ref", since = "1.12.0")] +impl<'a, T> AsRef<[T]> for Iter<'a, T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + /// Mutable slice iterator. /// /// This struct is created by the [`iter_mut`] method on [slices]. From dc22186efb7d6ea5fff2fc1f6d39684ce9633bf7 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 9 Aug 2016 20:51:47 -0400 Subject: [PATCH 044/768] Add basic unit test for `std::slice::Iter::as_slice`. --- src/libcollectionstest/slice.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index cb3579f0680f8..5b341ab62d097 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -645,6 +645,15 @@ fn test_iter_size_hints() { assert_eq!(xs.iter_mut().size_hint(), (5, Some(5))); } +#[test] +fn test_iter_as_slice() { + let xs = [1, 2, 5, 10, 11]; + let mut iter = xs.iter(); + assert_eq!(iter.as_slice(), &[1, 2, 5, 10, 11]); + iter.next(); + assert_eq!(iter.as_slice(), &[2, 5, 10, 11]); +} + #[test] fn test_iter_as_ref() { let xs = [1, 2, 5, 10, 11]; From 16fc02569db706df5749809155ba5612da7744da Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 16 Aug 2016 11:29:50 -0700 Subject: [PATCH 045/768] Bump version to 1.13 --- mk/main.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index c6c3e70abc37a..1725143325c61 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,7 +13,7 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.12.0 +CFG_RELEASE_NUM=1.13.0 # An optional number to put after the label, e.g. '.2' -> '-beta.2' # NB Make sure it starts with a dot to conform to semver pre-release From d2e78956c39c1b1e94169f2a1f7cde34aef4ff96 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 17 Aug 2016 00:57:44 +0800 Subject: [PATCH 046/768] Updated E0422 to new error message --- src/librustc_resolve/lib.rs | 6 ++++-- src/test/compile-fail/E0422.rs | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 962509be324de..a8b1cb123b843 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -317,11 +317,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::DoesNotNameAStruct(name) => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0422, "`{}` does not name a structure", - name) + name); + err.span_label(span, &format!("not a structure")); + err } ResolutionError::StructVariantUsedAsFunction(path_name) => { struct_span_err!(resolver.session, diff --git a/src/test/compile-fail/E0422.rs b/src/test/compile-fail/E0422.rs index d1cb7fd9640da..61e96b896a66a 100644 --- a/src/test/compile-fail/E0422.rs +++ b/src/test/compile-fail/E0422.rs @@ -9,5 +9,7 @@ // except according to those terms. fn main () { - let x = Foo { x: 1, y: 2 }; //~ ERROR E0422 + let x = Foo { x: 1, y: 2 }; + //~^ ERROR E0422 + //~| NOTE not a structure } From 3caa451b9db58836301dd93ffabc0fb493dd4fe7 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 17 Aug 2016 01:40:57 +0800 Subject: [PATCH 047/768] Updated E0394 to new error message --- src/librustc_mir/transform/qualify_consts.rs | 5 ++++- src/test/compile-fail/E0394.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 103a15dadb61c..1de67922b1b3a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -277,7 +277,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } else { "cannot refer to statics by value, use a constant instead" }; - span_err!(self.tcx.sess, self.span, E0394, "{}", msg); + struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg) + .span_label(self.span, &format!("referring to another static by value")) + .note(&format!("use the address-of operator or a constant instead")) + .emit(); // Replace STATIC with NOT_CONST to avoid further errors. self.qualif = self.qualif - Qualif::STATIC; diff --git a/src/test/compile-fail/E0394.rs b/src/test/compile-fail/E0394.rs index 1b86b8ad67496..e35d038248c81 100644 --- a/src/test/compile-fail/E0394.rs +++ b/src/test/compile-fail/E0394.rs @@ -9,7 +9,10 @@ // except according to those terms. static A: u32 = 0; -static B: u32 = A; //~ ERROR E0394 +static B: u32 = A; +//~^ ERROR E0394 +//~| NOTE referring to another static by value +//~| NOTE use the address-of operator or a constant instead fn main() { } From 193b9ae86b7ba498430866fb6090617194ba5ed7 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Tue, 16 Aug 2016 22:13:09 +0300 Subject: [PATCH 048/768] update to new error format E0409 --- src/librustc_resolve/lib.rs | 19 +++++++++++++------ src/test/compile-fail/E0409.rs | 7 ++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 962509be324de..a736067be6b7d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -117,7 +117,7 @@ enum ResolutionError<'a> { /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{} VariableNotBoundInPattern(Name, usize, usize), /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 - VariableBoundWithDifferentMode(Name, usize), + VariableBoundWithDifferentMode(Name, usize, Span), /// error E0411: use of `Self` outside of an impl or trait SelfUsedOutsideImplOrTrait, /// error E0412: use of undeclared @@ -270,14 +270,19 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, from, to) } - ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number) => { - struct_span_err!(resolver.session, + ResolutionError::VariableBoundWithDifferentMode(variable_name, + pattern_number, + first_binding_span) => { + let mut err = struct_span_err!(resolver.session, span, E0409, "variable `{}` is bound with different mode in pattern #{} than in \ pattern #1", variable_name, - pattern_number) + pattern_number); + err.span_label(span, &format!("bound in different ways")); + err.span_label(first_binding_span, &format!("first binding")); + err } ResolutionError::SelfUsedOutsideImplOrTrait => { let mut err = struct_span_err!(resolver.session, @@ -2044,8 +2049,10 @@ impl<'a> Resolver<'a> { if binding_0.binding_mode != binding_i.binding_mode { resolve_error(self, binding_i.span, - ResolutionError::VariableBoundWithDifferentMode(key.name, - i + 1)); + ResolutionError::VariableBoundWithDifferentMode( + key.name, + i + 1, + binding_0.span)); } } } diff --git a/src/test/compile-fail/E0409.rs b/src/test/compile-fail/E0409.rs index 366ad15207250..e89cc9ea5cbf2 100644 --- a/src/test/compile-fail/E0409.rs +++ b/src/test/compile-fail/E0409.rs @@ -13,7 +13,12 @@ fn main() { match x { (0, ref y) | (y, 0) => {} //~ ERROR E0409 - //~^ ERROR E0308 + //~^ NOTE bound in different ways + //~| NOTE first binding + //~| ERROR E0308 + //~| NOTE expected &{integer}, found integral variable + //~| NOTE expected type `&{integer}` + //~| NOTE found type `{integer}` _ => () } } From 98c8e0a05dd7b1ecbbda28c1d01e05c1e41b1638 Mon Sep 17 00:00:00 2001 From: cgswords Date: Thu, 4 Aug 2016 12:20:01 -0700 Subject: [PATCH 049/768] Proc_macro is alive --- mk/crates.mk | 8 +- src/libproc_macro/Cargo.toml | 15 + src/libproc_macro/build.rs | 89 ++++ src/libproc_macro/lib.rs | 137 +++++ src/libproc_macro/parse.rs | 26 + src/libproc_macro/prelude.rs | 12 + src/libproc_macro/qquote.rs | 470 ++++++++++++++++++ src/librustc_driver/Cargo.toml | 3 +- src/libsyntax/ext/proc_macro_shim.rs | 69 +++ src/libsyntax/lib.rs | 1 + src/libsyntax/tokenstream.rs | 6 + src/rustc/Cargo.lock | 11 + .../auxiliary/cond_noprelude_plugin.rs | 65 +++ .../auxiliary/cond_plugin.rs | 66 +++ .../auxiliary/cond_prelude_plugin.rs | 60 +++ src/test/run-pass-fulldeps/macro-quote-1.rs | 28 ++ .../run-pass-fulldeps/macro-quote-cond.rs | 54 ++ .../macro-quote-noprelude.rs | 54 ++ .../run-pass-fulldeps/macro-quote-prelude.rs | 54 ++ src/tools/tidy/src/cargo.rs | 6 + 20 files changed, 1230 insertions(+), 4 deletions(-) create mode 100644 src/libproc_macro/Cargo.toml create mode 100644 src/libproc_macro/build.rs create mode 100644 src/libproc_macro/lib.rs create mode 100644 src/libproc_macro/parse.rs create mode 100644 src/libproc_macro/prelude.rs create mode 100644 src/libproc_macro/qquote.rs create mode 100644 src/libsyntax/ext/proc_macro_shim.rs create mode 100644 src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs create mode 100644 src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs create mode 100644 src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs create mode 100644 src/test/run-pass-fulldeps/macro-quote-1.rs create mode 100644 src/test/run-pass-fulldeps/macro-quote-cond.rs create mode 100644 src/test/run-pass-fulldeps/macro-quote-noprelude.rs create mode 100644 src/test/run-pass-fulldeps/macro-quote-prelude.rs diff --git a/mk/crates.mk b/mk/crates.mk index 0bd0c70bd0519..5ff6d7a89dbe0 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -60,7 +60,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ rustc_const_eval rustc_const_math rustc_incremental -HOST_CRATES := syntax syntax_ext syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ +HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -100,6 +100,7 @@ DEPS_test := std getopts term native:rust_test_helpers DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros +DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize DEPS_rustc_const_math := std syntax log serialize @@ -114,8 +115,9 @@ DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_m DEPS_rustc_data_structures := std log serialize DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \ - rustc_trans rustc_privacy rustc_lint rustc_plugin \ - rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval \ + rustc_trans rustc_privacy rustc_lint rustc_plugin \ + rustc_metadata syntax_ext proc_macro \ + rustc_passes rustc_save_analysis rustc_const_eval \ rustc_incremental syntax_pos rustc_errors DEPS_rustc_errors := log libc serialize syntax_pos DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml new file mode 100644 index 0000000000000..99fb1d65cda90 --- /dev/null +++ b/src/libproc_macro/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "proc_macro" +version = "0.0.0" + +[lib] +name = "proc_macro" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +rustc_plugin = { path = "../librustc_plugin" } +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libproc_macro/build.rs b/src/libproc_macro/build.rs new file mode 100644 index 0000000000000..7b7590b863b71 --- /dev/null +++ b/src/libproc_macro/build.rs @@ -0,0 +1,89 @@ +// 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. + +extern crate syntax; +extern crate syntax_pos; + +use syntax::ast::Ident; +use syntax::codemap::DUMMY_SP; +use syntax::parse::token::{self, Token, keywords, str_to_ident}; +use syntax::tokenstream::{self, TokenTree, TokenStream}; +use std::rc::Rc; + +/// A wrapper around `TokenStream::concat` to avoid extra namespace specification and +/// provide TokenStream concatenation as a generic operator. +pub fn concat(ts1: TokenStream, ts2: TokenStream) -> TokenStream { + TokenStream::concat(ts1, ts2) +} + +/// Checks if two identifiers have the same name, disregarding context. This allows us to +/// fake 'reserved' keywords. +// FIXME We really want `free-identifier-=?` (a la Dybvig 1993). von Tander 2007 is +// probably the easiest way to do that. +pub fn ident_eq(tident: &TokenTree, id: Ident) -> bool { + let tid = match *tident { + TokenTree::Token(_, Token::Ident(ref id)) => id, + _ => { + return false; + } + }; + + tid.name == id.name +} + +// ____________________________________________________________________________________________ +// Conversion operators + +/// Convert a `&str` into a Token. +pub fn str_to_token_ident(s: &str) -> Token { + Token::Ident(str_to_ident(s)) +} + +/// Converts a keyword (from `syntax::parse::token::keywords`) into a Token that +/// corresponds to it. +pub fn keyword_to_token_ident(kw: keywords::Keyword) -> Token { + Token::Ident(str_to_ident(&kw.name().as_str()[..])) +} + +// ____________________________________________________________________________________________ +// Build Procedures + +/// Generically takes a `ts` and delimiter and returns `ts` delimited by the specified +/// delimiter. +pub fn build_delimited(ts: TokenStream, delim: token::DelimToken) -> TokenStream { + let tts = ts.to_tts(); + TokenStream::from_tts(vec![TokenTree::Delimited(DUMMY_SP, + Rc::new(tokenstream::Delimited { + delim: delim, + open_span: DUMMY_SP, + tts: tts, + close_span: DUMMY_SP, + }))]) +} + +/// Takes `ts` and returns `[ts]`. +pub fn build_bracket_delimited(ts: TokenStream) -> TokenStream { + build_delimited(ts, token::DelimToken::Bracket) +} + +/// Takes `ts` and returns `{ts}`. +pub fn build_brace_delimited(ts: TokenStream) -> TokenStream { + build_delimited(ts, token::DelimToken::Brace) +} + +/// Takes `ts` and returns `(ts)`. +pub fn build_paren_delimited(ts: TokenStream) -> TokenStream { + build_delimited(ts, token::DelimToken::Paren) +} + +/// Constructs `()`. +pub fn build_empty_args() -> TokenStream { + build_paren_delimited(TokenStream::mk_empty()) +} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs new file mode 100644 index 0000000000000..9e25cb88e015c --- /dev/null +++ b/src/libproc_macro/lib.rs @@ -0,0 +1,137 @@ +// 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. + +//! # Proc_Macro +//! +//! A library for procedural macro writers. +//! +//! ## Usage +//! This package provides the `qquote!` macro for syntax creation, and the prelude +//! (at libproc_macro::prelude) provides a number of operations: +//! - `concat`, for concatenating two TokenStreams. +//! - `ident_eq`, for checking if two identifiers are equal regardless of syntax context. +//! - `str_to_token_ident`, for converting an `&str` into a Token. +//! - `keyword_to_token_delim`, for converting a `parse::token::keywords::Keyword` into a +//! Token. +//! - `build_delimited`, for creating a new TokenStream from an existing one and a delimiter +//! by wrapping the TokenStream in the delimiter. +//! - `build_bracket_delimited`, `build_brace_delimited`, and `build_paren_delimited`, for +//! easing the above. +//! - `build_empty_args`, which returns a TokenStream containing `()`. +//! - `lex`, which takes an `&str` and returns the TokenStream it represents. +//! +//! The `qquote!` macro also imports `syntax::ext::proc_macro_shim::prelude::*`, so you +//! will need to `extern crate syntax` for usage. (This is a temporary solution until more +//! of the external API in libproc_macro is stabilized to support the token construction +//! operations that the qausiquoter relies on.) The shim file also provides additional +//! operations, such as `build_block_emitter` (as used in the `cond` example below). +//! +//! ## TokenStreams +//! +//! TokenStreams serve as the basis of the macro system. They are, in essence, vectors of +//! TokenTrees, where indexing treats delimited values as a single term. That is, the term +//! `even(a+c) && even(b)` will be indexibly encoded as `even | (a+c) | even | (b)` where, +//! in reality, `(a+c)` is actually a decorated pointer to `a | + | c`. +//! +//! If a user has a TokenStream that is a single, delimited value, they can use +//! `maybe_delimited` to destruct it and receive the internal vector as a new TokenStream +//! as: +//! ``` +//! `(a+c)`.maybe_delimited() ~> Some(a | + | c)` +//! ``` +//! +//! Check the TokenStream documentation for more information; the structure also provides +//! cheap concatenation and slicing. +//! +//! ## Quasiquotation +//! +//! The quasiquoter creates output that, when run, constructs the tokenstream specified as +//! input. For example, `qquote!(5 + 5)` will produce a program, that, when run, will +//! construct the TokenStream `5 | + | 5`. +//! +//! ### Unquoting +//! +//! Unquoting is currently done as `unquote`, and works by taking the single next +//! TokenTree in the TokenStream as the unquoted term. Ergonomically, `unquote(foo)` works +//! fine, but `unquote foo` is also supported. +//! +//! A simple example might be: +//! +//!``` +//!fn double(tmp: TokenStream) -> TokenStream { +//! qquote!(unquote(tmp) * 2) +//!} +//!``` +//! +//! ### Large Example: Implementing Scheme's `cond` +//! +//! Below is the full implementation of Scheme's `cond` operator. +//! +//! ``` +//! fn cond_rec(input: TokenStream) -> TokenStream { +//! if input.is_empty() { return quote!(); } +//! +//! let next = input.slice(0..1); +//! let rest = input.slice_from(1..); +//! +//! let clause : TokenStream = match next.maybe_delimited() { +//! Some(ts) => ts, +//! _ => panic!("Invalid input"), +//! }; +//! +//! // clause is ([test]) [rhs] +//! if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } +//! +//! let test: TokenStream = clause.slice(0..1); +//! let rhs: TokenStream = clause.slice_from(1..); +//! +//! if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { +//! quote!({unquote(rhs)}) +//! } else { +//! quote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) +//! } +//! } +//! ``` +//! + +#![crate_name = "proc_macro"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![feature(plugin_registrar)] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![cfg_attr(not(stage0), deny(warnings))] + +#![feature(staged_api)] +#![feature(rustc_diagnostic_macros)] +#![feature(rustc_private)] + +extern crate rustc_plugin; +extern crate syntax; +extern crate syntax_pos; +#[macro_use] extern crate log; + +mod qquote; +pub mod build; +pub mod parse; +pub mod prelude; +use qquote::qquote; + +use rustc_plugin::Registry; + +// ____________________________________________________________________________________________ +// Main macro definition + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("qquote", qquote); +} diff --git a/src/libproc_macro/parse.rs b/src/libproc_macro/parse.rs new file mode 100644 index 0000000000000..9af8a68cdcf49 --- /dev/null +++ b/src/libproc_macro/parse.rs @@ -0,0 +1,26 @@ +// 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. + +//! Parsing utilities for writing procedural macros. + +extern crate syntax; + +use syntax::parse::{ParseSess, filemap_to_tts}; +use syntax::tokenstream::TokenStream; + +/// Map a string to tts, using a made-up filename. For example, `lex(15)` will return a +/// TokenStream containing the literal 15. +pub fn lex(source_str: &str) -> TokenStream { + let ps = ParseSess::new(); + TokenStream::from_tts(filemap_to_tts(&ps, + ps.codemap().new_filemap("procmacro_lex".to_string(), + None, + source_str.to_owned()))) +} diff --git a/src/libproc_macro/prelude.rs b/src/libproc_macro/prelude.rs new file mode 100644 index 0000000000000..4c0c8ba6c6684 --- /dev/null +++ b/src/libproc_macro/prelude.rs @@ -0,0 +1,12 @@ +// 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. + +pub use build::*; +pub use parse::*; diff --git a/src/libproc_macro/qquote.rs b/src/libproc_macro/qquote.rs new file mode 100644 index 0000000000000..67d0c77b00d83 --- /dev/null +++ b/src/libproc_macro/qquote.rs @@ -0,0 +1,470 @@ +// 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. + +//! # Quasiquoter +//! This file contains the implementation internals of the quasiquoter provided by `quote!`. +//! +//! ## Ouput +//! The quasiquoter produces output of the form: +//! let tmp0 = ...; +//! let tmp1 = ...; +//! ... +//! concat(from_tokens(...), concat(...)) +//! +//! To the more explicit, the quasiquoter produces a series of bindings that each +//! construct TokenStreams via constructing Tokens and using `from_tokens`, ultimately +//! invoking `concat` on these bindings (and inlined expressions) to construct a +//! TokenStream that resembles the output syntax. +//! + +extern crate rustc_plugin; +extern crate syntax; +extern crate syntax_pos; + +use build::*; +use parse::lex; +use qquote::int_build::*; + +use syntax::ast::Ident; +use syntax::codemap::Span; +use syntax::ext::base::*; +use syntax::ext::base; +use syntax::ext::proc_macro_shim::build_block_emitter; +use syntax::parse::token::{self, Token, gensym_ident, str_to_ident}; +use syntax::print::pprust; +use syntax::tokenstream::{TokenTree, TokenStream}; + +// ____________________________________________________________________________________________ +// Main definition +/// The user should use the macro, not this procedure. +pub fn qquote<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) + -> Box { + + debug!("\nTTs in: {:?}\n", pprust::tts_to_string(&tts[..])); + let output = qquoter(cx, TokenStream::from_tts(tts.clone().to_owned())); + debug!("\nQQ out: {}\n", pprust::tts_to_string(&output.to_tts()[..])); + let imports = concat(lex("use syntax::ext::proc_macro_shim::prelude::*;"), + lex("use proc_macro::prelude::*;")); + build_block_emitter(cx, sp, build_brace_delimited(concat(imports, output))) +} + +// ____________________________________________________________________________________________ +// Datatype Definitions + +#[derive(Debug)] +struct QDelimited { + delim: token::DelimToken, + open_span: Span, + tts: Vec, + close_span: Span, +} + +#[derive(Debug)] +enum QTT { + TT(TokenTree), + QDL(QDelimited), + QIdent(TokenTree), +} + +type Bindings = Vec<(Ident, TokenStream)>; + +// ____________________________________________________________________________________________ +// Quasiquoter Algorithm +// This algorithm works as follows: +// Input: TokenStream +// 1. Walk the TokenStream, gathering up the unquoted expressions and marking them separately. +// 2. Hoist any unquoted term into its own let-binding via a gensym'd identifier +// 3. Convert the body from a `complex expression` into a simplified one via `convert_complex_tts +// 4. Stitch everything together with `concat`. +fn qquoter<'cx>(cx: &'cx mut ExtCtxt, ts: TokenStream) -> TokenStream { + if ts.is_empty() { + return lex("TokenStream::mk_empty()"); + } + let qq_res = qquote_iter(cx, 0, ts); + let mut bindings = qq_res.0; + let body = qq_res.1; + let mut cct_res = convert_complex_tts(cx, body); + + bindings.append(&mut cct_res.0); + + if bindings.is_empty() { + cct_res.1 + } else { + debug!("BINDINGS"); + for b in bindings.clone() { + debug!("{:?} = {}", b.0, pprust::tts_to_string(&b.1.to_tts()[..])); + } + TokenStream::concat(unravel(bindings), cct_res.1) + } +} + +fn qquote_iter<'cx>(cx: &'cx mut ExtCtxt, depth: i64, ts: TokenStream) -> (Bindings, Vec) { + let mut depth = depth; + let mut bindings: Bindings = Vec::new(); + let mut output: Vec = Vec::new(); + + let mut iter = ts.iter(); + + loop { + let next = iter.next(); + if next.is_none() { + break; + } + let next = next.unwrap().clone(); + match next { + TokenTree::Token(_, Token::Ident(id)) if is_unquote(id) => { + if depth == 0 { + let exp = iter.next(); + if exp.is_none() { + break; + } // produce an error or something first + let exp = vec![exp.unwrap().to_owned()]; + debug!("RHS: {:?}", exp.clone()); + let new_id = gensym_ident("tmp"); + debug!("RHS TS: {:?}", TokenStream::from_tts(exp.clone())); + debug!("RHS TS TT: {:?}", TokenStream::from_tts(exp.clone()).to_vec()); + bindings.push((new_id, TokenStream::from_tts(exp))); + debug!("BINDINGS"); + for b in bindings.clone() { + debug!("{:?} = {}", b.0, pprust::tts_to_string(&b.1.to_tts()[..])); + } + output.push(QTT::QIdent(as_tt(Token::Ident(new_id.clone())))); + } else { + depth = depth - 1; + output.push(QTT::TT(next.clone())); + } + } + TokenTree::Token(_, Token::Ident(id)) if is_qquote(id) => { + depth = depth + 1; + } + TokenTree::Delimited(_, ref dl) => { + let br = qquote_iter(cx, depth, TokenStream::from_tts(dl.tts.clone().to_owned())); + let mut bind_ = br.0; + let res_ = br.1; + bindings.append(&mut bind_); + + let new_dl = QDelimited { + delim: dl.delim, + open_span: dl.open_span, + tts: res_, + close_span: dl.close_span, + }; + + output.push(QTT::QDL(new_dl)); + } + t => { + output.push(QTT::TT(t)); + } + } + } + + (bindings, output) +} + +// ____________________________________________________________________________________________ +// Turns QQTs into a TokenStream and some Bindings. +/// Construct a chain of concatenations. +fn unravel_concats(tss: Vec) -> TokenStream { + let mut pushes: Vec = + tss.into_iter().filter(|&ref ts| !ts.is_empty()).collect(); + let mut output = match pushes.pop() { + Some(ts) => ts, + None => { + return TokenStream::mk_empty(); + } + }; + + while let Some(ts) = pushes.pop() { + output = build_fn_call(str_to_ident("concat"), + concat(concat(ts, + from_tokens(vec![Token::Comma])), + output)); + } + output +} + +/// This converts the vector of QTTs into a seet of Bindings for construction and the main +/// body as a TokenStream. +fn convert_complex_tts<'cx>(cx: &'cx mut ExtCtxt, tts: Vec) -> (Bindings, TokenStream) { + let mut pushes: Vec = Vec::new(); + let mut bindings: Bindings = Vec::new(); + + let mut iter = tts.into_iter(); + + loop { + let next = iter.next(); + if next.is_none() { + break; + } + let next = next.unwrap(); + match next { + QTT::TT(TokenTree::Token(_, t)) => { + let token_out = emit_token(t); + pushes.push(token_out); + } + // FIXME handle sequence repetition tokens + QTT::QDL(qdl) => { + debug!(" QDL: {:?} ", qdl.tts); + let new_id = gensym_ident("qdl_tmp"); + let mut cct_rec = convert_complex_tts(cx, qdl.tts); + bindings.append(&mut cct_rec.0); + bindings.push((new_id, cct_rec.1)); + + let sep = build_delim_tok(qdl.delim); + + pushes.push(build_mod_call(vec![str_to_ident("proc_macro"), + str_to_ident("build"), + str_to_ident("build_delimited")], + concat(from_tokens(vec![Token::Ident(new_id)]), + concat(lex(","), sep)))); + } + QTT::QIdent(t) => { + pushes.push(TokenStream::from_tts(vec![t])); + pushes.push(TokenStream::mk_empty()); + } + _ => panic!("Unhandled case!"), + } + + } + + (bindings, unravel_concats(pushes)) +} + +// ____________________________________________________________________________________________ +// Utilities + +/// Unravels Bindings into a TokenStream of `let` declarations. +fn unravel(binds: Bindings) -> TokenStream { + let mut output = TokenStream::mk_empty(); + + for b in binds { + output = concat(output, build_let(b.0, b.1)); + } + + output +} + +/// Checks if the Ident is `unquote`. +fn is_unquote(id: Ident) -> bool { + let qq = str_to_ident("unquote"); + id.name == qq.name // We disregard context; unquote is _reserved_ +} + +/// Checks if the Ident is `quote`. +fn is_qquote(id: Ident) -> bool { + let qq = str_to_ident("qquote"); + id.name == qq.name // We disregard context; qquote is _reserved_ +} + +mod int_build { + extern crate syntax; + extern crate syntax_pos; + + use parse::*; + use build::*; + + use syntax::ast::{self, Ident}; + use syntax::codemap::{DUMMY_SP}; + use syntax::parse::token::{self, Token, keywords, str_to_ident}; + use syntax::tokenstream::{TokenTree, TokenStream}; + + // ____________________________________________________________________________________________ + // Emitters + + pub fn emit_token(t: Token) -> TokenStream { + concat(lex("TokenStream::from_tokens"), + build_paren_delimited(build_vec(build_token_tt(t)))) + } + + pub fn emit_lit(l: token::Lit, n: Option) -> TokenStream { + let suf = match n { + Some(n) => format!("Some(ast::Name({}))", n.0), + None => "None".to_string(), + }; + + let lit = match l { + token::Lit::Byte(n) => format!("Lit::Byte(token::intern(\"{}\"))", n.to_string()), + token::Lit::Char(n) => format!("Lit::Char(token::intern(\"{}\"))", n.to_string()), + token::Lit::Integer(n) => format!("Lit::Integer(token::intern(\"{}\"))", n.to_string()), + token::Lit::Float(n) => format!("Lit::Float(token::intern(\"{}\"))", n.to_string()), + token::Lit::Str_(n) => format!("Lit::Str_(token::intern(\"{}\"))", n.to_string()), + token::Lit::ByteStr(n) => format!("Lit::ByteStr(token::intern(\"{}\"))", n.to_string()), + _ => panic!("Unsupported literal"), + }; + + let res = format!("Token::Literal({},{})", lit, suf); + debug!("{}", res); + lex(&res) + } + + // ____________________________________________________________________________________________ + // Token Builders + + pub fn build_binop_tok(bot: token::BinOpToken) -> TokenStream { + match bot { + token::BinOpToken::Plus => lex("Token::BinOp(BinOpToken::Plus)"), + token::BinOpToken::Minus => lex("Token::BinOp(BinOpToken::Minus)"), + token::BinOpToken::Star => lex("Token::BinOp(BinOpToken::Star)"), + token::BinOpToken::Slash => lex("Token::BinOp(BinOpToken::Slash)"), + token::BinOpToken::Percent => lex("Token::BinOp(BinOpToken::Percent)"), + token::BinOpToken::Caret => lex("Token::BinOp(BinOpToken::Caret)"), + token::BinOpToken::And => lex("Token::BinOp(BinOpToken::And)"), + token::BinOpToken::Or => lex("Token::BinOp(BinOpToken::Or)"), + token::BinOpToken::Shl => lex("Token::BinOp(BinOpToken::Shl)"), + token::BinOpToken::Shr => lex("Token::BinOp(BinOpToken::Shr)"), + } + } + + pub fn build_binopeq_tok(bot: token::BinOpToken) -> TokenStream { + match bot { + token::BinOpToken::Plus => lex("Token::BinOpEq(BinOpToken::Plus)"), + token::BinOpToken::Minus => lex("Token::BinOpEq(BinOpToken::Minus)"), + token::BinOpToken::Star => lex("Token::BinOpEq(BinOpToken::Star)"), + token::BinOpToken::Slash => lex("Token::BinOpEq(BinOpToken::Slash)"), + token::BinOpToken::Percent => lex("Token::BinOpEq(BinOpToken::Percent)"), + token::BinOpToken::Caret => lex("Token::BinOpEq(BinOpToken::Caret)"), + token::BinOpToken::And => lex("Token::BinOpEq(BinOpToken::And)"), + token::BinOpToken::Or => lex("Token::BinOpEq(BinOpToken::Or)"), + token::BinOpToken::Shl => lex("Token::BinOpEq(BinOpToken::Shl)"), + token::BinOpToken::Shr => lex("Token::BinOpEq(BinOpToken::Shr)"), + } + } + + pub fn build_delim_tok(dt: token::DelimToken) -> TokenStream { + match dt { + token::DelimToken::Paren => lex("DelimToken::Paren"), + token::DelimToken::Bracket => lex("DelimToken::Bracket"), + token::DelimToken::Brace => lex("DelimToken::Brace"), + token::DelimToken::NoDelim => lex("DelimToken::NoDelim"), + } + } + + pub fn build_token_tt(t: Token) -> TokenStream { + match t { + Token::Eq => lex("Token::Eq"), + Token::Lt => lex("Token::Lt"), + Token::Le => lex("Token::Le"), + Token::EqEq => lex("Token::EqEq"), + Token::Ne => lex("Token::Ne"), + Token::Ge => lex("Token::Ge"), + Token::Gt => lex("Token::Gt"), + Token::AndAnd => lex("Token::AndAnd"), + Token::OrOr => lex("Token::OrOr"), + Token::Not => lex("Token::Not"), + Token::Tilde => lex("Token::Tilde"), + Token::BinOp(tok) => build_binop_tok(tok), + Token::BinOpEq(tok) => build_binopeq_tok(tok), + Token::At => lex("Token::At"), + Token::Dot => lex("Token::Dot"), + Token::DotDot => lex("Token::DotDot"), + Token::DotDotDot => lex("Token::DotDotDot"), + Token::Comma => lex("Token::Comma"), + Token::Semi => lex("Token::Semi"), + Token::Colon => lex("Token::Colon"), + Token::ModSep => lex("Token::ModSep"), + Token::RArrow => lex("Token::RArrow"), + Token::LArrow => lex("Token::LArrow"), + Token::FatArrow => lex("Token::FatArrow"), + Token::Pound => lex("Token::Pound"), + Token::Dollar => lex("Token::Dollar"), + Token::Question => lex("Token::Question"), + Token::OpenDelim(dt) => { + match dt { + token::DelimToken::Paren => lex("Token::OpenDelim(DelimToken::Paren)"), + token::DelimToken::Bracket => lex("Token::OpenDelim(DelimToken::Bracket)"), + token::DelimToken::Brace => lex("Token::OpenDelim(DelimToken::Brace)"), + token::DelimToken::NoDelim => lex("DelimToken::NoDelim"), + } + } + Token::CloseDelim(dt) => { + match dt { + token::DelimToken::Paren => lex("Token::CloseDelim(DelimToken::Paren)"), + token::DelimToken::Bracket => lex("Token::CloseDelim(DelimToken::Bracket)"), + token::DelimToken::Brace => lex("Token::CloseDelim(DelimToken::Brace)"), + token::DelimToken::NoDelim => lex("DelimToken::NoDelim"), + } + } + Token::Underscore => lex("_"), + Token::Literal(lit, sfx) => emit_lit(lit, sfx), + // fix ident expansion information... somehow + Token::Ident(ident) => lex(&format!("Token::Ident(str_to_ident(\"{}\"))", ident.name)), + Token::Lifetime(ident) => lex(&format!("Token::Ident(str_to_ident(\"{}\"))", + ident.name)), + _ => panic!("Unhandled case!"), + } + } + + // ____________________________________________________________________________________________ + // Conversion operators + + pub fn as_tt(t: Token) -> TokenTree { + // FIXME do something nicer with the spans + TokenTree::Token(DUMMY_SP, t) + } + + // ____________________________________________________________________________________________ + // Build Procedures + + /// Takes `input` and returns `vec![input]`. + pub fn build_vec(ts: TokenStream) -> TokenStream { + build_mac_call(str_to_ident("vec"), ts) + // tts.clone().to_owned() + } + + /// Takes `ident` and `rhs` and produces `let ident = rhs;`. + pub fn build_let(id: Ident, tts: TokenStream) -> TokenStream { + concat(from_tokens(vec![keyword_to_token_ident(keywords::Let), + Token::Ident(id), + Token::Eq]), + concat(tts, from_tokens(vec![Token::Semi]))) + } + + /// Takes `ident ...`, and `args ...` and produces `ident::...(args ...)`. + pub fn build_mod_call(ids: Vec, args: TokenStream) -> TokenStream { + let call = from_tokens(intersperse(ids.into_iter().map(|id| Token::Ident(id)).collect(), + Token::ModSep)); + concat(call, build_paren_delimited(args)) + } + + /// Takes `ident` and `args ...` and produces `ident(args ...)`. + pub fn build_fn_call(name: Ident, args: TokenStream) -> TokenStream { + concat(from_tokens(vec![Token::Ident(name)]), build_paren_delimited(args)) + } + + /// Takes `ident` and `args ...` and produces `ident!(args ...)`. + pub fn build_mac_call(name: Ident, args: TokenStream) -> TokenStream { + concat(from_tokens(vec![Token::Ident(name), Token::Not]), + build_paren_delimited(args)) + } + + // ____________________________________________________________________________________________ + // Utilities + + /// A wrapper around `TokenStream::from_tokens` to avoid extra namespace specification and + /// provide it as a generic operator. + pub fn from_tokens(tokens: Vec) -> TokenStream { + TokenStream::from_tokens(tokens) + } + + pub fn intersperse(vs: Vec, t: T) -> Vec + where T: Clone + { + if vs.len() < 2 { + return vs; + } + let mut output = vec![vs.get(0).unwrap().to_owned()]; + + for v in vs.into_iter().skip(1) { + output.push(t.clone()); + output.push(v); + } + output + } +} diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 54c62d3665994..772d83eb2cfad 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -33,4 +33,5 @@ rustc_metadata = { path = "../librustc_metadata" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } +proc_macro = { path = "../libproc_macro" } diff --git a/src/libsyntax/ext/proc_macro_shim.rs b/src/libsyntax/ext/proc_macro_shim.rs new file mode 100644 index 0000000000000..fa37e9b54e457 --- /dev/null +++ b/src/libsyntax/ext/proc_macro_shim.rs @@ -0,0 +1,69 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This is a shim file to ease the transition to the final procedural macro interface for +//! Macros 2.0. It currently exposes the `libsyntax` operations that the quasiquoter's +//! output needs to compile correctly, along with the following operators: +//! +//! - `build_block_emitter`, which produces a `block` output macro result from the +//! provided TokenStream. + +use ast; +use codemap::Span; +use parse::parser::Parser; +use ptr::P; +use tokenstream::TokenStream; +use ext::base::*; + +/// Take a `ExtCtxt`, `Span`, and `TokenStream`, and produce a Macro Result that parses +/// the TokenStream as a block and returns it as an `Expr`. +pub fn build_block_emitter<'cx>(cx: &'cx mut ExtCtxt, sp: Span, output: TokenStream) + -> Box { + let parser = cx.new_parser_from_tts(&output.to_tts()); + + struct Result<'a> { + prsr: Parser<'a>, + span: Span, + }; //FIXME is this the right lifetime + + impl<'a> Result<'a> { + fn block(&mut self) -> P { + let res = self.prsr.parse_block().unwrap(); + res + } + } + + impl<'a> MacResult for Result<'a> { + fn make_expr(self: Box) -> Option> { + let mut me = *self; + Some(P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprKind::Block(me.block()), + span: me.span, + attrs: ast::ThinVec::new(), + })) + + } + } + + Box::new(Result { + prsr: parser, + span: sp, + }) +} + +pub mod prelude { + pub use ext::proc_macro_shim::build_block_emitter; + pub use ast::Ident; + pub use codemap::{DUMMY_SP, Span}; + pub use ext::base::{ExtCtxt, MacResult}; + pub use parse::token::{self, Token, DelimToken, keywords, str_to_ident}; + pub use tokenstream::{TokenTree, TokenStream}; +} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 5ad1744418890..b4311fc007d3d 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -128,6 +128,7 @@ pub mod ext { pub mod build; pub mod expand; pub mod hygiene; + pub mod proc_macro_shim; pub mod quote; pub mod source_util; diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 89ead21cc10cb..aab6f3d682e2c 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -548,6 +548,12 @@ impl TokenStream { TokenStream::mk_leaf(Rc::new(trees), span) } + /// Convert a vector of Tokens into a TokenStream. + pub fn from_tokens(tokens: Vec) -> TokenStream { + // FIXME do something nicer with the spans + TokenStream::from_tts(tokens.into_iter().map(|t| TokenTree::Token(DUMMY_SP, t)).collect()) + } + /// Manually change a TokenStream's span. pub fn respan(self, span: Span) -> TokenStream { match self.ts { diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 0b2287cf233d1..4f78519e13aa8 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -40,6 +40,16 @@ version = "0.0.0" name = "log" version = "0.0.0" +[[package]] +name = "proc_macro" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "rustc_plugin 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + [[package]] name = "rbml" version = "0.0.0" @@ -136,6 +146,7 @@ dependencies = [ "flate 0.0.0", "graphviz 0.0.0", "log 0.0.0", + "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_borrowck 0.0.0", diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs new file mode 100644 index 0000000000000..6aee63e2858e2 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs @@ -0,0 +1,65 @@ +// 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(unused_parens)] +#![feature(plugin)] +#![feature(plugin_registrar)] +#![feature(rustc_private)] +#![plugin(proc_macro)] + +extern crate rustc_plugin; +extern crate proc_macro; +extern crate syntax; + +use proc_macro::build::ident_eq; + +use syntax::ext::base::{ExtCtxt, MacResult}; +use syntax::ext::proc_macro_shim::build_block_emitter; +use syntax::tokenstream::{TokenTree, TokenStream}; +use syntax::parse::token::str_to_ident; +use syntax::codemap::Span; + +use rustc_plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("cond", cond); +} + +fn cond<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { + let output = cond_rec(TokenStream::from_tts(tts.clone().to_owned())); + build_block_emitter(cx, sp, output) +} + +fn cond_rec(input: TokenStream) -> TokenStream { + if input.is_empty() { + return qquote!(); + } + + let next = input.slice(0..1); + let rest = input.slice_from(1..); + + let clause : TokenStream = match next.maybe_delimited() { + Some(ts) => ts, + _ => panic!("Invalid input"), + }; + + // clause is ([test]) [rhs] + if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } + + let test: TokenStream = clause.slice(0..1); + let rhs: TokenStream = clause.slice_from(1..); + + if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { + qquote!({unquote(rhs)}) + } else { + qquote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) + } +} diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs new file mode 100644 index 0000000000000..8291c8a1e41c6 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -0,0 +1,66 @@ +// 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. + +#![allow(unused_parens)] +#![feature(plugin)] +#![feature(plugin_registrar)] +#![feature(rustc_private)] +#![plugin(proc_macro)] + +extern crate rustc_plugin; +extern crate proc_macro; +extern crate syntax; + +use proc_macro::prelude::*; + +use rustc_plugin::Registry; + +use syntax::ast::Ident; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ext::proc_macro_shim::build_block_emitter; +use syntax::ext::base::{ExtCtxt, MacResult}; +use syntax::parse::token::{self, Token, DelimToken, keywords, str_to_ident}; +use syntax::tokenstream::{TokenTree, TokenStream}; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("cond", cond); +} + +fn cond<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { + let output = cond_rec(TokenStream::from_tts(tts.clone().to_owned())); + build_block_emitter(cx, sp, output) +} + +fn cond_rec(input: TokenStream) -> TokenStream { + if input.is_empty() { + return qquote!(); + } + + let next = input.slice(0..1); + let rest = input.slice_from(1..); + + let clause : TokenStream = match next.maybe_delimited() { + Some(ts) => ts, + _ => panic!("Invalid input"), + }; + + // clause is ([test]) [rhs] + if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } + + let test: TokenStream = clause.slice(0..1); + let rhs: TokenStream = clause.slice_from(1..); + + if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { + qquote!({unquote(rhs)}) + } else { + qquote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) + } +} diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs new file mode 100644 index 0000000000000..2d92a0ef18199 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs @@ -0,0 +1,60 @@ +// 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(unused_parens)] +#![feature(plugin)] +#![feature(plugin_registrar)] +#![feature(rustc_private)] +#![plugin(proc_macro)] + +extern crate rustc_plugin; +extern crate proc_macro; +extern crate syntax; + +use syntax::ext::proc_macro_shim::prelude::*; +use proc_macro::prelude::*; + +use rustc_plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("cond", cond); +} + +fn cond<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { + let output = cond_rec(TokenStream::from_tts(tts.clone().to_owned())); + build_block_emitter(cx, sp, output) +} + +fn cond_rec(input: TokenStream) -> TokenStream { + if input.is_empty() { + return qquote!(); + } + + let next = input.slice(0..1); + let rest = input.slice_from(1..); + + let clause : TokenStream = match next.maybe_delimited() { + Some(ts) => ts, + _ => panic!("Invalid input"), + }; + + // clause is ([test]) [rhs] + if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } + + let test: TokenStream = clause.slice(0..1); + let rhs: TokenStream = clause.slice_from(1..); + + if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { + qquote!({unquote(rhs)}) + } else { + qquote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) + } +} diff --git a/src/test/run-pass-fulldeps/macro-quote-1.rs b/src/test/run-pass-fulldeps/macro-quote-1.rs new file mode 100644 index 0000000000000..4ee775dec0cef --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-quote-1.rs @@ -0,0 +1,28 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-stage1 + +#![feature(plugin)] +#![feature(rustc_private)] +#![plugin(proc_macro)] + +extern crate proc_macro; +use proc_macro::prelude::*; + +extern crate syntax; +use syntax::ast::Ident; +use syntax::codemap::DUMMY_SP; +use syntax::parse::token::{self, Token, keywords, str_to_ident}; + +fn main() { + let lex_true = lex("true"); + assert_eq!(qquote!(true).eq_unspanned(&lex_true), true); +} diff --git a/src/test/run-pass-fulldeps/macro-quote-cond.rs b/src/test/run-pass-fulldeps/macro-quote-cond.rs new file mode 100644 index 0000000000000..fa969b6a087cf --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-quote-cond.rs @@ -0,0 +1,54 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:cond_plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![feature(rustc_private)] +#![plugin(cond_plugin)] + +fn fact(n : i64) -> i64 { + if n == 0 { + 1 + } else { + n * fact(n - 1) + } +} + +fn fact_cond(n : i64) -> i64 { + cond!( + ((n == 0) 1) + (else (n * fact_cond(n-1))) + ) +} + +fn fib(n : i64) -> i64 { + if n == 0 || n == 1 { + 1 + } else { + fib(n-1) + fib(n-2) + } +} + +fn fib_cond(n : i64) -> i64 { + cond!( + ((n == 0) 1) + ((n == 1) 1) + (else (fib_cond(n-1) + fib_cond(n-2))) + ) +} + +fn main() { + assert_eq!(fact(3), fact_cond(3)); + assert_eq!(fact(5), fact_cond(5)); + assert_eq!(fib(5), fib_cond(5)); + assert_eq!(fib(8), fib_cond(8)); +} diff --git a/src/test/run-pass-fulldeps/macro-quote-noprelude.rs b/src/test/run-pass-fulldeps/macro-quote-noprelude.rs new file mode 100644 index 0000000000000..4184ca7be372f --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-quote-noprelude.rs @@ -0,0 +1,54 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:cond_noprelude_plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![feature(rustc_private)] +#![plugin(cond_noprelude_plugin)] + +fn fact(n : i64) -> i64 { + if n == 0 { + 1 + } else { + n * fact(n - 1) + } +} + +fn fact_cond(n : i64) -> i64 { + cond!( + ((n == 0) 1) + (else (n * fact_cond(n-1))) + ) +} + +fn fib(n : i64) -> i64 { + if n == 0 || n == 1 { + 1 + } else { + fib(n-1) + fib(n-2) + } +} + +fn fib_cond(n : i64) -> i64 { + cond!( + ((n == 0) 1) + ((n == 1) 1) + (else (fib_cond(n-1) + fib_cond(n-2))) + ) +} + +fn main() { + assert_eq!(fact(3), fact_cond(3)); + assert_eq!(fact(5), fact_cond(5)); + assert_eq!(fib(5), fib_cond(5)); + assert_eq!(fib(8), fib_cond(8)); +} diff --git a/src/test/run-pass-fulldeps/macro-quote-prelude.rs b/src/test/run-pass-fulldeps/macro-quote-prelude.rs new file mode 100644 index 0000000000000..5b703a5bc2668 --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-quote-prelude.rs @@ -0,0 +1,54 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:cond_prelude_plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![feature(rustc_private)] +#![plugin(cond_prelude_plugin)] + +fn fact(n : i64) -> i64 { + if n == 0 { + 1 + } else { + n * fact(n - 1) + } +} + +fn fact_cond(n : i64) -> i64 { + cond!( + ((n == 0) 1) + (else (n * fact_cond(n-1))) + ) +} + +fn fib(n : i64) -> i64 { + if n == 0 || n == 1 { + 1 + } else { + fib(n-1) + fib(n-2) + } +} + +fn fib_cond(n : i64) -> i64 { + cond!( + ((n == 0) 1) + ((n == 1) 1) + (else (fib_cond(n-1) + fib_cond(n-2))) + ) +} + +fn main() { + assert_eq!(fact(3), fact_cond(3)); + assert_eq!(fact(5), fact_cond(5)); + assert_eq!(fib(5), fib_cond(5)); + assert_eq!(fib(8), fib_cond(8)); +} diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index 48016721d52c1..4932fd5147afa 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -88,6 +88,12 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { continue } + // We want the compiler to depend on the proc_macro crate so that it is built and + // included in the end, but we don't want to actually use it in the compiler. + if toml.contains("name = \"rustc_driver\"") && krate == "proc_macro" { + continue + } + if !librs.contains(&format!("extern crate {}", krate)) { println!("{} doesn't have `extern crate {}`, but Cargo.toml \ depends on it", libfile.display(), krate); From 330b7f7359f27efee391be2edc1fa896146535f0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 16 Aug 2016 16:58:20 +0100 Subject: [PATCH 050/768] Implement RFC 1649 --- src/libcore/sync/atomic.rs | 142 +++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 2a7a0b6232936..14ce4f56fd22c 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -90,6 +90,8 @@ use default::Default; use fmt; /// A boolean type which can be safely shared between threads. +/// +/// This type has the same in-memory representation as a `bool`. #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] pub struct AtomicBool { @@ -110,6 +112,8 @@ impl Default for AtomicBool { unsafe impl Sync for AtomicBool {} /// A raw pointer type which can be safely shared between threads. +/// +/// This type has the same in-memory representation as a `*mut T`. #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] pub struct AtomicPtr { @@ -191,6 +195,48 @@ impl AtomicBool { AtomicBool { v: UnsafeCell::new(v as u8) } } + /// Returns a mutable reference to the underlying `bool`. + /// + /// This is safe because the mutable reference guarantees that no other threads are + /// concurrently accessing the atomic data. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_access)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = AtomicBool::new(true); + /// assert_eq!(*some_bool.get_mut(), true); + /// *some_bool.get_mut() = false; + /// assert_eq!(some_bool.load(Ordering::SeqCst), false); + /// ``` + #[inline] + #[unstable(feature = "atomic_access", issue = "35603")] + pub fn get_mut(&mut self) -> &mut bool { + unsafe { &mut *(self.v.get() as *mut bool) } + } + + /// Consumes the atomic and returns the contained value. + /// + /// This is safe because passing `self` by value guarantees that no other threads are + /// concurrently accessing the atomic data. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_access)] + /// use std::sync::atomic::AtomicBool; + /// + /// let some_bool = AtomicBool::new(true); + /// assert_eq!(some_bool.into_inner(), true); + /// ``` + #[inline] + #[unstable(feature = "atomic_access", issue = "35603")] + pub fn into_inner(self) -> bool { + unsafe { self.v.into_inner() != 0 } + } + /// Loads a value from the bool. /// /// `load` takes an `Ordering` argument which describes the memory ordering of this operation. @@ -528,6 +574,47 @@ impl AtomicPtr { AtomicPtr { p: UnsafeCell::new(p) } } + /// Returns a mutable reference to the underlying pointer. + /// + /// This is safe because the mutable reference guarantees that no other threads are + /// concurrently accessing the atomic data. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_access)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut atomic_ptr = AtomicPtr::new(&mut 10); + /// *atomic_ptr.get_mut() = &mut 5; + /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5); + /// ``` + #[inline] + #[unstable(feature = "atomic_access", issue = "35603")] + pub fn get_mut(&mut self) -> &mut *mut T { + unsafe { &mut *self.p.get() } + } + + /// Consumes the atomic and returns the contained value. + /// + /// This is safe because passing `self` by value guarantees that no other threads are + /// concurrently accessing the atomic data. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_access)] + /// use std::sync::atomic::AtomicPtr; + /// + /// let atomic_ptr = AtomicPtr::new(&mut 5); + /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5); + /// ``` + #[inline] + #[unstable(feature = "atomic_access", issue = "35603")] + pub fn into_inner(self) -> *mut T { + unsafe { self.p.into_inner() } + } + /// Loads a value from the pointer. /// /// `load` takes an `Ordering` argument which describes the memory ordering of this operation. @@ -730,8 +817,11 @@ macro_rules! atomic_int { ($stable:meta, $stable_cxchg:meta, $stable_debug:meta, + $stable_access:meta, $int_type:ident $atomic_type:ident $atomic_init:ident) => { /// An integer type which can be safely shared between threads. + /// + /// This type has the same in-memory representation as the underlying integer type. #[$stable] pub struct $atomic_type { v: UnsafeCell<$int_type>, @@ -777,6 +867,48 @@ macro_rules! atomic_int { $atomic_type {v: UnsafeCell::new(v)} } + /// Returns a mutable reference to the underlying integer. + /// + /// This is safe because the mutable reference guarantees that no other threads are + /// concurrently accessing the atomic data. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_access)] + /// use std::sync::atomic::{AtomicIsize, Ordering}; + /// + /// let mut some_isize = AtomicIsize::new(10); + /// assert_eq!(*some_isize.get_mut(), 10); + /// *some_isize.get_mut() = 5; + /// assert_eq!(some_isize.load(Ordering::SeqCst), 5); + /// ``` + #[inline] + #[$stable_access] + pub fn get_mut(&mut self) -> &mut $int_type { + unsafe { &mut *self.v.get() } + } + + /// Consumes the atomic and returns the contained value. + /// + /// This is safe because passing `self` by value guarantees that no other threads are + /// concurrently accessing the atomic data. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_access)] + /// use std::sync::atomic::AtomicIsize; + /// + /// let some_isize = AtomicIsize::new(5); + /// assert_eq!(some_isize.into_inner(), 5); + /// ``` + #[inline] + #[$stable_access] + pub fn into_inner(self) -> $int_type { + unsafe { self.v.into_inner() } + } + /// Loads a value from the atomic integer. /// /// `load` takes an `Ordering` argument which describes the memory ordering of this @@ -1057,6 +1189,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), i8 AtomicI8 ATOMIC_I8_INIT } #[cfg(target_has_atomic = "8")] @@ -1064,6 +1197,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), u8 AtomicU8 ATOMIC_U8_INIT } #[cfg(target_has_atomic = "16")] @@ -1071,6 +1205,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), i16 AtomicI16 ATOMIC_I16_INIT } #[cfg(target_has_atomic = "16")] @@ -1078,6 +1213,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), u16 AtomicU16 ATOMIC_U16_INIT } #[cfg(target_has_atomic = "32")] @@ -1085,6 +1221,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), i32 AtomicI32 ATOMIC_I32_INIT } #[cfg(target_has_atomic = "32")] @@ -1092,6 +1229,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), u32 AtomicU32 ATOMIC_U32_INIT } #[cfg(target_has_atomic = "64")] @@ -1099,6 +1237,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), i64 AtomicI64 ATOMIC_I64_INIT } #[cfg(target_has_atomic = "64")] @@ -1106,6 +1245,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), u64 AtomicU64 ATOMIC_U64_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1113,6 +1253,7 @@ atomic_int!{ stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), + unstable(feature = "atomic_access", issue = "35603"), isize AtomicIsize ATOMIC_ISIZE_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1120,6 +1261,7 @@ atomic_int!{ stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), + unstable(feature = "atomic_access", issue = "35603"), usize AtomicUsize ATOMIC_USIZE_INIT } From 1fc18aab5d6c62633562729bff1435299b2c344d Mon Sep 17 00:00:00 2001 From: Dustin Bensing Date: Tue, 16 Aug 2016 23:50:32 +0200 Subject: [PATCH 051/768] Update E0005 to use a label --- src/librustc_const_eval/check_match.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index bf6ebcb5efefb..5db293f5bb016 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -1073,11 +1073,12 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) { }; is_refutable(cx, pat, |uncovered_pat| { - span_err!(cx.tcx.sess, pat.span, E0005, + let pattern_string = pat_to_string(uncovered_pat); + struct_span_err!(cx.tcx.sess, pat.span, E0005, "refutable pattern in {}: `{}` not covered", origin, - pat_to_string(uncovered_pat), - ); + pattern_string, + ).span_label(pat.span, &format!("pattern `{}` not covered", pattern_string)).emit(); }); } From 1cf9cafeb14c4e9b16727b10953da95c5c5b0b1d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 16 Aug 2016 17:07:55 -0500 Subject: [PATCH 052/768] add mips-uclibc targets These targets cover OpenWRT 15.05 devices, which use the soft float ABI and the uclibc library. None of the other built-in mips targets covered those devices (mips-gnu is hard float and glibc-based, mips-musl is musl-based). With this commit one can now build std for these devices using these commands: ``` $ configure --enable-rustbuild --target=mips-unknown-linux-uclibc $ make ``` cc #35673 --- mk/cfg/mips-unknown-linux-uclibc.mk | 1 + mk/cfg/mipsel-unknown-linux-uclibc.mk | 1 + .../target/mips_unknown_linux_uclibc.rs | 30 ++++++++++++++++++ .../target/mipsel_unknown_linux_uclibc.rs | 31 +++++++++++++++++++ src/librustc_back/target/mod.rs | 2 ++ 5 files changed, 65 insertions(+) create mode 100644 mk/cfg/mips-unknown-linux-uclibc.mk create mode 100644 mk/cfg/mipsel-unknown-linux-uclibc.mk create mode 100644 src/librustc_back/target/mips_unknown_linux_uclibc.rs create mode 100644 src/librustc_back/target/mipsel_unknown_linux_uclibc.rs diff --git a/mk/cfg/mips-unknown-linux-uclibc.mk b/mk/cfg/mips-unknown-linux-uclibc.mk new file mode 100644 index 0000000000000..34aee77ae2107 --- /dev/null +++ b/mk/cfg/mips-unknown-linux-uclibc.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/cfg/mipsel-unknown-linux-uclibc.mk b/mk/cfg/mipsel-unknown-linux-uclibc.mk new file mode 100644 index 0000000000000..34aee77ae2107 --- /dev/null +++ b/mk/cfg/mipsel-unknown-linux-uclibc.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs new file mode 100644 index 0000000000000..529bd310391cd --- /dev/null +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -0,0 +1,30 @@ +// 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. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips-unknown-linux-uclibc".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "linux".to_string(), + target_env: "uclibc".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + cpu: "mips32r2".to_string(), + features: "+mips32r2,+soft-float".to_string(), + max_atomic_width: 32, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs new file mode 100644 index 0000000000000..1040a0fbe1724 --- /dev/null +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -0,0 +1,31 @@ +// 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. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mipsel-unknown-linux-uclibc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "linux".to_string(), + target_env: "uclibc".to_string(), + target_vendor: "unknown".to_string(), + + options: TargetOptions { + cpu: "mips32".to_string(), + features: "+mips32,+soft-float".to_string(), + max_atomic_width: 32, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 18686e3f1d648..86cd86d282cf5 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -143,6 +143,8 @@ supported_targets! { ("i686-unknown-linux-musl", i686_unknown_linux_musl), ("mips-unknown-linux-musl", mips_unknown_linux_musl), ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl), + ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc), + ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc), ("i686-linux-android", i686_linux_android), ("arm-linux-androideabi", arm_linux_androideabi), From 7a7cd644cbcf8f57a156a32c7e1312de86682b0d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 3 Aug 2016 13:14:59 +1200 Subject: [PATCH 053/768] rustdoc: refactoring and tidying up pulled out of #35020 --- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/item_type.rs | 4 +- src/librustdoc/html/layout.rs | 6 +- src/librustdoc/html/render.rs | 214 ++++++++++++++++--------------- 4 files changed, 114 insertions(+), 112 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 854ca57e8556c..8802bc6dc42e0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -326,7 +326,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { url.push_str("/index.html"); } _ => { - url.push_str(shortty.to_static_str()); + url.push_str(shortty.css_class()); url.push_str("."); url.push_str(fqp.last().unwrap()); url.push_str(".html"); diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 74f7b099044f1..c3d38637ab70c 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -90,7 +90,7 @@ impl ItemType { } } - pub fn to_static_str(&self) -> &'static str { + pub fn css_class(&self) -> &'static str { match *self { ItemType::Module => "mod", ItemType::ExternCrate => "externcrate", @@ -117,6 +117,6 @@ impl ItemType { impl fmt::Display for ItemType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_static_str().fmt(f) + self.css_class().fmt(f) } } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 265ed6be1552d..151e138efefbf 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -24,7 +24,7 @@ pub struct Layout { pub struct Page<'a> { pub title: &'a str, - pub ty: &'a str, + pub css_class: &'a str, pub root_path: &'a str, pub description: &'a str, pub keywords: &'a str, @@ -80,7 +80,7 @@ r##" -
{content}
+
{content}
@@ -152,7 +152,7 @@ r##" }, content = *t, root_path = page.root_path, - ty = page.ty, + css_class = page.css_class, logo = if layout.logo.is_empty() { "".to_string() } else { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e4e886c853347..963ea48d63420 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -587,7 +587,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { for &(did, ref item) in orphan_methods { if let Some(&(ref fqp, _)) = paths.get(&did) { search_index.push(IndexItem { - ty: shortty(item), + ty: item_type(item), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), desc: Escape(&shorter(item.doc_value())).to_string(), @@ -714,10 +714,10 @@ fn write_shared(cx: &Context, for line in BufReader::new(File::open(path)?).lines() { let line = line?; if !line.starts_with(key) { - continue + continue; } if line.starts_with(&format!(r#"{}["{}"]"#, key, krate)) { - continue + continue; } ret.push(line.to_string()); } @@ -761,7 +761,7 @@ fn write_shared(cx: &Context, try_err!(mkdir(&mydst), &mydst); } mydst.push(&format!("{}.{}.js", - remote_item_type.to_static_str(), + remote_item_type.css_class(), remote_path[remote_path.len() - 1])); let all_implementors = try_err!(collect(&mydst, &krate.name, "implementors"), @@ -832,7 +832,7 @@ fn mkdir(path: &Path) -> io::Result<()> { } /// Returns a documentation-level item type from the item. -fn shortty(item: &clean::Item) -> ItemType { +fn item_type(item: &clean::Item) -> ItemType { ItemType::from_item(item) } @@ -952,7 +952,7 @@ impl<'a> SourceCollector<'a> { let mut fname = p.file_name().expect("source has no filename") .to_os_string(); fname.push(".html"); - cur.push(&fname[..]); + cur.push(&fname); href.push_str(&fname.to_string_lossy()); let mut w = BufWriter::new(File::create(&cur)?); @@ -961,7 +961,7 @@ impl<'a> SourceCollector<'a> { let desc = format!("Source to the Rust file `{}`.", filename); let page = layout::Page { title: &title, - ty: "source", + css_class: "source", root_path: &root_path, description: &desc, keywords: BASIC_KEYWORDS, @@ -1080,7 +1080,7 @@ impl DocFolder for Cache { // inserted later on when serializing the search-index. if item.def_id.index != CRATE_DEF_INDEX { self.search_index.push(IndexItem { - ty: shortty(&item), + ty: item_type(&item), name: s.to_string(), path: path.join("::").to_string(), desc: Escape(&shorter(item.doc_value())).to_string(), @@ -1126,7 +1126,7 @@ impl DocFolder for Cache { self.access_levels.is_public(item.def_id) { self.paths.insert(item.def_id, - (self.stack.clone(), shortty(&item))); + (self.stack.clone(), item_type(&item))); } } // link variants to their parent enum because pages aren't emitted @@ -1139,7 +1139,7 @@ impl DocFolder for Cache { clean::PrimitiveItem(..) if item.visibility.is_some() => { self.paths.insert(item.def_id, (self.stack.clone(), - shortty(&item))); + item_type(&item))); } _ => {} @@ -1283,74 +1283,77 @@ impl Context { Ok(()) } - /// Non-parallelized version of rendering an item. This will take the input - /// item, render its contents, and then invoke the specified closure with - /// all sub-items which need to be rendered. - /// - /// The rendering driver uses this closure to queue up more work. - fn item(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where - F: FnMut(&mut Context, clean::Item), - { - fn render(writer: &mut io::Write, cx: &Context, it: &clean::Item, - pushname: bool) -> io::Result<()> { - // A little unfortunate that this is done like this, but it sure - // does make formatting *a lot* nicer. - CURRENT_LOCATION_KEY.with(|slot| { - *slot.borrow_mut() = cx.current.clone(); - }); + fn render_item(&self, + writer: &mut io::Write, + it: &clean::Item, + pushname: bool) + -> io::Result<()> { + // A little unfortunate that this is done like this, but it sure + // does make formatting *a lot* nicer. + CURRENT_LOCATION_KEY.with(|slot| { + *slot.borrow_mut() = self.current.clone(); + }); - let mut title = if it.is_primitive() { - // No need to include the namespace for primitive types - String::new() - } else { - cx.current.join("::") - }; - if pushname { - if !title.is_empty() { - title.push_str("::"); - } - title.push_str(it.name.as_ref().unwrap()); + let mut title = if it.is_primitive() { + // No need to include the namespace for primitive types + String::new() + } else { + self.current.join("::") + }; + if pushname { + if !title.is_empty() { + title.push_str("::"); } - title.push_str(" - Rust"); - let tyname = shortty(it).to_static_str(); - let desc = if it.is_crate() { - format!("API documentation for the Rust `{}` crate.", - cx.shared.layout.krate) - } else { - format!("API documentation for the Rust `{}` {} in crate `{}`.", - it.name.as_ref().unwrap(), tyname, cx.shared.layout.krate) - }; - let keywords = make_item_keywords(it); - let page = layout::Page { - ty: tyname, - root_path: &cx.root_path, - title: &title, - description: &desc, - keywords: &keywords, - }; + title.push_str(it.name.as_ref().unwrap()); + } + title.push_str(" - Rust"); + let tyname = item_type(it).css_class(); + let desc = if it.is_crate() { + format!("API documentation for the Rust `{}` crate.", + self.shared.layout.krate) + } else { + format!("API documentation for the Rust `{}` {} in crate `{}`.", + it.name.as_ref().unwrap(), tyname, self.shared.layout.krate) + }; + let keywords = make_item_keywords(it); + let page = layout::Page { + css_class: tyname, + root_path: &self.root_path, + title: &title, + description: &desc, + keywords: &keywords, + }; - reset_ids(true); + reset_ids(true); - if !cx.render_redirect_pages { - layout::render(writer, &cx.shared.layout, &page, - &Sidebar{ cx: cx, item: it }, - &Item{ cx: cx, item: it }, - cx.shared.css_file_extension.is_some())?; - } else { - let mut url = repeat("../").take(cx.current.len()) - .collect::(); - if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { - for name in &names[..names.len() - 1] { - url.push_str(name); - url.push_str("/"); - } - url.push_str(&item_path(ty, names.last().unwrap())); - layout::redirect(writer, &url)?; + if !self.render_redirect_pages { + layout::render(writer, &self.shared.layout, &page, + &Sidebar{ cx: self, item: it }, + &Item{ cx: self, item: it }, + self.shared.css_file_extension.is_some())?; + } else { + let mut url = repeat("../").take(self.current.len()) + .collect::(); + if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { + for name in &names[..names.len() - 1] { + url.push_str(name); + url.push_str("/"); } + url.push_str(&item_path(ty, names.last().unwrap())); + layout::redirect(writer, &url)?; } - Ok(()) } + Ok(()) + } + /// Non-parallelized version of rendering an item. This will take the input + /// item, render its contents, and then invoke the specified closure with + /// all sub-items which need to be rendered. + /// + /// The rendering driver uses this closure to queue up more work. + fn item(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where + F: FnMut(&mut Context, clean::Item), + { // Stripped modules survive the rustdoc passes (i.e. `strip-private`) // if they contain impls for public types. These modules can also // contain items such as publicly reexported structures. @@ -1371,7 +1374,7 @@ impl Context { let item = item.take().unwrap(); let mut buf = Vec::new(); - render(&mut buf, this, &item, false).unwrap(); + this.render_item(&mut buf, &item, false).unwrap(); // buf will be empty if the module is stripped and there is no redirect for it if !buf.is_empty() { let joint_dst = this.dst.join("index.html"); @@ -1386,7 +1389,7 @@ impl Context { _ => unreachable!() }; - // render sidebar-items.js used throughout this module + // Render sidebar-items.js used throughout this module. if !this.render_redirect_pages { let items = this.build_sidebar_items(&m); let js_dst = this.dst.join("sidebar-items.js"); @@ -1398,23 +1401,22 @@ impl Context { for item in m.items { f(this,item); } + Ok(()) - }) + })?; } else if item.name.is_some() { let mut buf = Vec::new(); - render(&mut buf, self, &item, true).unwrap(); + self.render_item(&mut buf, &item, true).unwrap(); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { - let joint_dst = self.dst.join(&item_path(shortty(&item), + let joint_dst = self.dst.join(&item_path(item_type(&item), item.name.as_ref().unwrap())); try_err!(fs::create_dir_all(&self.dst), &self.dst); let mut dst = try_err!(File::create(&joint_dst), &joint_dst); try_err!(dst.write_all(&buf), &joint_dst); } - Ok(()) - } else { - Ok(()) } + Ok(()) } fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { @@ -1423,7 +1425,7 @@ impl Context { for item in &m.items { if self.maybe_ignore_item(item) { continue } - let short = shortty(item).to_static_str(); + let short = item_type(item).css_class(); let myname = match item.name { None => continue, Some(ref s) => s.to_string(), @@ -1531,7 +1533,7 @@ impl<'a> Item<'a> { } Some(format!("{path}{file}?gotosrc={goto}", path = path, - file = item_path(shortty(self.item), external_path.last().unwrap()), + file = item_path(item_type(self.item), external_path.last().unwrap()), goto = self.item.def_id.index.as_usize())) } } @@ -1566,7 +1568,7 @@ impl<'a> fmt::Display for Item<'a> { } } write!(fmt, "
{}", - shortty(self.item), self.item.name.as_ref().unwrap())?; + item_type(self.item), self.item.name.as_ref().unwrap())?; write!(fmt, "")?; // in-band write!(fmt, "")?; @@ -1622,7 +1624,7 @@ impl<'a> fmt::Display for Item<'a> { fn item_path(ty: ItemType, name: &str) -> String { match ty { ItemType::Module => format!("{}/index.html", name), - _ => format!("{}.{}.html", ty.to_static_str(), name), + _ => format!("{}.{}.html", ty.css_class(), name), } } @@ -1714,8 +1716,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering { - let ty1 = shortty(i1); - let ty2 = shortty(i2); + let ty1 = item_type(i1); + let ty2 = item_type(i2); if ty1 != ty2 { return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2)) } @@ -1739,7 +1741,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, continue; } - let myty = Some(shortty(myitem)); + let myty = Some(item_type(myitem)); if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) { // Put `extern crate` and `use` re-exports in the same section. curty = myty; @@ -1825,9 +1827,9 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, docs = shorter(Some(&Markdown(doc_value).to_string())), - class = shortty(myitem), + class = item_type(myitem), stab = myitem.stability_class(), - href = item_path(shortty(myitem), myitem.name.as_ref().unwrap()), + href = item_path(item_type(myitem), myitem.name.as_ref().unwrap()), title = full_path(cx, myitem))?; } } @@ -2022,7 +2024,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item) -> fmt::Result { let name = m.name.as_ref().unwrap(); - let id = derive_id(format!("{}.{}", shortty(m), name)); + let id = derive_id(format!("{}.{}", item_type(m), name)); write!(w, "

", id = id, stab = m.stability_class())?; @@ -2104,7 +2106,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, let (ref path, _) = cache.external_paths[&it.def_id]; path[..path.len() - 1].join("/") }, - ty = shortty(it).to_static_str(), + ty = item_type(it).css_class(), name = *it.name.as_ref().unwrap())?; Ok(()) } @@ -2113,7 +2115,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink) -> String { use html::item_type::ItemType::*; let name = it.name.as_ref().unwrap(); - let ty = match shortty(it) { + let ty = match item_type(it) { Typedef | AssociatedType => AssociatedType, s@_ => s, }; @@ -2191,7 +2193,7 @@ fn render_assoc_item(w: &mut fmt::Formatter, link: AssocItemLink) -> fmt::Result { let name = meth.name.as_ref().unwrap(); - let anchor = format!("#{}.{}", shortty(meth), name); + let anchor = format!("#{}.{}", item_type(meth), name); let href = match link { AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id), AssocItemLink::Anchor(None) => anchor, @@ -2268,9 +2270,9 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if fields.peek().is_some() { write!(w, "

Fields

")?; for (field, ty) in fields { - write!(w, "{name}: {ty} + write!(w, "{name}: {ty} ", - shortty = ItemType::StructField, + item_type = ItemType::StructField, stab = field.stability_class(), name = field.name.as_ref().unwrap(), ty = ty)?; @@ -2339,8 +2341,8 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if !e.variants.is_empty() { write!(w, "

Variants

\n")?; for variant in &e.variants { - write!(w, "{name}", - shortty = ItemType::Variant, + write!(w, "{name}", + item_type = ItemType::Variant, name = variant.name.as_ref().unwrap())?; if let clean::VariantItem(ref var) = variant.inner { if let clean::TupleVariant(ref tys) = var.kind { @@ -2588,7 +2590,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi link: AssocItemLink, render_static: bool, is_default_item: bool, outer_version: Option<&str>, trait_: Option<&clean::Trait>) -> fmt::Result { - let shortty = shortty(item); + let item_type = item_type(item); let name = item.name.as_ref().unwrap(); let is_static = match item.inner { @@ -2601,8 +2603,8 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi clean::MethodItem(..) | clean::TyMethodItem(..) => { // Only render when the method is not static or we allow static methods if !is_static || render_static { - let id = derive_id(format!("{}.{}", shortty, name)); - write!(w, "

", id, shortty)?; + let id = derive_id(format!("{}.{}", item_type, name)); + write!(w, "

", id, item_type)?; write!(w, "")?; render_assoc_item(w, item, link.anchor(&id))?; write!(w, "")?; @@ -2612,25 +2614,25 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } clean::TypedefItem(ref tydef, _) => { let id = derive_id(format!("{}.{}", ItemType::AssociatedType, name)); - write!(w, "

", id, shortty)?; + write!(w, "

", id, item_type)?; assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?; write!(w, "

\n")?; } clean::AssociatedConstItem(ref ty, ref default) => { - let id = derive_id(format!("{}.{}", shortty, name)); - write!(w, "

", id, shortty)?; + let id = derive_id(format!("{}.{}", item_type, name)); + write!(w, "

", id, item_type)?; assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?; write!(w, "

\n")?; } clean::ConstantItem(ref c) => { - let id = derive_id(format!("{}.{}", shortty, name)); - write!(w, "

", id, shortty)?; + let id = derive_id(format!("{}.{}", item_type, name)); + write!(w, "

", id, item_type)?; assoc_const(w, item, &c.type_, Some(&c.expr), link.anchor(&id))?; write!(w, "

\n")?; } clean::AssociatedTypeItem(ref bounds, ref default) => { - let id = derive_id(format!("{}.{}", shortty, name)); - write!(w, "

", id, shortty)?; + let id = derive_id(format!("{}.{}", item_type, name)); + write!(w, "

", id, item_type)?; assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?; write!(w, "

\n")?; } @@ -2749,7 +2751,7 @@ impl<'a> fmt::Display for Sidebar<'a> { relpath: '{path}'\ }};", name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), - ty = shortty(it).to_static_str(), + ty = item_type(it).css_class(), path = relpath)?; if parentlen == 0 { // there is no sidebar-items.js beyond the crate root path From a41454bf651a8629ec4b08365eae65b095504cab Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 3 Aug 2016 13:19:06 +1200 Subject: [PATCH 054/768] rustdoc: add namespaces for items --- src/librustdoc/html/item_type.rs | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index c3d38637ab70c..039f385d7c564 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -42,6 +42,14 @@ pub enum ItemType { AssociatedConst = 18, } + +#[derive(Copy, Eq, PartialEq, Clone)] +pub enum NameSpace { + Type, + Value, + Macro, +} + impl ItemType { pub fn from_item(item: &clean::Item) -> ItemType { let inner = match item.inner { @@ -113,6 +121,32 @@ impl ItemType { ItemType::AssociatedConst => "associatedconstant", } } + + pub fn name_space(&self) -> NameSpace { + match *self { + ItemType::Struct | + ItemType::Enum | + ItemType::Module | + ItemType::Typedef | + ItemType::Trait | + ItemType::Primitive | + ItemType::AssociatedType => NameSpace::Type, + + ItemType::ExternCrate | + ItemType::Import | + ItemType::Function | + ItemType::Static | + ItemType::Impl | + ItemType::TyMethod | + ItemType::Method | + ItemType::StructField | + ItemType::Variant | + ItemType::Constant | + ItemType::AssociatedConst => NameSpace::Value, + + ItemType::Macro => NameSpace::Macro, + } + } } impl fmt::Display for ItemType { @@ -120,3 +154,17 @@ impl fmt::Display for ItemType { self.css_class().fmt(f) } } + +pub const NAMESPACE_TYPE: &'static str = "t"; +pub const NAMESPACE_VALUE: &'static str = "v"; +pub const NAMESPACE_MACRO: &'static str = "m"; + +impl NameSpace { + pub fn to_static_str(&self) -> &'static str { + match *self { + NameSpace::Type => NAMESPACE_TYPE, + NameSpace::Value => NAMESPACE_VALUE, + NameSpace::Macro => NAMESPACE_MACRO, + } + } +} From 77ca7dd1073a945afcc451bee79f36cd40100996 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 3 Aug 2016 13:56:18 +1200 Subject: [PATCH 055/768] rustdoc: redirects from sane, namespaced URLs to Rustdoc's ridiculous ones cc #35020 which does this properly --- src/librustdoc/html/item_type.rs | 6 ++++ src/librustdoc/html/render.rs | 59 +++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 039f385d7c564..6b462a76f04ed 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -168,3 +168,9 @@ impl NameSpace { } } } + +impl fmt::Display for NameSpace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.to_static_str().fmt(f) + } +} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 963ea48d63420..51068d5648e4d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -41,7 +41,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::default::Default; use std::error; use std::fmt::{self, Display, Formatter}; -use std::fs::{self, File}; +use std::fs::{self, File, OpenOptions}; use std::io::prelude::*; use std::io::{self, BufWriter, BufReader}; use std::iter::repeat; @@ -1409,11 +1409,23 @@ impl Context { self.render_item(&mut buf, &item, true).unwrap(); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { - let joint_dst = self.dst.join(&item_path(item_type(&item), - item.name.as_ref().unwrap())); + let name = item.name.as_ref().unwrap(); + let item_type = item_type(&item); + let file_name = &item_path(item_type, name); + let joint_dst = self.dst.join(file_name); try_err!(fs::create_dir_all(&self.dst), &self.dst); let mut dst = try_err!(File::create(&joint_dst), &joint_dst); try_err!(dst.write_all(&buf), &joint_dst); + + // Redirect from a sane URL using the namespace to Rustdoc's + // URL for the page. + let redir_name = format!("{}.{}.html", name, item_type.name_space()); + let redir_dst = self.dst.join(redir_name); + if let Ok(mut redirect_out) = OpenOptions::new().create_new(true) + .write(true) + .open(&redir_dst) { + try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); + } } } Ok(()) @@ -2270,9 +2282,12 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if fields.peek().is_some() { write!(w, "

Fields

")?; for (field, ty) in fields { - write!(w, "{name}: {ty} - ", + write!(w, " + + {name}: {ty} + ", item_type = ItemType::StructField, + name_space = ItemType::StructField.name_space(), stab = field.stability_class(), name = field.name.as_ref().unwrap(), ty = ty)?; @@ -2341,8 +2356,10 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if !e.variants.is_empty() { write!(w, "

Variants

\n")?; for variant in &e.variants { - write!(w, "{name}", + write!(w, "\ + {name}", item_type = ItemType::Variant, + name_space = ItemType::Variant.name_space(), name = variant.name.as_ref().unwrap())?; if let clean::VariantItem(ref var) = variant.inner { if let clean::TupleVariant(ref tys) = var.kind { @@ -2356,7 +2373,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, ")")?; } } - write!(w, "")?; + write!(w, "")?; document(w, cx, variant)?; use clean::{Variant, StructVariant}; @@ -2368,9 +2385,12 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if let StructFieldItem(ref ty) = field.inner { write!(w, "\ - {f}: {t}", + \ + {f}: {t}", v = variant.name.as_ref().unwrap(), f = field.name.as_ref().unwrap(), + vns = ItemType::Variant.name_space(), + fns = ItemType::StructField.name_space(), t = *ty)?; document(w, cx, field)?; write!(w, "")?; @@ -2605,36 +2625,41 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi if !is_static || render_static { let id = derive_id(format!("{}.{}", item_type, name)); write!(w, "

", id, item_type)?; + write!(w, "", name, item_type.name_space())?; write!(w, "")?; render_assoc_item(w, item, link.anchor(&id))?; write!(w, "")?; render_stability_since_raw(w, item.stable_since(), outer_version)?; - write!(w, "

\n")?; + write!(w, "

\n")?; } } clean::TypedefItem(ref tydef, _) => { let id = derive_id(format!("{}.{}", ItemType::AssociatedType, name)); - write!(w, "

", id, item_type)?; + write!(w, "

", id, item_type)?; + write!(w, "", name, item_type.name_space())?; assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?; - write!(w, "

\n")?; + write!(w, "

\n")?; } clean::AssociatedConstItem(ref ty, ref default) => { let id = derive_id(format!("{}.{}", item_type, name)); - write!(w, "

", id, item_type)?; + write!(w, "

", id, item_type)?; + write!(w, "", name, item_type.name_space())?; assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?; - write!(w, "

\n")?; + write!(w, "

\n")?; } clean::ConstantItem(ref c) => { let id = derive_id(format!("{}.{}", item_type, name)); - write!(w, "

", id, item_type)?; + write!(w, "

", id, item_type)?; + write!(w, "", name, item_type.name_space())?; assoc_const(w, item, &c.type_, Some(&c.expr), link.anchor(&id))?; - write!(w, "

\n")?; + write!(w, "

\n")?; } clean::AssociatedTypeItem(ref bounds, ref default) => { let id = derive_id(format!("{}.{}", item_type, name)); - write!(w, "

", id, item_type)?; + write!(w, "

", id, item_type)?; + write!(w, "", name, item_type.name_space())?; assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?; - write!(w, "

\n")?; + write!(w, "

\n")?; } clean::StrippedItem(..) => return Ok(()), _ => panic!("can't make docs for trait item with name {:?}", item.name) From 4cfdf634c18421e607779ad83c7e7bda642cc349 Mon Sep 17 00:00:00 2001 From: Dustin Bensing Date: Wed, 17 Aug 2016 00:40:08 +0200 Subject: [PATCH 056/768] Update E0005 Unit-Test --- src/test/compile-fail/E0005.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/E0005.rs b/src/test/compile-fail/E0005.rs index 0405bba81b585..809b3af3bea2a 100644 --- a/src/test/compile-fail/E0005.rs +++ b/src/test/compile-fail/E0005.rs @@ -11,4 +11,5 @@ fn main() { let x = Some(1); let Some(y) = x; //~ ERROR E0005 + //~| NOTE pattern `None` not covered } From 7e148cd06292d125f925323fda6fabbc625a42c8 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Tue, 16 Aug 2016 20:45:07 -0400 Subject: [PATCH 057/768] Make `vec::IntoIter` covariant again Closes #35721 --- src/libcollections/vec.rs | 15 +++++++++------ src/libcollectionstest/vec.rs | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a6f817a89624c..3aefcc7d4cfa4 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1453,10 +1453,11 @@ impl IntoIterator for Vec { } else { begin.offset(self.len() as isize) as *const T }; - let buf = ptr::read(&self.buf); + let cap = self.buf.cap(); mem::forget(self); IntoIter { - _buf: buf, + buf: Shared::new(begin), + cap: cap, ptr: begin, end: end, } @@ -1708,8 +1709,9 @@ impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { /// [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - _buf: RawVec, - ptr: *mut T, + buf: Shared, + cap: usize, + ptr: *const T, end: *const T, } @@ -1750,7 +1752,7 @@ impl IntoIter { #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")] pub fn as_mut_slice(&self) -> &mut [T] { unsafe { - slice::from_raw_parts_mut(self.ptr, self.len()) + slice::from_raw_parts_mut(self.ptr as *mut T, self.len()) } } } @@ -1846,9 +1848,10 @@ impl Drop for IntoIter { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // destroy the remaining elements - for _x in self {} + for _x in self.by_ref() {} // RawVec handles deallocation + let _ = unsafe { RawVec::from_raw_parts(*self.buf, self.cap) }; } } diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 9556174bd2294..537fabf8ab69b 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -11,7 +11,7 @@ use std::borrow::Cow; use std::iter::{FromIterator, repeat}; use std::mem::size_of; -use std::vec::Drain; +use std::vec::{Drain, IntoIter}; use test::Bencher; @@ -537,6 +537,7 @@ fn test_cow_from() { #[allow(dead_code)] fn assert_covariance() { fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } + fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { i } } #[bench] From f0ff2d32c89c2bdec65f55c8a82eb92bd562d231 Mon Sep 17 00:00:00 2001 From: Chris Stankus Date: Tue, 16 Aug 2016 20:47:45 -0500 Subject: [PATCH 058/768] E0403 update error format --- src/librustc_resolve/lib.rs | 30 ++++++++++++++++++------------ src/test/compile-fail/E0403.rs | 2 ++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 962509be324de..8242bf97b11e0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -103,7 +103,7 @@ enum ResolutionError<'a> { /// error E0402: cannot use an outer type parameter in this context OuterTypeParameterContext, /// error E0403: the name is already used for a type parameter in this type parameter list - NameAlreadyUsedInTypeParameterList(Name), + NameAlreadyUsedInTypeParameterList(Name, &'a Span), /// error E0404: is not a trait IsNotATrait(&'a str), /// error E0405: use of undeclared trait name @@ -210,13 +210,17 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, E0402, "cannot use an outer type parameter in this context") } - ResolutionError::NameAlreadyUsedInTypeParameterList(name) => { - struct_span_err!(resolver.session, - span, - E0403, - "the name `{}` is already used for a type parameter in this type \ - parameter list", - name) + ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => { + let mut err = struct_span_err!(resolver.session, + span, + E0403, + "the name `{}` is already used for a type parameter \ + in this type parameter list", + name); + err.span_label(span, &format!("already used")); + err.span_label(first_use_span.clone(), &format!("first use of `{}`", name)); + err + } ResolutionError::IsNotATrait(name) => { let mut err = struct_span_err!(resolver.session, @@ -1731,17 +1735,19 @@ impl<'a> Resolver<'a> { match type_parameters { HasTypeParameters(generics, space, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); - let mut seen_bindings = HashSet::new(); + let mut seen_bindings = HashMap::new(); for (index, type_parameter) in generics.ty_params.iter().enumerate() { let name = type_parameter.ident.name; debug!("with_type_parameter_rib: {}", type_parameter.id); - if seen_bindings.contains(&name) { + if seen_bindings.contains_key(&name) { + let span = seen_bindings.get(&name).unwrap(); resolve_error(self, type_parameter.span, - ResolutionError::NameAlreadyUsedInTypeParameterList(name)); + ResolutionError::NameAlreadyUsedInTypeParameterList(name, + span)); } - seen_bindings.insert(name); + seen_bindings.entry(name).or_insert(type_parameter.span); // plain insert (no renaming) let def_id = self.definitions.local_def_id(type_parameter.id); diff --git a/src/test/compile-fail/E0403.rs b/src/test/compile-fail/E0403.rs index 6a68013dc6ffe..cd8532fc4c305 100644 --- a/src/test/compile-fail/E0403.rs +++ b/src/test/compile-fail/E0403.rs @@ -9,6 +9,8 @@ // except according to those terms. fn foo(s: T, u: T) {} //~ ERROR E0403 + //~| NOTE already used + //~| NOTE first use of `T` fn main() { } From 34f856e905e99606c5d358a74d792fe1afda2040 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 05:37:48 +0300 Subject: [PATCH 059/768] Update LLVM to include 4 backported commits by @majnemer. --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 786aad117be48..c3eb3c7608f43 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 786aad117be48547f4ca50fae84c4879fa992d4d +Subproject commit c3eb3c7608f439231d0c1340af6b720f113b4bf4 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 378810a8b89fc..59c6d53bfa3b9 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-08-07 +2016-08-17 From e314636b866a8b1b8a98e45ccac9a2204e72b65a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 13 Jun 2016 20:10:32 +0300 Subject: [PATCH 060/768] rustc: use Vec instead of VecPerParamSpace for ty::GenericPredicates. --- src/librustc/traits/object_safety.rs | 2 +- src/librustc/traits/project.rs | 2 +- src/librustc/traits/select.rs | 2 +- src/librustc/ty/mod.rs | 16 +++++----- src/librustc/ty/subst.rs | 20 ------------ src/librustc/util/ppaux.rs | 2 +- src/librustc_metadata/common.rs | 5 ++- src/librustc_metadata/decoder.rs | 18 +++-------- src/librustc_metadata/encoder.rs | 11 ++----- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/meth.rs | 2 +- src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/compare_method.rs | 31 +++++++++--------- src/librustc_typeck/check/dropck.rs | 10 ++---- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/collect.rs | 32 ++++++++----------- src/librustdoc/clean/inline.rs | 33 ++++++++++++++++--- src/librustdoc/clean/mod.rs | 29 ++++++++--------- src/librustdoc/clean/simplify.rs | 35 +++++++-------------- 19 files changed, 109 insertions(+), 148 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 4889895860129..8ddb14e08e31e 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -184,7 +184,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Search for a predicate like `Self : Sized` amongst the trait bounds. let free_substs = self.construct_free_substs(generics, self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = predicates.instantiate(self, &free_substs).predicates.into_vec(); + let predicates = predicates.instantiate(self, &free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { match predicate { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index aed4f43932411..d580deed0756a 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -811,7 +811,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( // If so, extract what we know from the trait and try to come up with a good answer. let trait_predicates = selcx.tcx().lookup_predicates(def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), substs); - let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec()); + let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index b61cb0d3eee72..6b9de746f66c3 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1214,7 +1214,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { bounds); let matching_bound = - util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec()) + util::elaborate_predicates(self.tcx(), bounds.predicates) .filter_to_traits() .find( |bound| self.probe( diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index cfc2e89f9d5a1..4f39a711010b7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -178,7 +178,7 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { impl_def_id: impl_def_id, self_ty: tcx.lookup_item_type(impl_def_id).ty, trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.lookup_predicates(impl_def_id).predicates.into_vec(), + predicates: tcx.lookup_predicates(impl_def_id).predicates }.subst(tcx, &impl_substs); let traits::Normalized { value: mut header, obligations } = @@ -775,13 +775,13 @@ impl<'tcx> Generics<'tcx> { /// Bounds on generics. #[derive(Clone)] pub struct GenericPredicates<'tcx> { - pub predicates: VecPerParamSpace>, + pub predicates: Vec>, } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { pub fn empty() -> GenericPredicates<'tcx> { GenericPredicates { - predicates: VecPerParamSpace::empty(), + predicates: vec![] } } @@ -797,9 +797,9 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { -> InstantiatedPredicates<'tcx> { InstantiatedPredicates { - predicates: self.predicates.map(|pred| { + predicates: self.predicates.iter().map(|pred| { pred.subst_supertrait(tcx, poly_trait_ref) - }) + }).collect() } } } @@ -1193,12 +1193,12 @@ impl<'tcx> Predicate<'tcx> { /// [usize:Bar]]`. #[derive(Clone)] pub struct InstantiatedPredicates<'tcx> { - pub predicates: VecPerParamSpace>, + pub predicates: Vec>, } impl<'tcx> InstantiatedPredicates<'tcx> { pub fn empty() -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { predicates: VecPerParamSpace::empty() } + InstantiatedPredicates { predicates: vec![] } } pub fn is_empty(&self) -> bool { @@ -2909,7 +2909,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let tcx = self.global_tcx(); let bounds = generic_predicates.instantiate(tcx, &free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); - let predicates = bounds.predicates.into_vec(); + let predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 595d965ffce26..25b108cee2755 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -217,14 +217,6 @@ pub struct VecPerParamSpace { content: Vec, } -/// The `split` function converts one `VecPerParamSpace` into this -/// `SeparateVecsPerParamSpace` structure. -pub struct SeparateVecsPerParamSpace { - pub types: Vec, - pub selfs: Vec, - pub fns: Vec, -} - impl fmt::Debug for VecPerParamSpace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{:?};{:?};{:?}]", @@ -428,18 +420,6 @@ impl VecPerParamSpace { self.self_limit) } - pub fn split(self) -> SeparateVecsPerParamSpace { - let VecPerParamSpace { type_limit, self_limit, content } = self; - - let mut content_iter = content.into_iter(); - - SeparateVecsPerParamSpace { - types: content_iter.by_ref().take(type_limit).collect(), - selfs: content_iter.by_ref().take(self_limit - type_limit).collect(), - fns: content_iter.collect() - } - } - pub fn with_slice(mut self, space: ParamSpace, slice: &[T]) -> VecPerParamSpace where T: Clone diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 896ef49de6f05..37750b568bba2 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -917,7 +917,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { let mut first = true; let mut is_sized = false; write!(f, "impl")?; - for predicate in bounds.predicates.into_vec() { + for predicate in bounds.predicates { if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { // Don't print +Sized, but rather +?Sized if absent. if Some(trait_ref.def_id()) == tcx.lang_items.sized_trait() { diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index ff072cce5db96..0011b59c70ed3 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -207,9 +207,8 @@ pub const tag_type_param_def: usize = 0x94; pub const tag_item_generics: usize = 0x95; pub const tag_method_ty_generics: usize = 0x96; -pub const tag_type_predicate: usize = 0x97; -pub const tag_self_predicate: usize = 0x98; -pub const tag_fn_predicate: usize = 0x99; +pub const tag_predicate: usize = 0x97; +// GAP 0x98, 0x99 pub const tag_unsafety: usize = 0x9a; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 64b614b56e12f..b91fb993f08ee 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1622,21 +1622,11 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, { let doc = reader::get_doc(base_doc, tag); - let mut predicates = subst::VecPerParamSpace::empty(); - for predicate_doc in reader::tagged_docs(doc, tag_type_predicate) { - predicates.push(subst::TypeSpace, - doc_predicate(cdata, predicate_doc, tcx)); - } - for predicate_doc in reader::tagged_docs(doc, tag_self_predicate) { - predicates.push(subst::SelfSpace, - doc_predicate(cdata, predicate_doc, tcx)); - } - for predicate_doc in reader::tagged_docs(doc, tag_fn_predicate) { - predicates.push(subst::FnSpace, - doc_predicate(cdata, predicate_doc, tcx)); + ty::GenericPredicates { + predicates: reader::tagged_docs(doc, tag_predicate).map(|predicate_doc| { + doc_predicate(cdata, predicate_doc, tcx) + }).collect() } - - ty::GenericPredicates { predicates: predicates } } pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index cc1d07b33c7e8..288fb74cc18a1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -26,7 +26,6 @@ use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; use rustc::dep_graph::{DepGraph, DepNode, DepTask}; -use rustc::ty::subst; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; @@ -541,14 +540,8 @@ fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, index: &mut CrateIndex<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - for (space, _, predicate) in predicates.predicates.iter_enumerated() { - let tag = match space { - subst::TypeSpace => tag_type_predicate, - subst::SelfSpace => tag_self_predicate, - subst::FnSpace => tag_fn_predicate - }; - - rbml_w.wr_tagged_u32(tag, + for predicate in &predicates.predicates { + rbml_w.wr_tagged_u32(tag_predicate, index.add_xref(XRef::Predicate(predicate.clone()))); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index acc302430aee6..ffacbae1afd6f 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1257,7 +1257,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(mth.is_provided); let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(tcx, predicates.into_vec()) { + if !normalize_and_test_predicates(tcx, predicates) { continue; } diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 3d6093d4d6960..169242fbf7270 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -289,7 +289,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // try and trans it, in that case. Issue #23435. if mth.is_provided { let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(tcx, predicates.into_vec()) { + if !normalize_and_test_predicates(tcx, predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ed67c9fbe30be..a0af98dec7298 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -56,7 +56,6 @@ use hir::print as pprust; use middle::resolve_lifetime as rl; use rustc::lint; use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; -use rustc::ty::subst::VecPerParamSpace; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -1778,7 +1777,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let predicates = bounds.predicates(tcx, ty); let predicates = tcx.lift_to_global(&predicates).unwrap(); tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates { - predicates: VecPerParamSpace::new(vec![], vec![], predicates) + predicates: predicates }); ty diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index e6ddc6ad69379..d501a8a184cee 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -13,7 +13,7 @@ use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, Reveal}; use rustc::ty::error::ExpectedFound; -use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace}; +use rustc::ty::subst::{self, Subst, Substs}; use rustc::hir::map::Node; use rustc::hir::{ImplItemKind, TraitItem_}; @@ -213,6 +213,15 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return; } + // Depend on trait/impl predicates always being before method's own predicates, + // to be able to split method predicates into "inherited" and method-specific. + let trait_predicates = tcx.lookup_predicates(trait_m.container_id()).predicates; + let impl_predicates = tcx.lookup_predicates(impl_m.container_id()).predicates; + let trait_method_start = trait_predicates.len(); + let impl_method_start = impl_predicates.len(); + assert_eq!(&trait_predicates[..], &trait_m.predicates.predicates[..trait_method_start]); + assert_eq!(&impl_predicates[..], &impl_m.predicates.predicates[..impl_method_start]); + tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| { let mut fulfillment_cx = traits::FulfillmentContext::new(); @@ -224,15 +233,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_bounds = - impl_m.predicates.instantiate(tcx, impl_to_skol_substs); + let impl_bounds = impl_m.predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", impl_bounds); - // Obtain the predicate split predicate sets for each. - let trait_pred = trait_bounds.predicates.split(); - let impl_pred = impl_bounds.predicates.split(); - // This is the only tricky bit of the new way we check implementation methods // We need to build a set of predicates where only the FnSpace bounds // are from the trait and we assume all other bounds from the implementation @@ -240,24 +244,21 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // // We then register the obligations from the impl_m and check to see // if all constraints hold. - let hybrid_preds = VecPerParamSpace::new( - impl_pred.types, - impl_pred.selfs, - trait_pred.fns - ); + let hybrid_preds = impl_bounds.predicates[..impl_method_start].iter() + .chain(trait_bounds.predicates[trait_method_start..].iter()); // Construct trait parameter environment and then shift it into the skolemized viewpoint. // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); - let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.into_vec()); + let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.cloned().collect()); let trait_param_env = traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone()); // FIXME(@jroesch) this seems ugly, but is a temporary change infcx.parameter_environment = trait_param_env; - debug!("compare_impl_method: trait_bounds={:?}", + debug!("compare_impl_method: caller_bounds={:?}", infcx.parameter_environment.caller_bounds); let mut selcx = traits::SelectionContext::new(&infcx); @@ -266,7 +267,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, infcx.replace_late_bound_regions_with_fresh_var( impl_m_span, infer::HigherRankedType, - &ty::Binder(impl_pred.fns)); + &ty::Binder(impl_bounds.predicates[impl_method_start..].to_vec())); for predicate in impl_pred_fns { let traits::Normalized { value: predicate, .. } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index f3a01ef7409fa..1e2446788adc9 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -179,10 +179,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( let generic_assumptions = tcx.lookup_predicates(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); - assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace)); - assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::FnSpace)); - let assumptions_in_impl_context = - assumptions_in_impl_context.predicates.get_slice(subst::TypeSpace); + let assumptions_in_impl_context = assumptions_in_impl_context.predicates; // An earlier version of this code attempted to do this checking // via the traits::fulfill machinery. However, it ran into trouble @@ -190,10 +187,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // 'a:'b and T:'b into region inference constraints. It is simpler // just to look for all the predicates directly. - assert!(dtor_predicates.predicates.is_empty_in(subst::SelfSpace)); - assert!(dtor_predicates.predicates.is_empty_in(subst::FnSpace)); - let predicates = dtor_predicates.predicates.get_slice(subst::TypeSpace); - for predicate in predicates { + for predicate in &dtor_predicates.predicates { // (We do not need to worry about deep analysis of type // expressions etc because the Drop impls are already forced // to take on a structure that is roughly an alpha-renaming of diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 99f1b13d4e4ab..e4701bb119559 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -799,7 +799,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let trait_predicates = self.tcx.lookup_predicates(def_id); let bounds = trait_predicates.instantiate(self.tcx, substs); - let predicates = bounds.predicates.into_vec(); + let predicates = bounds.predicates; debug!("assemble_projection_candidates: predicates={:?}", predicates); for poly_bound in diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d38065f4f1238..22da4ab9c43fa 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -65,7 +65,7 @@ use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; -use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; +use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; @@ -1185,9 +1185,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, // generic types: let trait_def = trait_def_of_item(ccx, item); let self_predicate = ty::GenericPredicates { - predicates: VecPerParamSpace::new(vec![], - vec![trait_def.trait_ref.to_predicate()], - vec![]) + predicates: vec![trait_def.trait_ref.to_predicate()] }; let scope = &(generics, &self_predicate); @@ -1209,7 +1207,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, // Combine the two lists to form the complete set of superbounds: let superbounds = superbounds1.into_iter().chain(superbounds2).collect(); let superpredicates = ty::GenericPredicates { - predicates: VecPerParamSpace::new(superbounds, vec![], vec![]) + predicates: superbounds }; debug!("superpredicates for trait {:?} = {:?}", tcx.map.local_def_id(item.id), @@ -1368,7 +1366,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. let self_predicate = trait_def.trait_ref.to_poly_trait_ref().to_predicate(); - base_predicates.predicates.push(SelfSpace, self_predicate); + base_predicates.predicates.push(self_predicate); // add in the explicit where-clauses let mut trait_predicates = @@ -1379,7 +1377,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) &trait_predicates, trait_def.trait_ref, items); - trait_predicates.predicates.extend(TypeSpace, assoc_predicates.into_iter()); + trait_predicates.predicates.extend(assoc_predicates); let prev_predicates = tcx.predicates.borrow_mut().insert(def_id, trait_predicates); assert!(prev_predicates.is_none()); @@ -1784,8 +1782,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, SizedByDefault::Yes, None, param.span); - let predicates = bounds.predicates(ccx.tcx, param_ty); - result.predicates.extend(space, predicates.into_iter()); + result.predicates.extend(bounds.predicates(ccx.tcx, param_ty)); } // Collect the region predicates that were declared inline as @@ -1803,7 +1800,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for bound in ¶m.bounds { let bound_region = ast_region_to_region(ccx.tcx, bound); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); - result.predicates.push(space, outlives.to_predicate()); + result.predicates.push(outlives.to_predicate()); } } @@ -1827,17 +1824,17 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, poly_trait_ref, &mut projections); - result.predicates.push(space, trait_ref.to_predicate()); + result.predicates.push(trait_ref.to_predicate()); for projection in &projections { - result.predicates.push(space, projection.to_predicate()); + result.predicates.push(projection.to_predicate()); } } &hir::TyParamBound::RegionTyParamBound(ref lifetime) => { let region = ast_region_to_region(tcx, lifetime); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); - result.predicates.push(space, ty::Predicate::TypeOutlives(pred)) + result.predicates.push(ty::Predicate::TypeOutlives(pred)) } } } @@ -1848,7 +1845,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for bound in ®ion_pred.bounds { let r2 = ast_region_to_region(tcx, bound); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); - result.predicates.push(space, ty::Predicate::RegionOutlives(pred)) + result.predicates.push(ty::Predicate::RegionOutlives(pred)) } } @@ -1861,7 +1858,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - return result; + result } fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, @@ -2221,9 +2218,6 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - assert!(impl_predicates.predicates.is_empty_in(FnSpace)); - assert!(impl_predicates.predicates.is_empty_in(SelfSpace)); - // The trait reference is an input, so find all type parameters // reachable from there, to start (if this is an inherent impl, // then just examine the self type). @@ -2233,7 +2227,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, input_parameters.extend(ctp::parameters_for(trait_ref, false)); } - ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace), + ctp::setup_constraining_predicates(&mut impl_predicates.predicates, impl_trait_ref, &mut input_parameters); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3d6925041cf5b..cea12404298fc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -395,8 +395,12 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, }; // Not sure the choice of ParamSpace actually matters here, // because an associated type won't have generics on the LHS - let typedef = (type_scheme, ty::GenericPredicates::empty(), - subst::ParamSpace::TypeSpace).clean(cx); + let typedef = clean::Typedef { + type_: type_scheme.ty.clean(cx), + generics: (&type_scheme.generics, + &ty::GenericPredicates::empty(), + subst::TypeSpace).clean(cx) + }; Some(clean::Item { name: Some(assoc_ty.name.clean(cx)), inner: clean::TypedefItem(typedef, true), @@ -512,11 +516,32 @@ fn build_static<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, /// its associated types as well. We specifically move these clauses to the /// associated types instead when displaying, so when we're genering the /// generics for the trait itself we need to be sure to remove them. +/// We also need to remove the implied "recursive" Self: Trait bound. /// /// The inverse of this filtering logic can be found in the `Clean` /// implementation for `AssociatedType` fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics { + for pred in &mut g.where_predicates { + match *pred { + clean::WherePredicate::BoundPredicate { + ty: clean::Generic(ref s), + ref mut bounds + } if *s == "Self" => { + bounds.retain(|bound| { + match *bound { + clean::TyParamBound::TraitBound(clean::PolyTrait { + trait_: clean::ResolvedPath { did, .. }, + .. + }, _) => did != trait_did, + _ => true + } + }); + } + _ => {} + } + } + g.where_predicates.retain(|pred| { match *pred { clean::WherePredicate::BoundPredicate { @@ -524,8 +549,8 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) self_type: box clean::Generic(ref s), trait_: box clean::ResolvedPath { did, .. }, name: ref _name, - }, .. - } => *s != "Self" || did != trait_did, + }, ref bounds + } => !(*s == "Self" && did == trait_did) && !bounds.is_empty(), _ => true, } }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 99d2732c4bb06..0da833d147ee5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1010,8 +1010,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, srp.clean(cx) }).collect::>(); - let mut where_predicates = preds.predicates.get_slice(space) - .to_vec().clean(cx); + let mut where_predicates = preds.predicates.to_vec().clean(cx); // Type parameters and have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with @@ -1363,7 +1362,17 @@ impl Clean for hir::ImplItem { impl<'tcx> Clean for ty::Method<'tcx> { fn clean(&self, cx: &DocContext) -> Item { - let generics = (&self.generics, &self.predicates, + // Depend on trait/impl predicates always being before method's own predicates, + // to be able to split method predicates into "inherited" and method-specific. + let outer_predicates = cx.tcx().lookup_predicates(self.container_id()).predicates; + let method_start = outer_predicates.len(); + assert_eq!(&outer_predicates[..], &self.predicates.predicates[..method_start]); + + let method_predicates = ty::GenericPredicates { + predicates: self.predicates.predicates[method_start..].to_vec() + }; + + let generics = (&self.generics, &method_predicates, subst::FnSpace).clean(cx); let mut decl = (self.def_id, &self.fty.sig).clean(cx); match self.explicit_self { @@ -1863,8 +1872,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { let item_predicates = cx.tcx().lookup_predicates(def_id); let substs = cx.tcx().lift(&substs).unwrap(); let bounds = item_predicates.instantiate(cx.tcx(), substs); - let predicates = bounds.predicates.into_vec(); - ImplTrait(predicates.into_iter().filter_map(|predicate| { + ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { predicate.to_opt_poly_trait_ref().clean(cx) }).collect()) } @@ -2967,17 +2975,6 @@ impl<'tcx> Clean for ty::AssociatedType<'tcx> { } } -impl<'a> Clean for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>, - ParamSpace) { - fn clean(&self, cx: &DocContext) -> Typedef { - let (ref ty_scheme, ref predicates, ps) = *self; - Typedef { - type_: ty_scheme.ty.clean(cx), - generics: (&ty_scheme.generics, predicates, ps).clean(cx) - } - } -} - fn lang_struct(cx: &DocContext, did: Option, t: ty::Ty, name: &str, fallback: fn(Box) -> Type) -> Type { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index c0faa04323e47..7ae177439064f 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -30,11 +30,11 @@ use std::mem; use std::collections::BTreeMap; use rustc::hir::def_id::DefId; -use rustc::ty::subst; +use rustc::ty; use clean::PathParameters as PP; use clean::WherePredicate as WP; -use clean::{self, Clean}; +use clean; use core::DocContext; pub fn where_clauses(cx: &DocContext, clauses: Vec) -> Vec { @@ -153,27 +153,16 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let def = cx.tcx().lookup_trait_def(child); - let predicates = cx.tcx().lookup_predicates(child); - let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); - generics.where_predicates.iter().filter_map(|pred| { - match *pred { - clean::WherePredicate::BoundPredicate { - ty: clean::Generic(ref s), - ref bounds - } if *s == "Self" => Some(bounds), - _ => None, - } - }).flat_map(|bounds| bounds).any(|bound| { - let poly_trait = match *bound { - clean::TraitBound(ref t, _) => t, - _ => return false, - }; - match poly_trait.trait_ { - clean::ResolvedPath { did, .. } => { - trait_is_same_or_supertrait(cx, did, trait_) + let predicates = cx.tcx().lookup_super_predicates(child).predicates; + predicates.iter().filter_map(|pred| { + if let ty::Predicate::Trait(ref pred) = *pred { + if pred.0.trait_ref.self_ty().is_self() { + Some(pred.def_id()) + } else { + None } - _ => false, + } else { + None } - }) + }).any(|did| trait_is_same_or_supertrait(cx, did, trait_)) } From b354ae95a29a7f78059a1a9fc867dd2e8639671a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 13 Jun 2016 20:13:37 +0300 Subject: [PATCH 061/768] rustc: move the SelfSpace before TypeSpace in Substs. --- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/select.rs | 5 +- src/librustc/ty/subst.rs | 75 +++++++++---------- src/librustc_trans/base.rs | 4 +- src/librustc_typeck/check/mod.rs | 2 +- .../trait-method-default-impl.rs | 10 +-- .../compile-fail/variance-associated-types.rs | 4 +- .../compile-fail/variance-object-types.rs | 2 +- .../compile-fail/variance-region-bounds.rs | 2 +- .../compile-fail/variance-regions-direct.rs | 14 ++-- .../compile-fail/variance-regions-indirect.rs | 10 +-- .../compile-fail/variance-trait-bounds.rs | 10 +-- .../variance-trait-object-bound.rs | 2 +- .../compile-fail/variance-types-bounds.rs | 10 +-- src/test/compile-fail/variance-types.rs | 12 +-- 15 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index cf004767b2aac..4c8489ff07159 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -182,7 +182,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let rps = self.region_vars_for_defs(obligation.cause.span, rps); let mut substs = subst::Substs::new( subst::VecPerParamSpace::empty(), - subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new())); + subst::VecPerParamSpace::new(Vec::new(), rps, Vec::new())); self.type_vars_for_defs(obligation.cause.span, TypeSpace, &mut substs, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6b9de746f66c3..9c7dd7ccd7011 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1602,7 +1602,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return; } }; - let target = obligation.predicate.0.input_types()[0]; + let target = obligation.predicate.skip_binder().input_types()[1]; debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); @@ -2476,7 +2476,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // regions here. See the comment there for more details. let source = self.infcx.shallow_resolve( tcx.no_late_bound_regions(&obligation.self_ty()).unwrap()); - let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); + let target = obligation.predicate.skip_binder().input_types()[1]; + let target = self.infcx.shallow_resolve(target); debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 25b108cee2755..0fe8d09664008 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -48,8 +48,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { r: Vec) -> Substs<'tcx> { - Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()), - VecPerParamSpace::new(r, Vec::new(), Vec::new())) + Substs::new(VecPerParamSpace::new(vec![], t, vec![]), + VecPerParamSpace::new(vec![], r, vec![])) } pub fn new_trait(t: Vec>, @@ -57,8 +57,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { s: Ty<'tcx>) -> Substs<'tcx> { - Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()), - VecPerParamSpace::new(r, Vec::new(), Vec::new())) + Substs::new(VecPerParamSpace::new(vec![s], t, vec![]), + VecPerParamSpace::new(vec![], r, vec![])) } pub fn empty() -> Substs<'tcx> { @@ -169,28 +169,28 @@ impl<'tcx> Decodable for &'tcx Substs<'tcx> { #[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum ParamSpace { - TypeSpace, // Type parameters attached to a type definition, trait, or impl SelfSpace, // Self parameter on a trait + TypeSpace, // Type parameters attached to a type definition, trait, or impl FnSpace, // Type parameters attached to a method or fn } impl ParamSpace { pub fn all() -> [ParamSpace; 3] { - [TypeSpace, SelfSpace, FnSpace] + [SelfSpace, TypeSpace, FnSpace] } pub fn to_uint(self) -> usize { match self { - TypeSpace => 0, - SelfSpace => 1, + SelfSpace => 0, + TypeSpace => 1, FnSpace => 2, } } pub fn from_uint(u: usize) -> ParamSpace { match u { - 0 => TypeSpace, - 1 => SelfSpace, + 0 => SelfSpace, + 1 => TypeSpace, 2 => FnSpace, _ => bug!("Invalid ParamSpace: {}", u) } @@ -209,19 +209,19 @@ pub struct VecPerParamSpace { // Here is how the representation corresponds to the abstraction // i.e. the "abstraction function" AF: // - // AF(self) = (self.content[..self.type_limit], - // self.content[self.type_limit..self.self_limit], - // self.content[self.self_limit..]) - type_limit: usize, + // AF(self) = (self.content[..self.self_limit], + // self.content[self.self_limit..self.type_limit], + // self.content[self.type_limit..]) self_limit: usize, + type_limit: usize, content: Vec, } impl fmt::Debug for VecPerParamSpace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{:?};{:?};{:?}]", - self.get_slice(TypeSpace), self.get_slice(SelfSpace), + self.get_slice(TypeSpace), self.get_slice(FnSpace)) } } @@ -229,44 +229,44 @@ impl fmt::Debug for VecPerParamSpace { impl VecPerParamSpace { fn limits(&self, space: ParamSpace) -> (usize, usize) { match space { - TypeSpace => (0, self.type_limit), - SelfSpace => (self.type_limit, self.self_limit), - FnSpace => (self.self_limit, self.content.len()), + SelfSpace => (0, self.self_limit), + TypeSpace => (self.self_limit, self.type_limit), + FnSpace => (self.type_limit, self.content.len()), } } pub fn empty() -> VecPerParamSpace { VecPerParamSpace { - type_limit: 0, self_limit: 0, + type_limit: 0, content: Vec::new() } } - /// `t` is the type space. /// `s` is the self space. + /// `t` is the type space. /// `f` is the fn space. - pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { - let type_limit = t.len(); - let self_limit = type_limit + s.len(); + pub fn new(s: Vec, t: Vec, f: Vec) -> VecPerParamSpace { + let self_limit = s.len(); + let type_limit = self_limit + t.len(); - let mut content = t; - content.extend(s); + let mut content = s; + content.extend(t); content.extend(f); VecPerParamSpace { - type_limit: type_limit, self_limit: self_limit, + type_limit: type_limit, content: content, } } - fn new_internal(content: Vec, type_limit: usize, self_limit: usize) + fn new_internal(content: Vec, self_limit: usize, type_limit: usize) -> VecPerParamSpace { VecPerParamSpace { - type_limit: type_limit, self_limit: self_limit, + type_limit: type_limit, content: content, } } @@ -278,8 +278,8 @@ impl VecPerParamSpace { pub fn push(&mut self, space: ParamSpace, value: T) { let (_, limit) = self.limits(space); match space { - TypeSpace => { self.type_limit += 1; self.self_limit += 1; } - SelfSpace => { self.self_limit += 1; } + SelfSpace => { self.type_limit += 1; self.self_limit += 1; } + TypeSpace => { self.type_limit += 1; } FnSpace => { } } self.content.insert(limit, value); @@ -302,8 +302,8 @@ impl VecPerParamSpace { None } else { match space { - TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; } - SelfSpace => { self.self_limit -= 1; } + SelfSpace => { self.type_limit -= 1; self.self_limit -= 1; } + TypeSpace => { self.type_limit -= 1; } FnSpace => {} } if self.content.is_empty() { @@ -388,8 +388,7 @@ impl VecPerParamSpace { pub fn all_vecs

(&self, mut pred: P) -> bool where P: FnMut(&[T]) -> bool, { - let spaces = [TypeSpace, SelfSpace, FnSpace]; - spaces.iter().all(|&space| { pred(self.get_slice(space)) }) + ParamSpace::all().iter().all(|&space| { pred(self.get_slice(space)) }) } pub fn all

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { @@ -407,8 +406,8 @@ impl VecPerParamSpace { pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { let result = self.iter().map(pred).collect(); VecPerParamSpace::new_internal(result, - self.type_limit, - self.self_limit) + self.self_limit, + self.type_limit) } pub fn map_enumerated(&self, pred: P) -> VecPerParamSpace where @@ -416,8 +415,8 @@ impl VecPerParamSpace { { let result = self.iter_enumerated().map(pred).collect(); VecPerParamSpace::new_internal(result, - self.type_limit, - self.self_limit) + self.self_limit, + self.type_limit) } pub fn with_slice(mut self, space: ParamSpace, slice: &[T]) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c78cda75e820e..3ea7f0d5eabb9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -675,8 +675,8 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> CustomCoerceUnsized { - let trait_substs = Substs::new(subst::VecPerParamSpace::new(vec![target_ty], - vec![source_ty], + let trait_substs = Substs::new(subst::VecPerParamSpace::new(vec![source_ty], + vec![target_ty], Vec::new()), subst::VecPerParamSpace::empty()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d985d3ccbea89..76b9052af6820 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2797,7 +2797,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let rps = self.region_vars_for_defs(span, rps); let mut substs = subst::Substs::new( VecPerParamSpace::empty(), - VecPerParamSpace::new(rps, Vec::new(), Vec::new())); + VecPerParamSpace::new(Vec::new(), rps, Vec::new())); self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty); diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs index 2b3b83cb7ec63..47892781902ea 100644 --- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs +++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs @@ -37,7 +37,7 @@ impl SomeGenericTrait for i32 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0] } // Non-generic impl of generic trait @@ -54,16 +54,16 @@ fn main() { //~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] let _ = 2i8.bar("&str"); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0i32.bar(0u64, 'c'); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0i32.bar(0u64, "&str"); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0u32.bar(0i8, &['c']); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0u32.bar(0i16, ()); } diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index 0ed0861d34af1..a3456b0628b35 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -20,12 +20,12 @@ trait Trait<'a> { } #[rustc_variance] -struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[+];[];[]], regions=[[-];[];[]]) +struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[];[+];[]], regions=[[];[-];[]]) field: (T, &'a ()) } #[rustc_variance] -struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[o];[];[]], regions=[[o];[];[]]) +struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[];[o];[]], regions=[[];[o];[]]) field: >::Type } diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index 2b7b05970d90f..ffd829c38d3d3 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -18,7 +18,7 @@ use std::cell::Cell; // For better or worse, associated types are invariant, and hence we // get an invariant result for `'a`. #[rustc_variance] -struct Foo<'a> { //~ ERROR regions=[[o];[];[]] +struct Foo<'a> { //~ ERROR regions=[[];[o];[]] x: Box &'a i32 + 'static> } diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs index dfa5dc1444151..6dd791f2558a7 100644 --- a/src/test/compile-fail/variance-region-bounds.rs +++ b/src/test/compile-fail/variance-region-bounds.rs @@ -13,7 +13,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -trait Foo: 'static { //~ ERROR types=[[];[o];[]] +trait Foo: 'static { //~ ERROR types=[[o];[];[]] } #[rustc_variance] diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index bb452eecbfc8b..0c712d3fa0377 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -16,7 +16,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]] +struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[];[-, -, -];[]] x: &'a isize, y: &'b [isize], c: &'c str @@ -25,7 +25,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] +struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[];[+, +, +];[]] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), c: extern "Rust" fn(&'c str), @@ -34,7 +34,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] +struct Test4<'a, 'b:'a> { //~ ERROR regions=[[];[-, o];[]] x: &'a mut &'b isize, } @@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[];[]] +struct Test5<'a, 'b:'a> { //~ ERROR regions=[[];[+, o];[]] x: extern "Rust" fn(&'a mut &'b isize), } @@ -52,14 +52,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[];[]] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] +struct Test6<'a, 'b:'a> { //~ ERROR regions=[[];[-, o];[]] x: &'a mut extern "Rust" fn(&'b isize), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR regions=[[*];[];[]] +struct Test7<'a> { //~ ERROR regions=[[];[*];[]] //~^ ERROR parameter `'a` is never used x: isize } @@ -67,7 +67,7 @@ struct Test7<'a> { //~ ERROR regions=[[*];[];[]] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[];[+, -, o];[]] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index 9beb90d0b2483..9bdb05e188dcf 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -15,7 +15,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[];[+, -, o, *];[]] //~^ ERROR parameter `'d` is never used Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), @@ -23,25 +23,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[];[*, o, -, +];[]] //~^ ERROR parameter `'w` is never used f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[];[o, o, *];[]] //~^ ERROR parameter `'c` is never used f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[];[o, -, *];[]] //~^ ERROR parameter `'c` is never used f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[];[+, -, o];[]] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index b6f197987bab1..528be50c0b850 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -25,18 +25,18 @@ trait Setter { //~ ERROR types=[[o];[o];[]] } #[rustc_variance] -struct TestStruct> { //~ ERROR types=[[+, +];[];[]] +struct TestStruct> { //~ ERROR types=[[];[+, +];[]] t: T, u: U } #[rustc_variance] -enum TestEnum> {//~ ERROR types=[[*, +];[];[]] +enum TestEnum> {//~ ERROR types=[[];[*, +];[]] //~^ ERROR parameter `U` is never used Foo(T) } #[rustc_variance] -trait TestTrait> { //~ ERROR types=[[o, o];[o];[]] +trait TestTrait> { //~ ERROR types=[[o];[o, o];[]] fn getter(&self, u: U) -> T; } @@ -50,13 +50,13 @@ trait TestTrait3 { //~ ERROR types=[[o];[o];[]] } #[rustc_variance] -struct TestContraStruct> { //~ ERROR types=[[*, +];[];[]] +struct TestContraStruct> { //~ ERROR types=[[];[*, +];[]] //~^ ERROR parameter `U` is never used t: T } #[rustc_variance] -struct TestBox+Setter> { //~ ERROR types=[[*, +];[];[]] +struct TestBox+Setter> { //~ ERROR types=[[];[*, +];[]] //~^ ERROR parameter `U` is never used t: T } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index f0ca1edd56387..b58540204986a 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -21,7 +21,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[[-];[];[]] +struct TOption<'a> { //~ ERROR regions=[[];[-];[]] v: Option>, } diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index a02f20656e7b5..d110c402d3b77 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -14,24 +14,24 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct TestImm { //~ ERROR types=[[+, +];[];[]] +struct TestImm { //~ ERROR types=[[];[+, +];[]] x: A, y: B, } #[rustc_variance] -struct TestMut { //~ ERROR types=[[+, o];[];[]] +struct TestMut { //~ ERROR types=[[];[+, o];[]] x: A, y: &'static mut B, } #[rustc_variance] -struct TestIndirect { //~ ERROR types=[[+, o];[];[]] +struct TestIndirect { //~ ERROR types=[[];[+, o];[]] m: TestMut } #[rustc_variance] -struct TestIndirect2 { //~ ERROR types=[[o, o];[];[]] +struct TestIndirect2 { //~ ERROR types=[[];[o, o];[]] n: TestMut, m: TestMut } @@ -68,7 +68,7 @@ trait SetterInTypeBound { //~ ERROR types=[[o];[o];[]] } #[rustc_variance] -struct TestObject { //~ ERROR types=[[o, o];[];[]] +struct TestObject { //~ ERROR types=[[];[o, o];[]] n: Box+Send>, m: Box+Send>, } diff --git a/src/test/compile-fail/variance-types.rs b/src/test/compile-fail/variance-types.rs index 2fd8bf20c7997..8c1a544334c2a 100644 --- a/src/test/compile-fail/variance-types.rs +++ b/src/test/compile-fail/variance-types.rs @@ -17,32 +17,32 @@ use std::cell::Cell; // not considered bivariant. #[rustc_variance] -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[[o, o];[];[]], regions=[[-];[];[]] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[[];[o, o];[]], regions=[[];[-];[]] t: &'a mut (A,B) } #[rustc_variance] -struct InvariantCell { //~ ERROR types=[[o];[];[]] +struct InvariantCell { //~ ERROR types=[[];[o];[]] t: Cell } #[rustc_variance] -struct InvariantIndirect { //~ ERROR types=[[o];[];[]] +struct InvariantIndirect { //~ ERROR types=[[];[o];[]] t: InvariantCell } #[rustc_variance] -struct Covariant { //~ ERROR types=[[+];[];[]] +struct Covariant { //~ ERROR types=[[];[+];[]] t: A, u: fn() -> A } #[rustc_variance] -struct Contravariant { //~ ERROR types=[[-];[];[]] +struct Contravariant { //~ ERROR types=[[];[-];[]] t: fn(A) } #[rustc_variance] -enum Enum { //~ ERROR types=[[+, -, o];[];[]] +enum Enum { //~ ERROR types=[[];[+, -, o];[]] Foo(Covariant), Bar(Contravariant), Zed(Covariant,Contravariant) From 77dc61b5c68aacce4ab5d115b14825699ea6302b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 13 Jun 2016 20:46:08 +0300 Subject: [PATCH 062/768] rustc: force all raw accesses to VecPerParamSpace through as_full_slice. --- src/librustc/traits/fulfill.rs | 2 +- src/librustc/ty/flags.rs | 4 +- src/librustc/ty/mod.rs | 13 ++++--- src/librustc/ty/structural_impls.rs | 2 +- src/librustc/ty/sty.rs | 8 ++-- src/librustc/ty/subst.rs | 43 +++------------------ src/librustc/ty/walk.rs | 10 ++--- src/librustc/ty/wf.rs | 2 +- src/librustc_metadata/encoder.rs | 4 +- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 4 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/trans_item.rs | 2 +- src/librustc_typeck/check/mod.rs | 5 ++- src/librustc_typeck/check/regionck.rs | 15 +++---- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 8 ++-- src/librustdoc/clean/mod.rs | 5 ++- 20 files changed, 52 insertions(+), 85 deletions(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 5ba7b914d6591..1ee1dc50b717d 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -142,7 +142,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { // Auto trait obligations on `impl Trait`. if tcx.trait_has_default_impl(predicate.def_id()) { let substs = predicate.skip_binder().trait_ref.substs; - if substs.types.as_slice().len() == 1 && substs.regions.is_empty() { + if substs.types.as_full_slice().len() == 1 && substs.regions.is_empty() { if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty { return true; } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 0997d6c1a7562..3a5f3d421eaf7 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -209,8 +209,8 @@ impl FlagComputation { } fn add_substs(&mut self, substs: &subst::Substs) { - self.add_tys(substs.types.as_slice()); - for &r in &substs.regions { + self.add_tys(substs.types.as_full_slice()); + for &r in substs.regions.as_full_slice() { self.add_region(r); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4f39a711010b7..708dcb30f1b84 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -971,7 +971,7 @@ impl<'tcx> TraitPredicate<'tcx> { } pub fn input_types(&self) -> &[Ty<'tcx>] { - self.trait_ref.substs.types.as_slice() + self.trait_ref.substs.types.as_full_slice() } pub fn self_ty(&self) -> Ty<'tcx> { @@ -1113,7 +1113,7 @@ impl<'tcx> Predicate<'tcx> { pub fn walk_tys(&self) -> IntoIter> { let vec: Vec<_> = match *self { ty::Predicate::Trait(ref data) => { - data.0.trait_ref.substs.types.as_slice().to_vec() + data.0.trait_ref.substs.types.as_full_slice().to_vec() } ty::Predicate::Rfc1592(ref data) => { return data.walk_tys() @@ -1128,7 +1128,8 @@ impl<'tcx> Predicate<'tcx> { vec![] } ty::Predicate::Projection(ref data) => { - let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice(); + let trait_inputs = data.0.projection_ty.trait_ref.substs + .types.as_full_slice(); trait_inputs.iter() .cloned() .chain(Some(data.0.ty)) @@ -1220,7 +1221,7 @@ impl<'tcx> TraitRef<'tcx> { // now this is all the types that appear in the // trait-reference, but it should eventually exclude // associated types. - self.substs.types.as_slice() + self.substs.types.as_full_slice() } } @@ -2864,7 +2865,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { free_id_outlive: CodeExtent) -> Substs<'gcx> { // map T => T let mut types = VecPerParamSpace::empty(); - for def in generics.types.as_slice() { + for def in generics.types.as_full_slice() { debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", def); types.push(def.space, self.global_tcx().mk_param_from_def(def)); @@ -2872,7 +2873,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // map bound 'a => free 'a let mut regions = VecPerParamSpace::empty(); - for def in generics.regions.as_slice() { + for def in generics.regions.as_full_slice() { let region = ReFree(FreeRegion { scope: free_id_outlive, bound_region: def.to_bound_region() }); diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 83413d16ffb3f..b0f8e2e13f7e0 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -433,7 +433,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|elem| elem.visit_with(visitor)) + self.as_full_slice().iter().any(|elem| elem.visit_with(visitor)) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 9680632ec4dcc..098943dfce29a 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1211,19 +1211,19 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyTrait(ref obj) => { let mut v = vec![obj.bounds.region_bound]; v.extend_from_slice(obj.principal.skip_binder() - .substs.regions.as_slice()); + .substs.regions.as_full_slice()); v } TyEnum(_, substs) | TyStruct(_, substs) | TyAnon(_, substs) => { - substs.regions.as_slice().to_vec() + substs.regions.as_full_slice().to_vec() } TyClosure(_, ref substs) => { - substs.func_substs.regions.as_slice().to_vec() + substs.func_substs.regions.as_full_slice().to_vec() } TyProjection(ref data) => { - data.trait_ref.substs.regions.as_slice().to_vec() + data.trait_ref.substs.regions.as_full_slice().to_vec() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0fe8d09664008..10e7f3ad0d17f 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -19,9 +19,6 @@ use ty::fold::{TypeFoldable, TypeFolder}; use serialize::{Encodable, Encoder, Decodable, Decoder}; use std::fmt; -use std::iter::IntoIterator; -use std::slice::Iter; -use std::vec::{Vec, IntoIter}; use syntax_pos::{Span, DUMMY_SP}; /////////////////////////////////////////////////////////////////////////// @@ -365,26 +362,14 @@ impl VecPerParamSpace { &self.get_slice(space)[index] } - pub fn iter<'a>(&'a self) -> Iter<'a,T> { - self.content.iter() - } - - pub fn into_iter(self) -> IntoIter { - self.content.into_iter() - } - pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> { EnumeratedItems::new(self) } - pub fn as_slice(&self) -> &[T] { + pub fn as_full_slice(&self) -> &[T] { &self.content } - pub fn into_vec(self) -> Vec { - self.content - } - pub fn all_vecs

(&self, mut pred: P) -> bool where P: FnMut(&[T]) -> bool, { @@ -392,11 +377,11 @@ impl VecPerParamSpace { } pub fn all

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { - self.iter().all(pred) + self.as_full_slice().iter().all(pred) } pub fn any

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { - self.iter().any(pred) + self.as_full_slice().iter().any(pred) } pub fn is_empty(&self) -> bool { @@ -404,7 +389,7 @@ impl VecPerParamSpace { } pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { - let result = self.iter().map(pred).collect(); + let result = self.as_full_slice().iter().map(pred).collect(); VecPerParamSpace::new_internal(result, self.self_limit, self.type_limit) @@ -478,29 +463,11 @@ impl<'a,T> Iterator for EnumeratedItems<'a,T> { } fn size_hint(&self) -> (usize, Option) { - let size = self.vec.as_slice().len(); + let size = self.vec.as_full_slice().len(); (size, Some(size)) } } -impl IntoIterator for VecPerParamSpace { - type Item = T; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - self.into_vec().into_iter() - } -} - -impl<'a,T> IntoIterator for &'a VecPerParamSpace { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.as_slice().into_iter() - } -} - /////////////////////////////////////////////////////////////////////////// // Public trait `Subst` diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 9c1f9d9537a4f..3f87d80e337dd 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -79,10 +79,10 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.push(mt.ty); } ty::TyProjection(ref data) => { - push_reversed(stack, data.trait_ref.substs.types.as_slice()); + push_reversed(stack, data.trait_ref.substs.types.as_full_slice()); } ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { - push_reversed(stack, principal.substs().types.as_slice()); + push_reversed(stack, principal.substs().types.as_full_slice()); push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { pred.0.ty }).collect::>()); @@ -90,17 +90,17 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | ty::TyAnon(_, ref substs) => { - push_reversed(stack, substs.types.as_slice()); + push_reversed(stack, substs.types.as_full_slice()); } ty::TyClosure(_, ref substs) => { - push_reversed(stack, substs.func_substs.types.as_slice()); + push_reversed(stack, substs.func_substs.types.as_full_slice()); push_reversed(stack, &substs.upvar_tys); } ty::TyTuple(ref ts) => { push_reversed(stack, ts); } ty::TyFnDef(_, substs, ref ft) => { - push_reversed(stack, substs.types.as_slice()); + push_reversed(stack, substs.types.as_full_slice()); push_sig_subtypes(stack, &ft.sig); } ty::TyFnPtr(ref ft) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index bfc2e11d9fbce..009e3e2433431 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -261,7 +261,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); self.out.extend( trait_ref.substs.types - .as_slice() + .as_full_slice() .iter() .filter(|ty| !ty.has_escaping_regions()) .map(|ty| traits::Obligation::new(cause.clone(), diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 288fb74cc18a1..d19eb6391820a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -515,7 +515,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, { rbml_w.start_tag(tag); - for param in &generics.types { + for param in generics.types.as_full_slice() { rbml_w.start_tag(tag_type_param_def); tyencode::enc_type_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param); rbml_w.mark_stable_position(); @@ -523,7 +523,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, } // Region parameters - for param in &generics.regions { + for param in generics.regions.as_full_slice() { rbml_w.start_tag(tag_region_param_def); tyencode::enc_region_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param); rbml_w.mark_stable_position(); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 5e2c0805c2ea3..bb27a308f71f7 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -252,7 +252,7 @@ impl<'a, 'tcx> Instance<'tcx> { // and should not matter anyhow. let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_slice()); + let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_full_slice()); let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index d6a4ce3c43a4e..1aae3b3127faa 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -358,7 +358,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, name_to_append_suffix_to: &mut String) -> DIArray { - let actual_types = param_substs.types.as_slice(); + let actual_types = param_substs.types.as_full_slice(); if actual_types.is_empty() { return create_DIArray(DIB(cx), &[]); @@ -381,7 +381,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { - generics.types.as_slice().iter().enumerate().map(|(i, param)| { + generics.types.as_full_slice().iter().enumerate().map(|(i, param)| { let actual_type = cx.tcx().normalize_associated_type(&actual_types[i]); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); let name = CString::new(param.name.as_str().as_bytes()).unwrap(); diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 73b1c828663e1..4bca091ef95ac 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -181,7 +181,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push('<'); - for &type_parameter in &substs.types { + for &type_parameter in substs.types.as_full_slice() { push_debuginfo_type_name(cx, type_parameter, true, output); output.push_str(", "); } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index e9aacaa0f954f..663c5167d1492 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -181,7 +181,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { impl<'tcx> Instance<'tcx> { pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> Instance<'tcx> { - assert!(substs.regions.iter().all(|&r| r == ty::ReErased)); + assert!(substs.regions.as_full_slice().iter().all(|&r| r == ty::ReErased)); Instance { def: def_id, substs: substs } } pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 90058f0b8329a..c1149279b4ddd 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -570,7 +570,7 @@ fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push('<'); - for &type_parameter in types { + for &type_parameter in types.as_full_slice() { push_unique_type_name(tcx, type_parameter, output); output.push_str(", "); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 76b9052af6820..b82ce2f5bc4e0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -888,7 +888,8 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // `{Self}` is allowed Position::ArgumentNamed(s) if s == "Self" => (), // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => match types.iter().find(|t| { + Position::ArgumentNamed(s) => match types.as_full_slice() + .iter().find(|t| { t.name.as_str() == s }) { Some(_) => (), @@ -1895,7 +1896,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Registers obligations that all types appearing in `substs` are well-formed. pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr) { - for &ty in &substs.types { + for &ty in substs.types.as_full_slice() { self.register_wf_obligation(ty, expr.span, traits::MiscObligation); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 22ffcfbaae111..6f3d48282e25c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1445,11 +1445,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for ®ion in &substs.regions { + for ®ion in substs.regions.as_full_slice() { self.sub_regions(origin.clone(), expr_region, region); } - for &ty in &substs.types { + for &ty in substs.types.as_full_slice() { let ty = self.resolve_type(ty); self.type_must_outlive(origin.clone(), ty, expr_region); } @@ -1571,18 +1571,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let needs_infer = { - projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) || - projection_ty.trait_ref.substs.regions.iter().any(|r| r.needs_infer()) - }; + let needs_infer = projection_ty.trait_ref.needs_infer(); if env_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); - for &component_ty in &projection_ty.trait_ref.substs.types { + for &component_ty in projection_ty.trait_ref.substs.types.as_full_slice() { self.type_must_outlive(origin.clone(), component_ty, region); } - for &r in &projection_ty.trait_ref.substs.regions { + for &r in projection_ty.trait_ref.substs.regions.as_full_slice() { self.sub_regions(origin.clone(), region, r); } @@ -1600,7 +1597,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { let unique_bound = env_bounds[0]; debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); - if projection_ty.trait_ref.substs.regions + if projection_ty.trait_ref.substs.regions.as_full_slice() .iter() .any(|r| env_bounds.contains(r)) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4bb9f4fd332f2..678c102a4de3b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -621,7 +621,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait impl: take implied bounds from all types that // appear in the trait reference. let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); - trait_ref.substs.types.as_slice().to_vec() + trait_ref.substs.types.as_full_slice().to_vec() } None => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 22da4ab9c43fa..69545aefb4446 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1550,7 +1550,7 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Debugging aid. if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") { let object_lifetime_default_reprs: String = - scheme.generics.types.iter() + scheme.generics.types.as_full_slice().iter() .map(|t| match t.object_lifetime_default { ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), d => format!("{:?}", d), diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index a4faee8f633ed..1e342d4b81971 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -302,8 +302,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, trait_ref.def_id, - trait_def.generics.types.as_slice(), - trait_def.generics.regions.as_slice(), + trait_def.generics.types.as_full_slice(), + trait_def.generics.regions.as_full_slice(), trait_ref.substs, variance); } @@ -388,8 +388,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, trait_ref.def_id, - trait_def.generics.types.as_slice(), - trait_def.generics.regions.as_slice(), + trait_def.generics.types.as_full_slice(), + trait_def.generics.regions.as_full_slice(), trait_ref.substs, variance); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0da833d147ee5..284e0d4dbddf3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -788,8 +788,9 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { impl<'tcx> Clean>> for subst::Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { let mut v = Vec::new(); - v.extend(self.regions.iter().filter_map(|r| r.clean(cx)).map(RegionBound)); - v.extend(self.types.iter().map(|t| TraitBound(PolyTrait { + v.extend(self.regions.as_full_slice().iter().filter_map(|r| r.clean(cx)) + .map(RegionBound)); + v.extend(self.types.as_full_slice().iter().map(|t| TraitBound(PolyTrait { trait_: t.clean(cx), lifetimes: vec![] }, hir::TraitBoundModifier::None))); From c87063f07e8f74c1950f3fd099fb578a833682c5 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 15 Jun 2016 01:40:09 +0300 Subject: [PATCH 063/768] rustc: avoid using subst::VecPerParamSpace::{empty,new} directly. --- src/librustc/traits/error_reporting.rs | 4 +--- src/librustc/ty/mod.rs | 23 +++++++++++++++-------- src/librustc/ty/subst.rs | 8 ++++++++ src/librustc_metadata/decoder.rs | 10 ++++------ src/librustc_mir/build/scope.rs | 7 ++----- src/librustc_trans/base.rs | 7 ++----- src/librustc_typeck/check/mod.rs | 4 +--- src/librustc_typeck/variance/solve.rs | 12 +++--------- src/librustc_typeck/variance/terms.rs | 7 ++----- 9 files changed, 38 insertions(+), 44 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 4c8489ff07159..b5133738ada8c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -180,9 +180,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ity.ty); let rps = self.region_vars_for_defs(obligation.cause.span, rps); - let mut substs = subst::Substs::new( - subst::VecPerParamSpace::empty(), - subst::VecPerParamSpace::new(Vec::new(), rps, Vec::new())); + let mut substs = subst::Substs::new_type(vec![], rps); self.type_vars_for_defs(obligation.cause.span, TypeSpace, &mut substs, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 708dcb30f1b84..44532fcb4e64f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -429,6 +429,15 @@ pub struct ItemVariances { pub regions: VecPerParamSpace, } +impl ItemVariances { + pub fn empty() -> ItemVariances { + ItemVariances { + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty(), + } + } +} + #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -2864,22 +2873,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn construct_free_substs(self, generics: &Generics<'gcx>, free_id_outlive: CodeExtent) -> Substs<'gcx> { // map T => T - let mut types = VecPerParamSpace::empty(); - for def in generics.types.as_full_slice() { + let types = generics.types.map(|def| { debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", def); - types.push(def.space, self.global_tcx().mk_param_from_def(def)); - } + self.global_tcx().mk_param_from_def(def) + }); // map bound 'a => free 'a - let mut regions = VecPerParamSpace::empty(); - for def in generics.regions.as_full_slice() { + let regions = generics.regions.map(|def| { let region = ReFree(FreeRegion { scope: free_id_outlive, bound_region: def.to_bound_region() }); debug!("push_region_params {:?}", region); - regions.push(def.space, region); - } + region + }); Substs { types: types, diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 10e7f3ad0d17f..63399ee138893 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -41,6 +41,14 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { Substs { types: t, regions: r } } + pub fn new_fn(t: Vec>, + r: Vec) + -> Substs<'tcx> + { + Substs::new(VecPerParamSpace::new(vec![], vec![], t), + VecPerParamSpace::new(vec![], vec![], r)) + } + pub fn new_type(t: Vec>, r: Vec) -> Substs<'tcx> diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b91fb993f08ee..eeb1859c01311 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -35,7 +35,6 @@ use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; use middle::lang_items; -use rustc::ty::subst; use rustc::ty::{ImplContainer, TraitContainer}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; @@ -1580,25 +1579,24 @@ fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, { let doc = reader::get_doc(base_doc, tag); - let mut types = subst::VecPerParamSpace::empty(); + let mut generics = ty::Generics::empty(); for p in reader::tagged_docs(doc, tag_type_param_def) { let bd = TyDecoder::with_doc(tcx, cdata.cnum, p, &mut |did| translate_def_id(cdata, did)) .parse_type_param_def(); - types.push(bd.space, bd); + generics.types.push(bd.space, bd); } - let mut regions = subst::VecPerParamSpace::empty(); for p in reader::tagged_docs(doc, tag_region_param_def) { let bd = TyDecoder::with_doc(tcx, cdata.cnum, p, &mut |did| translate_def_id(cdata, did)) .parse_region_param_def(); - regions.push(bd.space, bd); + generics.regions.push(bd.space, bd); } - ty::Generics { types: types, regions: regions } + generics } fn doc_predicate<'a, 'tcx>(cdata: Cmd, diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index cae9e8379897c..6af9ad02b91ba 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -89,7 +89,7 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; -use rustc::ty::subst::{Substs, Subst, VecPerParamSpace}; +use rustc::ty::subst::{Substs, Subst}; use rustc::ty::{Ty, TyCtxt}; use rustc::mir::repr::*; use syntax_pos::Span; @@ -750,10 +750,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> TerminatorKind<'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = tcx.mk_substs(Substs::new( - VecPerParamSpace::new(vec![], vec![], vec![data.item_ty]), - VecPerParamSpace::new(vec![], vec![], vec![]) - )); + let substs = tcx.mk_substs(Substs::new_fn(vec![data.item_ty], vec![])); TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3ea7f0d5eabb9..0dcac188bb024 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -39,7 +39,7 @@ use rustc::cfg; use rustc::hir::def_id::DefId; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::hir::pat_util::simple_name; -use rustc::ty::subst::{self, Substs}; +use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::adjustment::CustomCoerceUnsized; @@ -675,10 +675,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> CustomCoerceUnsized { - let trait_substs = Substs::new(subst::VecPerParamSpace::new(vec![source_ty], - vec![target_ty], - Vec::new()), - subst::VecPerParamSpace::empty()); + let trait_substs = Substs::new_trait(vec![target_ty], vec![], source_ty); let trait_ref = ty::Binder(ty::TraitRef { def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b82ce2f5bc4e0..fae64f3741974 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2796,9 +2796,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); let rps = self.region_vars_for_defs(span, rps); - let mut substs = subst::Substs::new( - VecPerParamSpace::empty(), - VecPerParamSpace::new(Vec::new(), rps, Vec::new())); + let mut substs = subst::Substs::new_type(vec![], rps); self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty); diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 0763cfd7e2e60..8bb49410a5bdc 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -15,7 +15,6 @@ //! optimal solution to the constraints. The final variance for each //! inferred is then written into the `variance_map` in the tcx. -use rustc::ty::subst::VecPerParamSpace; use rustc::ty; use std::rc::Rc; @@ -109,8 +108,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { let num_inferred = self.terms_cx.num_inferred(); while index < num_inferred { let item_id = inferred_infos[index].item_id; - let mut types = VecPerParamSpace::empty(); - let mut regions = VecPerParamSpace::empty(); + let mut item_variances = ty::ItemVariances::empty(); while index < num_inferred && inferred_infos[index].item_id == item_id { let info = &inferred_infos[index]; @@ -118,17 +116,13 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { debug!("Index {} Info {} / {:?} / {:?} Variance {:?}", index, info.index, info.kind, info.space, variance); match info.kind { - TypeParam => { types.push(info.space, variance); } - RegionParam => { regions.push(info.space, variance); } + TypeParam => { item_variances.types.push(info.space, variance); } + RegionParam => { item_variances.regions.push(info.space, variance); } } index += 1; } - let item_variances = ty::ItemVariances { - types: types, - regions: regions - }; debug!("item_id={} item_variances={:?}", item_id, item_variances); diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index d9e7e8cbf7df4..72f8d9cb23ba8 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -21,7 +21,7 @@ use arena::TypedArena; use dep_graph::DepTrackingMapConfig; -use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace}; +use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace}; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::ItemVariances; use std::fmt; @@ -112,10 +112,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( // cache and share the variance struct used for items with // no type/region parameters - empty_variances: Rc::new(ty::ItemVariances { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty() - }) + empty_variances: Rc::new(ty::ItemVariances::empty()) }; // See README.md for a discussion on dep-graph management. From 5ef6af09e3b9df3dd01f0e4d53176b0a72ce5722 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 03:56:18 +0300 Subject: [PATCH 064/768] rustc: move defaulting's use of &mut Substs from InferCtxt to typeck. --- src/librustc/infer/mod.rs | 122 ++++++++++---------- src/librustc/traits/error_reporting.rs | 28 +---- src/librustc/traits/util.rs | 3 +- src/librustc/ty/subst.rs | 31 +++++ src/librustc_typeck/astconv.rs | 47 ++++---- src/librustc_typeck/check/method/confirm.rs | 84 ++++++-------- src/librustc_typeck/check/method/mod.rs | 33 +++--- src/librustc_typeck/check/method/probe.rs | 35 +++--- src/librustc_typeck/check/mod.rs | 50 +++----- src/librustc_typeck/collect.rs | 6 +- src/librustc_typeck/lib.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 4 +- 12 files changed, 213 insertions(+), 232 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 24fadc549fafc..79eea7314cdf3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1172,15 +1172,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(false)) } - pub fn next_ty_var_with_default(&self, - default: Option>) -> Ty<'tcx> { - let ty_var_id = self.type_variables - .borrow_mut() - .new_var(false, default); - - self.tcx.mk_var(ty_var_id) - } - pub fn next_diverging_ty_var(&self) -> Ty<'tcx> { self.tcx.mk_var(self.next_ty_var_id(true)) } @@ -1205,35 +1196,49 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::ReVar(self.region_vars.new_region_var(origin)) } + /// Create a region inference variable for the given + /// region parameter definition. + pub fn region_var_for_def(&self, + span: Span, + def: &ty::RegionParameterDef) + -> ty::Region { + self.next_region_var(EarlyBoundRegion(span, def.name)) + } + + /// Create a type inference variable for the given + /// type parameter definition. The substitutions are + /// for actual parameters that may be referred to by + /// the default of this type parameter, if it exists. + /// E.g. `struct Foo(...);` when + /// used in a path such as `Foo::::new()` will + /// use an inference variable for `C` with `[T, U]` + /// as the substitutions for the default, `(T, U)`. + pub fn type_var_for_def(&self, + span: Span, + def: &ty::TypeParameterDef<'tcx>, + substs: &Substs<'tcx>) + -> Ty<'tcx> { + let default = def.default.map(|default| { + type_variable::Default { + ty: default.subst_spanned(self.tcx, substs, Some(span)), + origin_span: span, + def_id: def.default_def_id + } + }); + + + let ty_var_id = self.type_variables + .borrow_mut() + .new_var(false, default); + + self.tcx.mk_var(ty_var_id) + } + pub fn region_vars_for_defs(&self, span: Span, defs: &[ty::RegionParameterDef]) -> Vec { - defs.iter() - .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name))) - .collect() - } - - // We have to take `&mut Substs` in order to provide the correct substitutions for defaults - // along the way, for this reason we don't return them. - pub fn type_vars_for_defs(&self, - span: Span, - space: subst::ParamSpace, - substs: &mut Substs<'tcx>, - defs: &[ty::TypeParameterDef<'tcx>]) { - - for def in defs.iter() { - let default = def.default.map(|default| { - type_variable::Default { - ty: default.subst_spanned(self.tcx, substs, Some(span)), - origin_span: span, - def_id: def.default_def_id - } - }); - - let ty_var = self.next_ty_var_with_default(default); - substs.types.push(space, ty_var); - } + defs.iter().map(|def| self.region_var_for_def(span, def)).collect() } /// Given a set of generics defined on a type or impl, returns a substitution mapping each @@ -1243,21 +1248,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { generics: &ty::Generics<'tcx>) -> &'tcx subst::Substs<'tcx> { - let type_params = subst::VecPerParamSpace::empty(); - - let region_params = - generics.regions.map( - |d| self.next_region_var(EarlyBoundRegion(span, d.name))); - - let mut substs = subst::Substs::new(type_params, region_params); - - for space in subst::ParamSpace::all().iter() { - self.type_vars_for_defs( - span, - *space, - &mut substs, - generics.types.get_slice(*space)); - } + let type_defs = generics.types.as_full_slice(); + let region_defs = generics.regions.as_full_slice(); + let substs = Substs::from_param_defs(region_defs, type_defs, |def| { + self.region_var_for_def(span, def) + }, |def, substs| { + self.type_var_for_def(span, def, substs) + }); self.tcx.mk_substs(substs) } @@ -1269,25 +1266,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, generics: &ty::Generics<'tcx>, self_ty: Ty<'tcx>) - -> subst::Substs<'tcx> + -> &'tcx subst::Substs<'tcx> { - assert!(generics.types.len(subst::SelfSpace) == 1); assert!(generics.types.len(subst::FnSpace) == 0); - assert!(generics.regions.len(subst::SelfSpace) == 0); - assert!(generics.regions.len(subst::FnSpace) == 0); - - let type_params = Vec::new(); - - let region_param_defs = generics.regions.get_slice(subst::TypeSpace); - let regions = self.region_vars_for_defs(span, region_param_defs); - let mut substs = subst::Substs::new_trait(type_params, regions, self_ty); - - let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); - self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs); + let type_defs = generics.types.as_full_slice(); + let region_defs = generics.regions.as_full_slice(); + let substs = Substs::from_param_defs(region_defs, type_defs, |def| { + self.region_var_for_def(span, def) + }, |def, substs| { + if def.space == subst::SelfSpace { + self_ty + } else { + self.type_var_for_def(span, def, substs) + } + }); - return substs; + self.tcx.mk_substs(substs) } pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b5133738ada8c..5d50eac1716a3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -31,7 +31,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; -use ty::subst::{self, Subst, TypeSpace}; +use ty::subst::{Subst, TypeSpace}; use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; @@ -167,27 +167,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }); } - fn impl_substs(&self, - did: DefId, - obligation: PredicateObligation<'tcx>) - -> subst::Substs<'tcx> { - let tcx = self.tcx; - - let ity = tcx.lookup_item_type(did); - let (tps, rps, _) = - (ity.generics.types.get_slice(TypeSpace), - ity.generics.regions.get_slice(TypeSpace), - ity.ty); - - let rps = self.region_vars_for_defs(obligation.cause.span, rps); - let mut substs = subst::Substs::new_type(vec![], rps); - self.type_vars_for_defs(obligation.cause.span, - TypeSpace, - &mut substs, - tps); - substs - } - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// returns the fuzzy category of a given type, or None /// if the type can be equated to any type. @@ -242,10 +221,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lookup_trait_def(trait_ref.def_id) .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| { + let ity = tcx.lookup_item_type(def_id); + let impl_substs = self.fresh_substs_for_generics(obligation.cause.span, + &ity.generics); let impl_trait_ref = tcx .impl_trait_ref(def_id) .unwrap() - .subst(tcx, &self.impl_substs(def_id, obligation.clone())); + .subst(tcx, impl_substs); let impl_self_ty = impl_trait_ref.self_ty(); diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 818eb4eb2fb1e..80a3ad9122bd1 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -358,8 +358,7 @@ pub fn fresh_type_vars_for_impl<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx impl_def_id: DefId) -> &'tcx Substs<'tcx> { - let tcx = infcx.tcx; - let impl_generics = tcx.lookup_item_type(impl_def_id).generics; + let impl_generics = infcx.tcx.lookup_item_type(impl_def_id).generics; infcx.fresh_substs_for_generics(span, &impl_generics) } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 63399ee138893..34e7899e2fddb 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -73,6 +73,33 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } } + /// Creates a Substs for generic parameter definitions, + /// by calling closures to obtain each region and type. + /// The closures get to observe the Substs as they're + /// being built, which can be used to correctly + /// substitute defaults of type parameters. + pub fn from_generics(generics: &ty::Generics<'tcx>, + mut mk_region: FR, + mut mk_type: FT) + -> Substs<'tcx> + where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { + let mut substs = Substs::empty(); + for &space in &ParamSpace::all() { + for def in generics.regions.get_slice(space) { + let region = mk_region(def, &substs); + assert_eq!(substs.regions.len(def.space), def.index as usize); + substs.regions.push(def.space, region); + } + for def in generics.types.get_slice(space) { + let ty = mk_type(def, &substs); + assert_eq!(substs.types.len(def.space), def.index as usize); + substs.types.push(def.space, ty); + } + } + substs + } + pub fn is_noop(&self) -> bool { self.regions.is_empty() && self.types.is_empty() } @@ -81,6 +108,10 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { *self.types.get(ty_param_def.space, ty_param_def.index as usize) } + pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region { + *self.regions.get(def.space, def.index as usize) + } + pub fn self_ty(&self) -> Option> { self.types.get_self().cloned() } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a0af98dec7298..ea7b447632c07 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use hir::def_id::DefId; use hir::print as pprust; use middle::resolve_lifetime as rl; use rustc::lint; -use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; +use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -115,11 +115,15 @@ pub trait AstConv<'gcx, 'tcx> { fn get_free_substs(&self) -> Option<&Substs<'tcx>>; /// What type should we use when a type is omitted? - fn ty_infer(&self, - param_and_substs: Option>, - substs: Option<&mut Substs<'tcx>>, - space: Option, - span: Span) -> Ty<'tcx>; + fn ty_infer(&self, span: Span) -> Ty<'tcx>; + + /// Same as ty_infer, but with a known type parameter definition. + fn ty_infer_for_def(&self, + _def: &ty::TypeParameterDef<'tcx>, + _substs: &Substs<'tcx>, + span: Span) -> Ty<'tcx> { + self.ty_infer(span) + } /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -535,26 +539,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self_ty: Option>) -> Vec> { - fn default_type_parameter<'tcx>(p: &ty::TypeParameterDef<'tcx>, self_ty: Option>) - -> Option> - { + let use_default = |p: &ty::TypeParameterDef<'tcx>| { if let Some(ref default) = p.default { if self_ty.is_none() && default.has_self_ty() { // There is no suitable inference default for a type parameter // that references self with no self-type provided. - return None; + return false; } } - Some(p.clone()) - } + true + }; if param_mode == PathParamMode::Optional && types_provided.is_empty() { - ty_param_defs - .iter() - .map(|p| self.ty_infer(default_type_parameter(p, self_ty), Some(&mut substs), - Some(TypeSpace), span)) - .collect() + ty_param_defs.iter().map(|def| { + let ty_var = if use_default(def) { + self.ty_infer_for_def(def, &substs, span) + } else { + self.ty_infer(span) + }; + substs.types.push(def.space, ty_var); + ty_var + }).collect() } else { types_provided } @@ -1828,7 +1834,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // values in a ExprClosure, or as // the type of local variables. Both of these cases are // handled specially and will not descend into this routine. - self.ty_infer(None, None, None, ast_ty.span) + self.ty_infer(ast_ty.span) } }; @@ -1845,7 +1851,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { { match a.ty.node { hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), - hir::TyInfer => self.ty_infer(None, None, None, a.ty.span), + hir::TyInfer => self.ty_infer(a.ty.span), _ => self.ast_ty_to_ty(rscope, &a.ty), } } @@ -2067,8 +2073,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let output_ty = match decl.output { _ if is_infer && expected_ret_ty.is_some() => expected_ret_ty.unwrap(), - _ if is_infer => - self.ty_infer(None, None, None, decl.output.span()), + _ if is_infer => self.ty_infer(decl.output.span()), hir::Return(ref output) => self.ast_ty_to_ty(&rb, &output), hir::DefaultReturn(..) => bug!(), diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 5fac65bbfd655..d1d7259955576 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -198,7 +198,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn fresh_receiver_substs(&mut self, self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) - -> subst::Substs<'tcx> + -> &'tcx subst::Substs<'tcx> { match pick.kind { probe::InherentImplPick => { @@ -231,7 +231,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { original_poly_trait_ref, upcast_trait_ref, trait_def_id); - upcast_trait_ref.substs.clone() + upcast_trait_ref.substs }) } @@ -249,9 +249,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let impl_trait_ref = self.instantiate_type_scheme( self.span, - &impl_polytype.substs, + impl_polytype.substs, &self.tcx.impl_trait_ref(impl_def_id).unwrap()); - impl_trait_ref.substs.clone() + impl_trait_ref.substs } probe::TraitPick => { @@ -271,7 +271,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { probe::WhereClausePick(ref poly_trait_ref) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - self.replace_late_bound_regions_with_fresh_var(&poly_trait_ref).substs.clone() + self.replace_late_bound_regions_with_fresh_var(&poly_trait_ref).substs } } } @@ -303,8 +303,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_substs(&mut self, pick: &probe::Pick<'tcx>, - supplied_method_types: Vec>, - substs: subst::Substs<'tcx>) + mut supplied_method_types: Vec>, + substs: &subst::Substs<'tcx>) -> subst::Substs<'tcx> { // Determine the values for the generic parameters of the method. @@ -312,50 +312,42 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // variables. let num_supplied_types = supplied_method_types.len(); let method = pick.item.as_opt_method().unwrap(); - let method_types = method.generics.types.get_slice(subst::FnSpace); - let num_method_types = method_types.len(); - + let num_method_types = method.generics.types.len(subst::FnSpace); + + if num_supplied_types > 0 && num_supplied_types != num_method_types { + if num_method_types == 0 { + span_err!(self.tcx.sess, self.span, E0035, + "does not take type parameters"); + } else { + span_err!(self.tcx.sess, self.span, E0036, + "incorrect number of type parameters given for this method: \ + expected {}, found {}", + num_method_types, num_supplied_types); + } + supplied_method_types = vec![self.tcx.types.err; num_method_types]; + } // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - let method_regions = - self.region_vars_for_defs( - self.span, - pick.item.as_opt_method().unwrap() - .generics.regions.get_slice(subst::FnSpace)); - - let subst::Substs { types, regions } = substs; - let regions = regions.with_slice(subst::FnSpace, &method_regions); - let mut final_substs = subst::Substs { types: types, regions: regions }; - - if num_supplied_types == 0 { - self.type_vars_for_defs( - self.span, - subst::FnSpace, - &mut final_substs, - method_types); - } else if num_method_types == 0 { - span_err!(self.tcx.sess, self.span, E0035, - "does not take type parameters"); - self.type_vars_for_defs( - self.span, - subst::FnSpace, - &mut final_substs, - method_types); - } else if num_supplied_types != num_method_types { - span_err!(self.tcx.sess, self.span, E0036, - "incorrect number of type parameters given for this method: expected {}, found {}", - num_method_types, num_supplied_types); - final_substs.types.replace( - subst::FnSpace, - vec![self.tcx.types.err; num_method_types]); - } else { - final_substs.types.replace(subst::FnSpace, supplied_method_types); - } - - return final_substs; + let type_defs = method.generics.types.as_full_slice(); + let region_defs = method.generics.regions.as_full_slice(); + subst::Substs::from_param_defs(region_defs, type_defs, |def| { + if def.space != subst::FnSpace { + substs.region_for_def(def) + } else { + self.region_var_for_def(self.span, def) + } + }, |def, cur_substs| { + if def.space != subst::FnSpace { + substs.type_for_def(def) + } else if supplied_method_types.is_empty() { + self.type_var_for_def(self.span, def, cur_substs) + } else { + supplied_method_types[def.index as usize] + } + }) } fn unify_receivers(&mut self, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e6401be5b3ef6..532a5c0de4e46 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -182,29 +182,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let trait_def = self.tcx.lookup_trait_def(trait_def_id); - let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace); - let expected_number_of_input_types = type_parameter_defs.len(); - + if let Some(ref input_types) = opt_input_types { + assert_eq!(trait_def.generics.types.len(subst::TypeSpace), input_types.len()); + } assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0); assert!(trait_def.generics.regions.is_empty()); // Construct a trait-reference `self_ty : Trait` - let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty); - - match opt_input_types { - Some(input_types) => { - assert_eq!(expected_number_of_input_types, input_types.len()); - substs.types.replace(subst::ParamSpace::TypeSpace, input_types); + let type_defs = trait_def.generics.types.as_full_slice(); + let region_defs = trait_def.generics.regions.as_full_slice(); + let substs = subst::Substs::from_param_defs(region_defs, type_defs, |def| { + self.region_var_for_def(span, def) + }, |def, substs| { + if def.space == subst::SelfSpace { + self_ty + } else if let Some(ref input_types) = opt_input_types { + input_types[def.index as usize] + } else { + self.type_var_for_def(span, def, substs) } - - None => { - self.type_vars_for_defs( - span, - subst::ParamSpace::TypeSpace, - &mut substs, - type_parameter_defs); - } - } + }); let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs)); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e4701bb119559..44e371482c55c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1227,28 +1227,29 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return impl_ty; } - let mut placeholder; + let placeholder; let mut substs = substs; if !method.generics.types.is_empty_in(subst::FnSpace) || !method.generics.regions.is_empty_in(subst::FnSpace) { - // In general, during probe we erase regions. See - // `impl_self_ty()` for an explanation. - let method_regions = - method.generics.regions.get_slice(subst::FnSpace) - .iter() - .map(|_| ty::ReErased) - .collect(); - - placeholder = (*substs).clone().with_method(Vec::new(), method_regions); - - self.type_vars_for_defs( - self.span, - subst::FnSpace, - &mut placeholder, - method.generics.types.get_slice(subst::FnSpace)); - + let type_defs = method.generics.types.as_full_slice(); + let region_defs = method.generics.regions.as_full_slice(); + placeholder = subst::Substs::from_param_defs(region_defs, type_defs, |def| { + if def.space != subst::FnSpace { + substs.region_for_def(def) + } else { + // In general, during probe we erase regions. See + // `impl_self_ty()` for an explanation. + ty::ReErased + } + }, |def, cur_substs| { + if def.space != subst::FnSpace { + substs.type_for_def(def) + } else { + self.type_var_for_def(self.span, def, cur_substs) + } + }); substs = &placeholder; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fae64f3741974..b5018d51b7f56 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1358,27 +1358,15 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { trait_def.associated_type_names.contains(&assoc_name) } - fn ty_infer(&self, - ty_param_def: Option>, - substs: Option<&mut subst::Substs<'tcx>>, - space: Option, - span: Span) -> Ty<'tcx> { - // Grab the default doing subsitution - let default = ty_param_def.and_then(|def| { - def.default.map(|ty| type_variable::Default { - ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)), - origin_span: span, - def_id: def.default_def_id - }) - }); - - let ty_var = self.next_ty_var_with_default(default); + fn ty_infer(&self, _span: Span) -> Ty<'tcx> { + self.next_ty_var() + } - // Finally we add the type variable to the substs - match substs { - None => ty_var, - Some(substs) => { substs.types.push(space.unwrap(), ty_var); ty_var } - } + fn ty_infer_for_def(&self, + ty_param_def: &ty::TypeParameterDef<'tcx>, + substs: &subst::Substs<'tcx>, + span: Span) -> Ty<'tcx> { + self.type_var_for_def(span, ty_param_def, substs) } fn projected_ty_from_poly_trait_ref(&self, @@ -2785,20 +2773,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, // (potential) receiver for this impl did: DefId) -> TypeAndSubsts<'tcx> { - let tcx = self.tcx; - - let ity = tcx.lookup_item_type(did); - let (tps, rps, raw_ty) = - (ity.generics.types.get_slice(subst::TypeSpace), - ity.generics.regions.get_slice(subst::TypeSpace), - ity.ty); + let ity = self.tcx.lookup_item_type(did); + debug!("impl_self_ty: ity={:?}", ity); - debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); - - let rps = self.region_vars_for_defs(span, rps); - let mut substs = subst::Substs::new_type(vec![], rps); - self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); - let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty); + let substs = self.fresh_substs_for_generics(span, &ity.generics); + let substd_ty = self.instantiate_type_scheme(span, &substs, &ity.ty); TypeAndSubsts { substs: substs, ty: substd_ty } } @@ -4532,7 +4511,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { substs.types.replace(space, Vec::new()); - self.type_vars_for_defs(span, space, substs, &desired[..]); + for def in desired { + let ty_var = self.type_var_for_def(span, def, substs); + substs.types.push(def.space, ty_var); + } return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 69545aefb4446..0ddc051d4a868 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -362,11 +362,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { None } - fn ty_infer(&self, - _ty_param_def: Option>, - _substs: Option<&mut Substs<'tcx>>, - _space: Option, - span: Span) -> Ty<'tcx> { + fn ty_infer(&self, span: Span) -> Ty<'tcx> { struct_span_err!( self.tcx().sess, span, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 11743ade2d469..4ce6f8210c3c5 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -132,7 +132,7 @@ pub mod coherence; pub mod variance; pub struct TypeAndSubsts<'tcx> { - pub substs: Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, pub ty: Ty<'tcx>, } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1e342d4b81971..50c568cfef8f6 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -464,7 +464,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.declared_variance(p.def_id, def_id, TypeParam, p.space, p.index as usize); let variance_i = self.xform(variance, variance_decl); - let substs_ty = *substs.types.get(p.space, p.index as usize); + let substs_ty = substs.type_for_def(p); debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}", variance_decl, variance_i); self.add_constraints_from_ty(generics, substs_ty, variance_i); @@ -475,7 +475,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.declared_variance(p.def_id, def_id, RegionParam, p.space, p.index as usize); let variance_i = self.xform(variance, variance_decl); - let substs_r = *substs.regions.get(p.space, p.index as usize); + let substs_r = substs.region_for_def(p); self.add_constraints_from_region(generics, substs_r, variance_i); } } From 4b25f08512eab11aec151d8f718fca0d8840d0c0 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 4 Aug 2016 15:52:57 +0300 Subject: [PATCH 065/768] rustc: move trait objects from TraitRef to ExistentialTraitRef. --- src/librustc/infer/mod.rs | 8 +- src/librustc/traits/coherence.rs | 4 +- src/librustc/traits/project.rs | 7 +- src/librustc/traits/select.rs | 49 +-- src/librustc/ty/context.rs | 25 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/fast_reject.rs | 2 +- src/librustc/ty/flags.rs | 21 +- src/librustc/ty/fold.rs | 9 - src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/mod.rs | 6 +- src/librustc/ty/relate.rs | 89 ++-- src/librustc/ty/structural_impls.rs | 90 ++-- src/librustc/ty/sty.rs | 180 ++++---- src/librustc/ty/util.rs | 10 +- src/librustc/ty/walk.rs | 6 +- src/librustc/ty/wf.rs | 23 +- src/librustc/util/ppaux.rs | 104 ++--- src/librustc_metadata/astencode.rs | 49 --- src/librustc_metadata/tydecode.rs | 61 ++- src/librustc_metadata/tyencode.rs | 67 +-- src/librustc_trans/base.rs | 11 +- src/librustc_trans/collector.rs | 3 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/trans_item.rs | 8 +- src/librustc_typeck/astconv.rs | 463 ++++++++------------ src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/closure.rs | 11 +- src/librustc_typeck/check/method/confirm.rs | 20 +- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 37 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/regionck.rs | 4 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/coherence/overlap.rs | 4 +- src/librustc_typeck/collect.rs | 34 +- src/librustc_typeck/variance/constraints.rs | 9 +- src/librustdoc/clean/mod.rs | 42 +- 39 files changed, 682 insertions(+), 792 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 79eea7314cdf3..951570679e08e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1248,9 +1248,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { generics: &ty::Generics<'tcx>) -> &'tcx subst::Substs<'tcx> { - let type_defs = generics.types.as_full_slice(); - let region_defs = generics.regions.as_full_slice(); - let substs = Substs::from_param_defs(region_defs, type_defs, |def| { + let substs = Substs::from_generics(generics, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { self.type_var_for_def(span, def, substs) @@ -1271,9 +1269,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { assert!(generics.types.len(subst::SelfSpace) == 1); assert!(generics.types.len(subst::FnSpace) == 0); - let type_defs = generics.types.as_full_slice(); - let region_defs = generics.regions.as_full_slice(); - let substs = Substs::from_param_defs(region_defs, type_defs, |def| { + let substs = Substs::from_generics(generics, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { if def.space == subst::SelfSpace { diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index b38f5f96de448..f1701d60fd0c0 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -231,7 +231,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.is_fundamental(), ty::TyTrait(ref data) => - tcx.has_attr(data.principal_def_id(), "fundamental"), + tcx.has_attr(data.principal.def_id(), "fundamental"), _ => false } @@ -275,7 +275,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> } ty::TyTrait(ref tt) => { - tt.principal_def_id().is_local() + tt.principal.def_id().is_local() } ty::TyError => { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index d580deed0756a..ea4fc1c25ab42 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1133,10 +1133,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( object_ty) } }; - let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); - let env_predicates = projection_bounds.iter() - .map(|p| p.to_predicate()) - .collect(); + let env_predicates = data.projection_bounds.iter().map(|p| { + p.with_self_ty(selcx.tcx(), object_ty).to_predicate() + }).collect(); let env_predicate = { let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9c7dd7ccd7011..73108e7d37f88 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1528,7 +1528,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyTrait(ref data) => { match this.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { - if data.bounds.builtin_bounds.contains(&bound) { + if data.builtin_bounds.contains(&bound) { debug!("assemble_candidates_from_object_ty: matched builtin bound, \ pushing candidate"); candidates.vec.push(BuiltinObjectCandidate); @@ -1538,7 +1538,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ => {} } - data.principal_trait_ref_with_self_ty(this.tcx(), self_ty) + data.principal.with_self_ty(this.tcx(), self_ty) } ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_candidates_from_object_ty: ambiguous"); @@ -1622,7 +1622,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // We always upcast when we can because of reason // #2 (region bounds). data_a.principal.def_id() == data_a.principal.def_id() && - data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) + data_a.builtin_bounds.is_superset(&data_b.builtin_bounds) } // T -> Trait. @@ -2179,10 +2179,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self_ty.sty { ty::TyTrait(ref data) => { // OK to skip the binder, it is reintroduced below - let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace); - let assoc_types = data.bounds.projection_bounds - .iter() - .map(|pb| pb.skip_binder().ty); + let input_types = data.principal.skip_binder().input_types(); + let assoc_types = data.projection_bounds.iter() + .map(|pb| pb.skip_binder().ty); let all_types: Vec<_> = input_types.iter().cloned() .chain(assoc_types) .collect(); @@ -2315,7 +2314,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let poly_trait_ref = match self_ty.sty { ty::TyTrait(ref data) => { - data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) + data.principal.with_self_ty(self.tcx(), self_ty) } _ => { span_bug!(obligation.cause.span, @@ -2487,13 +2486,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => { // See assemble_candidates_for_unsizing for more info. - let bounds = ty::ExistentialBounds { - region_bound: data_b.bounds.region_bound, - builtin_bounds: data_b.bounds.builtin_bounds, - projection_bounds: data_a.bounds.projection_bounds.clone(), - }; - - let new_trait = tcx.mk_trait(data_a.principal.clone(), bounds); + let new_trait = tcx.mk_trait(ty::TraitObject { + principal: data_a.principal, + region_bound: data_b.region_bound, + builtin_bounds: data_b.builtin_bounds, + projection_bounds: data_a.projection_bounds.clone(), + }); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_trait, target) @@ -2504,8 +2502,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let cause = ObligationCause::new(obligation.cause.span, obligation.cause.body_id, ObjectCastObligation(target)); - let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound, - data_b.bounds.region_bound); + let outlives = ty::OutlivesPredicate(data_a.region_bound, + data_b.region_bound); nested.push(Obligation::with_depth(cause, obligation.recursion_depth + 1, ty::Binder(outlives).to_predicate())); @@ -2513,12 +2511,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { - let mut object_dids = Some(data.principal_def_id()).into_iter(); + let mut object_dids = Some(data.principal.def_id()).into_iter(); // FIXME(#33243) -// data.bounds.builtin_bounds.iter().flat_map(|bound| { +// data.builtin_bounds.iter().flat_map(|bound| { // tcx.lang_items.from_builtin_kind(bound).ok() // }) -// .chain(Some(data.principal_def_id())); +// .chain(Some(data.principal.def_id())); if let Some(did) = object_dids.find(|did| { !tcx.is_object_safe(*did) }) { @@ -2535,10 +2533,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }; // Create the obligation for casting from T to Trait. - push(data.principal_trait_ref_with_self_ty(tcx, source).to_predicate()); + push(data.principal.with_self_ty(tcx, source).to_predicate()); // We can only make objects from sized types. - let mut builtin_bounds = data.bounds.builtin_bounds; + let mut builtin_bounds = data.builtin_bounds; builtin_bounds.insert(ty::BoundSized); // Create additional obligations for all the various builtin @@ -2554,14 +2552,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Create obligations for the projection predicates. - for bound in data.projection_bounds_with_self_ty(tcx, source) { - push(bound.to_predicate()); + for bound in &data.projection_bounds { + push(bound.with_self_ty(tcx, source).to_predicate()); } // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` outlives `'a`: - let outlives = ty::OutlivesPredicate(source, - data.bounds.region_bound); + let outlives = ty::OutlivesPredicate(source, data.region_bound); push(ty::Binder(outlives).to_predicate()); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 4056fb01aa2c2..dfb5482ad873b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -27,9 +27,9 @@ use ty::subst::{self, Substs}; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants}; -use ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region}; +use ty::{AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; -use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy}; +use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject}; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; use ty::TypeVariants::*; use ty::layout::{Layout, TargetDataLayout}; @@ -1150,12 +1150,6 @@ impl_interners!('tcx, region: mk_region(Region, keep_local) -> Region ); -fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { - bounds.is_empty() || - bounds[1..].iter().enumerate().all( - |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) -} - impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Create an unsafe fn ty based on a safe fn ty. pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { @@ -1288,18 +1282,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyFnPtr(fty)) } - pub fn mk_trait(self, - principal: ty::PolyTraitRef<'tcx>, - bounds: ExistentialBounds<'tcx>) - -> Ty<'tcx> - { - assert!(bound_list_is_sorted(&bounds.projection_bounds)); - - let inner = box TraitTy { - principal: principal, - bounds: bounds - }; - self.mk_ty(TyTrait(inner)) + pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> { + obj.projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); + self.mk_ty(TyTrait(box obj)) } pub fn mk_projection(self, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 42d5788568f1c..933746ebc2ad1 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -243,7 +243,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyFnDef(..) => format!("fn item"), ty::TyFnPtr(_) => "fn pointer".to_string(), ty::TyTrait(ref inner) => { - format!("trait {}", tcx.item_path_str(inner.principal_def_id())) + format!("trait {}", tcx.item_path_str(inner.principal.def_id())) } ty::TyStruct(def, _) => { format!("struct `{}`", tcx.item_path_str(def.did)) diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 9bf2daeb5f49b..f7472d611befe 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -61,7 +61,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), ty::TyRawPtr(_) => Some(PtrSimplifiedType), ty::TyTrait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal_def_id())) + Some(TraitSimplifiedType(trait_info.principal.def_id())) } ty::TyStruct(def, _) => { Some(StructSimplifiedType(def.did)) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 3a5f3d421eaf7..6cc759c420d29 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -116,17 +116,16 @@ impl FlagComputation { self.add_substs(substs); } - &ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { + &ty::TyTrait(ref obj) => { let mut computation = FlagComputation::new(); - computation.add_substs(principal.0.substs); - for projection_bound in &bounds.projection_bounds { + computation.add_substs(obj.principal.skip_binder().substs); + for projection_bound in &obj.projection_bounds { let mut proj_computation = FlagComputation::new(); - proj_computation.add_projection_predicate(&projection_bound.0); + proj_computation.add_existential_projection(&projection_bound.0); self.add_bound_computation(&proj_computation); } self.add_bound_computation(&computation); - - self.add_bounds(bounds); + self.add_region(obj.region_bound); } &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => { @@ -199,9 +198,9 @@ impl FlagComputation { } } - fn add_projection_predicate(&mut self, projection_predicate: &ty::ProjectionPredicate) { - self.add_projection_ty(&projection_predicate.projection_ty); - self.add_ty(projection_predicate.ty); + fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) { + self.add_substs(projection.trait_ref.substs); + self.add_ty(projection.ty); } fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) { @@ -214,8 +213,4 @@ impl FlagComputation { self.add_region(r); } } - - fn add_bounds(&mut self, bounds: &ty::ExistentialBounds) { - self.add_region(bounds.region_bound); - } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 3eeff6ee5792f..597261cca72bf 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -140,10 +140,6 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { t.super_fold_with(self) } - fn fold_trait_ref(&mut self, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> { - t.super_fold_with(self) - } - fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> { imp.super_fold_with(self) } @@ -177,11 +173,6 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { r.super_fold_with(self) } - fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>) - -> ty::ExistentialBounds<'tcx> { - s.super_fold_with(self) - } - fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) -> adjustment::AutoRef<'tcx> { ar.super_fold_with(self) diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 8ddd8bef36a6f..1dcc623d36558 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -322,7 +322,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => Some(adt_def.did), - ty::TyTrait(ref data) => Some(data.principal_def_id()), + ty::TyTrait(ref data) => Some(data.principal.def_id()), ty::TyArray(subty, _) | ty::TySlice(subty) | diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 44532fcb4e64f..6ac57a877a759 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -54,11 +54,13 @@ use hir::{ItemImpl, ItemTrait, PatKind}; use hir::intravisit::Visitor; pub use self::sty::{Binder, DebruijnIndex}; -pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; +pub use self::sty::{BuiltinBound, BuiltinBounds}; pub use self::sty::{BareFnTy, FnSig, PolyFnSig}; -pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy}; +pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitObject}; pub use self::sty::{ClosureSubsts, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; +pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; +pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::Issue32330; pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 05a9b8111570d..aa48474e50cf1 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -326,24 +326,33 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { +impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { fn relate<'a, 'gcx, R>(relation: &mut R, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>) - -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> + a: &ty::ExistentialProjection<'tcx>, + b: &ty::ExistentialProjection<'tcx>) + -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let projection_ty = relation.relate(&a.projection_ty, &b.projection_ty)?; - let ty = relation.relate(&a.ty, &b.ty)?; - Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) + if a.item_name != b.item_name { + Err(TypeError::ProjectionNameMismatched( + expected_found(relation, &a.item_name, &b.item_name))) + } else { + let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?; + let ty = relation.relate(&a.ty, &b.ty)?; + Ok(ty::ExistentialProjection { + trait_ref: trait_ref, + item_name: a.item_name, + ty: ty + }) + } } } -impl<'tcx> Relate<'tcx> for Vec> { +impl<'tcx> Relate<'tcx> for Vec> { fn relate<'a, 'gcx, R>(relation: &mut R, - a: &Vec>, - b: &Vec>) - -> RelateResult<'tcx, Vec>> + a: &Vec>, + b: &Vec>) + -> RelateResult<'tcx, Vec>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { // To be compatible, `a` and `b` must be for precisely the @@ -361,27 +370,6 @@ impl<'tcx> Relate<'tcx> for Vec> { } } -impl<'tcx> Relate<'tcx> for ty::ExistentialBounds<'tcx> { - fn relate<'a, 'gcx, R>(relation: &mut R, - a: &ty::ExistentialBounds<'tcx>, - b: &ty::ExistentialBounds<'tcx>) - -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> - where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a - { - let r = - relation.with_cause( - Cause::ExistentialRegionBound, - |relation| relation.relate_with_variance(ty::Contravariant, - &a.region_bound, - &b.region_bound))?; - let nb = relation.relate(&a.builtin_bounds, &b.builtin_bounds)?; - let pb = relation.relate(&a.projection_bounds, &b.projection_bounds)?; - Ok(ty::ExistentialBounds { region_bound: r, - builtin_bounds: nb, - projection_bounds: pb }) - } -} - impl<'tcx> Relate<'tcx> for ty::BuiltinBounds { fn relate<'a, 'gcx, R>(relation: &mut R, a: &ty::BuiltinBounds, @@ -416,6 +404,23 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { + fn relate<'a, 'gcx, R>(relation: &mut R, + a: &ty::ExistentialTraitRef<'tcx>, + b: &ty::ExistentialTraitRef<'tcx>) + -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a + { + // Different traits cannot be related + if a.def_id != b.def_id { + Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) + } else { + let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?; + Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs }) + } + } +} + impl<'tcx> Relate<'tcx> for Ty<'tcx> { fn relate<'a, 'gcx, R>(relation: &mut R, a: &Ty<'tcx>, @@ -478,11 +483,23 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_enum(a_def, substs)) } - (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) => + (&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) => { - let principal = relation.relate(&a_.principal, &b_.principal)?; - let bounds = relation.relate(&a_.bounds, &b_.bounds)?; - Ok(tcx.mk_trait(principal, bounds)) + let principal = relation.relate(&a_obj.principal, &b_obj.principal)?; + let r = + relation.with_cause( + Cause::ExistentialRegionBound, + |relation| relation.relate_with_variance(ty::Contravariant, + &a_obj.region_bound, + &b_obj.region_bound))?; + let nb = relation.relate(&a_obj.builtin_bounds, &b_obj.builtin_bounds)?; + let pb = relation.relate(&a_obj.projection_bounds, &b_obj.projection_bounds)?; + Ok(tcx.mk_trait(ty::TraitObject { + principal: principal, + region_bound: r, + builtin_bounds: nb, + projection_bounds: pb + })) } (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index b0f8e2e13f7e0..14005c1bd8b76 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -10,7 +10,7 @@ use infer::type_variable; use ty::subst::{self, VecPerParamSpace}; -use ty::{self, Lift, TraitRef, Ty, TyCtxt}; +use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use std::rc::Rc; @@ -80,10 +80,20 @@ impl<'tcx> Lift<'tcx> for ty::Region { } } -impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> { - type Lifted = TraitRef<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - tcx.lift(&self.substs).map(|substs| TraitRef { +impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { + type Lifted = ty::TraitRef<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.substs).map(|substs| ty::TraitRef { + def_id: self.def_id, + substs: substs + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { + type Lifted = ty::ExistentialTraitRef<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs: substs }) @@ -141,6 +151,19 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { + type Lifted = ty::ExistentialProjection<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&(self.trait_ref, self.ty)).map(|(trait_ref, ty)| { + ty::ExistentialProjection { + trait_ref: trait_ref, + item_name: self.item_name, + ty: ty + } + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { type Lifted = ty::Predicate<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -437,16 +460,20 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { } } -impl<'tcx> TypeFoldable<'tcx> for ty::TraitTy<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::TraitTy { + ty::TraitObject { principal: self.principal.fold_with(folder), - bounds: self.bounds.fold_with(folder), + region_bound: self.region_bound.fold_with(folder), + builtin_bounds: self.builtin_bounds, + projection_bounds: self.projection_bounds.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.principal.visit_with(visitor) || self.bounds.visit_with(visitor) + self.principal.visit_with(visitor) || + self.region_bound.visit_with(visitor) || + self.projection_bounds.visit_with(visitor) } } @@ -599,8 +626,17 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_trait_ref(self) + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.substs.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialTraitRef<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::ExistentialTraitRef { + def_id: self.def_id, + substs: self.substs.fold_with(folder), + } } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -741,24 +777,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::ExistentialBounds { - region_bound: self.region_bound.fold_with(folder), - builtin_bounds: self.builtin_bounds, - projection_bounds: self.projection_bounds.fold_with(folder), - } - } - - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_existential_bounds(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.region_bound.visit_with(visitor) || self.projection_bounds.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TypeParameterDef { @@ -893,6 +911,20 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialProjection<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::ExistentialProjection { + trait_ref: self.trait_ref.fold_with(folder), + item_name: self.item_name, + ty: self.ty.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.trait_ref.visit_with(visitor) || self.ty.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ProjectionTy { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 098943dfce29a..91214873f193d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -152,7 +152,7 @@ pub enum TypeVariants<'tcx> { TyFnPtr(&'tcx BareFnTy<'tcx>), /// A trait, defined with `trait`. - TyTrait(Box>), + TyTrait(Box>), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -291,57 +291,11 @@ impl<'tcx> Decodable for ClosureSubsts<'tcx> { } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct TraitTy<'tcx> { - pub principal: ty::PolyTraitRef<'tcx>, - pub bounds: ExistentialBounds<'tcx>, -} - -impl<'a, 'gcx, 'tcx> TraitTy<'tcx> { - pub fn principal_def_id(&self) -> DefId { - self.principal.0.def_id - } - - /// Object types don't have a self-type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self-type. A common choice is `mk_err()` - /// or some skolemized type. - pub fn principal_trait_ref_with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - self_ty: Ty<'tcx>) - -> ty::PolyTraitRef<'tcx> - { - // otherwise the escaping regions would be captured by the binder - assert!(!self_ty.has_escaping_regions()); - - ty::Binder(TraitRef { - def_id: self.principal.0.def_id, - substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)), - }) - } - - pub fn projection_bounds_with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - self_ty: Ty<'tcx>) - -> Vec> - { - // otherwise the escaping regions would be captured by the binders - assert!(!self_ty.has_escaping_regions()); - - self.bounds.projection_bounds.iter() - .map(|in_poly_projection_predicate| { - let in_projection_ty = &in_poly_projection_predicate.0.projection_ty; - let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty)); - let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id, - substs); - let projection_ty = ty::ProjectionTy { - trait_ref: trait_ref, - item_name: in_projection_ty.item_name - }; - ty::Binder(ty::ProjectionPredicate { - projection_ty: projection_ty, - ty: in_poly_projection_predicate.0.ty - }) - }) - .collect() - } +pub struct TraitObject<'tcx> { + pub principal: PolyExistentialTraitRef<'tcx>, + pub region_bound: ty::Region, + pub builtin_bounds: BuiltinBounds, + pub projection_bounds: Vec>, } /// A complete reference to a trait. These take numerous guises in syntax, @@ -392,6 +346,70 @@ impl<'tcx> PolyTraitRef<'tcx> { } } +/// An existential reference to a trait, where `Self` is erased. +/// For example, the trait object `Trait<'a, 'b, X, Y>` is: +/// +/// exists T. T: Trait<'a, 'b, X, Y> +/// +/// The substitutions don't include the erased `Self`, only trait +/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct ExistentialTraitRef<'tcx> { + pub def_id: DefId, + pub substs: &'tcx Substs<'tcx>, +} + +impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { + pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_ref: ty::TraitRef<'tcx>) + -> ty::ExistentialTraitRef<'tcx> { + let mut substs = trait_ref.substs.clone(); + substs.types.pop(subst::SelfSpace); + ty::ExistentialTraitRef { + def_id: trait_ref.def_id, + substs: tcx.mk_substs(substs) + } + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + // Select only the "input types" from a trait-reference. For + // now this is all the types that appear in the + // trait-reference, but it should eventually exclude + // associated types. + self.substs.types.as_full_slice() + } +} + +pub type PolyExistentialTraitRef<'tcx> = Binder>; + +impl<'a, 'gcx, 'tcx> PolyExistentialTraitRef<'tcx> { + pub fn def_id(&self) -> DefId { + self.0.def_id + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> + self.0.input_types() + } + + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyTraitRef<'tcx> + { + // otherwise the escaping regions would be captured by the binder + assert!(!self_ty.has_escaping_regions()); + + self.map_bound(|trait_ref| TraitRef { + def_id: trait_ref.def_id, + substs: tcx.mk_substs(trait_ref.substs.with_self_ty(self_ty)), + }) + } +} + /// Binder is a binder for higher-ranked lifetimes. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` /// (which would be represented by the type `PolyTraitRef == @@ -730,27 +748,40 @@ pub enum InferTy { FreshFloatTy(u32) } -/// Bounds suitable for an existentially quantified type parameter -/// such as those that appear in object types or closure types. -#[derive(PartialEq, Eq, Hash, Clone)] -pub struct ExistentialBounds<'tcx> { - pub region_bound: ty::Region, - pub builtin_bounds: BuiltinBounds, - pub projection_bounds: Vec>, +/// A `ProjectionPredicate` for an `ExistentialTraitRef`. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct ExistentialProjection<'tcx> { + pub trait_ref: ExistentialTraitRef<'tcx>, + pub item_name: Name, + pub ty: Ty<'tcx> } -impl<'tcx> ExistentialBounds<'tcx> { - pub fn new(region_bound: ty::Region, - builtin_bounds: BuiltinBounds, - projection_bounds: Vec>) - -> Self { - let mut projection_bounds = projection_bounds; - projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); - ExistentialBounds { - region_bound: region_bound, - builtin_bounds: builtin_bounds, - projection_bounds: projection_bounds - } +pub type PolyExistentialProjection<'tcx> = Binder>; + +impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { + pub fn item_name(&self) -> Name { + self.0.item_name // safe to skip the binder to access a name + } + + pub fn sort_key(&self) -> (DefId, Name) { + (self.0.trait_ref.def_id, self.0.item_name) + } + + pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyProjectionPredicate<'tcx> + { + // otherwise the escaping regions would be captured by the binders + assert!(!self_ty.has_escaping_regions()); + + let trait_ref = self.map_bound(|proj| proj.trait_ref); + self.map_bound(|proj| ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref.with_self_ty(tcx, self_ty).0, + item_name: proj.item_name + }, + ty: proj.ty + }) } } @@ -1185,7 +1216,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_to_def_id(&self) -> Option { match self.sty { - TyTrait(ref tt) => Some(tt.principal_def_id()), + TyTrait(ref tt) => Some(tt.principal.def_id()), TyStruct(def, _) | TyEnum(def, _) => Some(def.did), TyClosure(id, _) => Some(id), @@ -1209,9 +1240,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { vec![*region] } TyTrait(ref obj) => { - let mut v = vec![obj.bounds.region_bound]; - v.extend_from_slice(obj.principal.skip_binder() - .substs.regions.as_full_slice()); + let mut v = vec![obj.region_bound]; + v.extend_from_slice(obj.principal.skip_binder().substs.regions.as_full_slice()); v } TyEnum(_, substs) | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d7bb8ff2995aa..3c1f6e9199220 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -451,21 +451,21 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { // to sort them again by the name, in string form. // Hash the whole principal trait ref. - self.def_id(data.principal_def_id()); + self.def_id(data.principal.def_id()); data.principal.visit_with(self); // Hash region and builtin bounds. - data.bounds.region_bound.visit_with(self); - self.hash(data.bounds.builtin_bounds); + data.region_bound.visit_with(self); + self.hash(data.builtin_bounds); // Only projection bounds are left, sort and hash them. - let mut projection_bounds: Vec<_> = data.bounds.projection_bounds + let mut projection_bounds: Vec<_> = data.projection_bounds .iter() .map(|b| (b.item_name().as_str(), b)) .collect(); projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); for (name, bound) in projection_bounds { - self.def_id(bound.0.projection_ty.trait_ref.def_id); + self.def_id(bound.0.trait_ref.def_id); self.hash(name); bound.visit_with(self); } diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 3f87d80e337dd..3bf539245571e 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -81,9 +81,9 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyProjection(ref data) => { push_reversed(stack, data.trait_ref.substs.types.as_full_slice()); } - ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { - push_reversed(stack, principal.substs().types.as_full_slice()); - push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { + ty::TyTrait(ref obj) => { + push_reversed(stack, obj.principal.input_types()); + push_reversed(stack, &obj.projection_bounds.iter().map(|pred| { pred.0.ty }).collect::>()); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 009e3e2433431..77d0835bf6bc1 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -406,13 +406,13 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // FIXME(#33243): remove RFC1592 self.out.push(traits::Obligation::new( cause.clone(), - ty::Predicate::ObjectSafe(data.principal_def_id()) + ty::Predicate::ObjectSafe(data.principal.def_id()) )); let component_traits = - data.bounds.builtin_bounds.iter().flat_map(|bound| { + data.builtin_bounds.iter().flat_map(|bound| { tcx.lang_items.from_builtin_kind(bound).ok() }); -// .chain(Some(data.principal_def_id())); +// .chain(Some(data.principal.def_id())); self.out.extend( component_traits.map(|did| { traits::Obligation::new( cause.clone(), @@ -476,7 +476,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { .collect() } - fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitTy<'tcx>) { + fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitObject<'tcx>) { // Imagine a type like this: // // trait Foo { } @@ -512,10 +512,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { if !data.has_escaping_regions() { let implicit_bounds = object_region_bounds(self.infcx.tcx, - &data.principal, - data.bounds.builtin_bounds); + data.principal, + data.builtin_bounds); - let explicit_bound = data.bounds.region_bound; + let explicit_bound = data.region_bound; for implicit_bound in implicit_bounds { let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); @@ -534,7 +534,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// `ty::required_region_bounds`, see that for more information. pub fn object_region_bounds<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, - principal: &ty::PolyTraitRef<'tcx>, + principal: ty::PolyExistentialTraitRef<'tcx>, others: ty::BuiltinBounds) -> Vec { @@ -543,13 +543,8 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>( // a skolemized type. let open_ty = tcx.mk_infer(ty::FreshTy(0)); - // Note that we preserve the overall binding levels here. - assert!(!open_ty.has_escaping_regions()); - let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); - let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); - let mut predicates = others.to_predicates(tcx, open_ty); - predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); + predicates.push(principal.with_self_ty(tcx, open_ty).to_predicate()); tcx.required_region_bounds(open_ty, predicates) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37750b568bba2..fb0b6413fab40 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -288,7 +288,8 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, /// projection bounds, so we just stuff them altogether. But in /// reality we should eventually sort things out better. #[derive(Clone, Debug)] -struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec>); +struct TraitAndProjections<'tcx>(ty::ExistentialTraitRef<'tcx>, + Vec>); impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -311,24 +312,24 @@ impl<'tcx> fmt::Display for TraitAndProjections<'tcx> { } } -impl<'tcx> fmt::Display for ty::TraitTy<'tcx> { +impl<'tcx> fmt::Display for ty::TraitObject<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let bounds = &self.bounds; - // Generate the main trait ref, including associated types. ty::tls::with(|tcx| { let principal = tcx.lift(&self.principal.0) .expect("could not lift TraitRef for printing"); - let projections = tcx.lift(&bounds.projection_bounds[..]) - .expect("could not lift projections for printing"); - let projections = projections.into_iter().map(|p| p.0).collect(); + let projections = self.projection_bounds.iter().map(|p| { + let projection = tcx.lift(p) + .expect("could not lift projection for printing"); + projection.with_self_ty(tcx, tcx.types.err).0 + }).collect(); let tap = ty::Binder(TraitAndProjections(principal, projections)); in_binder(f, tcx, &ty::Binder(""), Some(tap)) })?; // Builtin bounds. - for bound in &bounds.builtin_bounds { + for bound in &self.builtin_bounds { write!(f, " + {:?}", bound)?; } @@ -337,7 +338,7 @@ impl<'tcx> fmt::Display for ty::TraitTy<'tcx> { // use thread-local data of some kind? There are also // advantages to just showing the region, since it makes // people aware that it's there. - let bound = bounds.region_bound.to_string(); + let bound = self.region_bound.to_string(); if !bound.is_empty() { write!(f, " + {}", bound)?; } @@ -397,10 +398,13 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { // when printing out the debug representation, we don't need // to enumerate the `for<...>` etc because the debruijn index // tells you everything you need to know. - match self.substs.self_ty() { - None => write!(f, "{}", *self), - Some(self_ty) => write!(f, "<{:?} as {}>", self_ty, *self) - } + write!(f, "<{:?} as {}>", self.self_ty(), *self) + } +} + +impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", *self) } } @@ -448,11 +452,38 @@ impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> { } } -impl<'tcx> fmt::Debug for ty::TraitTy<'tcx> { +impl<'tcx> fmt::Debug for ty::TraitObject<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TraitTy({:?},{:?})", - self.principal, - self.bounds) + let mut empty = true; + let mut maybe_continue = |f: &mut fmt::Formatter| { + if empty { + empty = false; + Ok(()) + } else { + write!(f, " + ") + } + }; + + maybe_continue(f)?; + write!(f, "{:?}", self.principal)?; + + let region_str = format!("{:?}", self.region_bound); + if !region_str.is_empty() { + maybe_continue(f)?; + write!(f, "{}", region_str)?; + } + + for bound in &self.builtin_bounds { + maybe_continue(f)?; + write!(f, "{:?}", bound)?; + } + + for projection_bound in &self.projection_bounds { + maybe_continue(f)?; + write!(f, "{:?}", projection_bound)?; + } + + Ok(()) } } @@ -668,38 +699,6 @@ impl<'tcx> fmt::Display for ty::FnSig<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ExistentialBounds<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut empty = true; - let mut maybe_continue = |f: &mut fmt::Formatter| { - if empty { - empty = false; - Ok(()) - } else { - write!(f, " + ") - } - }; - - let region_str = format!("{:?}", self.region_bound); - if !region_str.is_empty() { - maybe_continue(f)?; - write!(f, "{}", region_str)?; - } - - for bound in &self.builtin_bounds { - maybe_continue(f)?; - write!(f, "{:?}", bound)?; - } - - for projection_bound in &self.projection_bounds { - maybe_continue(f)?; - write!(f, "{:?}", projection_bound)?; - } - - Ok(()) - } -} - impl fmt::Display for ty::BuiltinBounds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut bounds = self.iter(); @@ -819,6 +818,13 @@ impl<'tcx> fmt::Display for ty::TraitRef<'tcx> { } } +impl<'tcx> fmt::Display for ty::ExistentialTraitRef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + parameterized(f, self.substs, self.def_id, Ns::Type, &[], + |tcx| Some(tcx.lookup_trait_def(self.def_id).generics.clone())) + } +} + impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index b8e66530ea153..c552e612504e9 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -524,16 +524,8 @@ pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { trait rbml_writer_helpers<'tcx> { fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); - fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); - fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - predicate: &ty::Predicate<'tcx>); - fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - ty: &ty::TraitRef<'tcx>); fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, substs: &subst::Substs<'tcx>); - fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, - bounds: &ty::ExistentialBounds<'tcx>); - fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, adj: &adjustment::AutoAdjustment<'tcx>); @@ -556,39 +548,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { ty))); } - fn emit_tys<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, tys: &[Ty<'tcx>]) { - self.emit_from_vec(tys, |this, ty| Ok(this.emit_ty(ecx, *ty))); - } - - fn emit_trait_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - trait_ref: &ty::TraitRef<'tcx>) { - self.emit_opaque(|this| Ok(tyencode::enc_trait_ref(&mut this.cursor, - &ecx.ty_str_ctxt(), - *trait_ref))); - } - - fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - predicate: &ty::Predicate<'tcx>) { - self.emit_opaque(|this| { - Ok(tyencode::enc_predicate(&mut this.cursor, - &ecx.ty_str_ctxt(), - predicate)) - }); - } - - fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, - bounds: &ty::ExistentialBounds<'tcx>) { - self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(&mut this.cursor, - &ecx.ty_str_ctxt(), - bounds))); - } - - fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) { - self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(&mut this.cursor, - &ecx.ty_str_ctxt(), - bounds))); - } - fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) { use rustc_serialize::Encoder; @@ -879,8 +838,6 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::PolyTraitRef<'tcx>; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::Predicate<'tcx>; - fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::ExistentialBounds<'tcx>; fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> subst::Substs<'tcx>; fn read_upvar_capture(&mut self, dcx: &DecodeContext) @@ -988,12 +945,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate()) } - fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::ExistentialBounds<'tcx> - { - self.read_ty_encoded(dcx, |decoder| decoder.parse_existential_bounds()) - } - fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> subst::Substs<'tcx> { self.read_opaque(|_, doc| { diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 7b4919bb4773b..11c155cbd5b9f 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -307,6 +307,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { ty::TraitRef {def_id: def, substs: substs} } + pub fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> { + let def = self.parse_def(); + let substs = self.tcx.mk_substs(self.parse_substs()); + ty::ExistentialTraitRef {def_id: def, substs: substs} + } + pub fn parse_ty(&mut self) -> Ty<'tcx> { let tcx = self.tcx; match self.next() { @@ -340,10 +346,30 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'x' => { assert_eq!(self.next(), '['); - let trait_ref = ty::Binder(self.parse_trait_ref()); - let bounds = self.parse_existential_bounds(); + let trait_ref = ty::Binder(self.parse_existential_trait_ref()); + let builtin_bounds = self.parse_builtin_bounds(); + let region_bound = self.parse_region(); + let mut projection_bounds = Vec::new(); + + loop { + match self.next() { + 'P' => { + let bound = self.parse_existential_projection(); + projection_bounds.push(ty::Binder(bound)); + } + '.' => { break; } + c => { + bug!("parse_bounds: bad bounds ('{}')", c) + } + } + } assert_eq!(self.next(), ']'); - return tcx.mk_trait(trait_ref, bounds); + return tcx.mk_trait(ty::TraitObject { + principal: trait_ref, + region_bound: region_bound, + builtin_bounds: builtin_bounds, + projection_bounds: projection_bounds + }); } 'p' => { assert_eq!(self.next(), '['); @@ -588,6 +614,14 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } + fn parse_existential_projection(&mut self) -> ty::ExistentialProjection<'tcx> { + ty::ExistentialProjection { + trait_ref: self.parse_existential_trait_ref(), + item_name: token::intern(&self.parse_str('|')), + ty: self.parse_ty(), + } + } + pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { let name = self.parse_name(':'); let def_id = self.parse_def(); @@ -649,27 +683,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - pub fn parse_existential_bounds(&mut self) -> ty::ExistentialBounds<'tcx> { - let builtin_bounds = self.parse_builtin_bounds(); - let region_bound = self.parse_region(); - let mut projection_bounds = Vec::new(); - - loop { - match self.next() { - 'P' => { - projection_bounds.push(ty::Binder(self.parse_projection_predicate())); - } - '.' => { break; } - c => { - bug!("parse_bounds: bad bounds ('{}')", c) - } - } - } - - ty::ExistentialBounds::new( - region_bound, builtin_bounds, projection_bounds) - } - fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds { let mut builtin_bounds = ty::BuiltinBounds::empty(); loop { diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 15bafcdd3c99e..8deb1eb6ac31d 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -104,11 +104,26 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx enc_substs(w, cx, substs); write!(w, "]"); } - ty::TyTrait(box ty::TraitTy { ref principal, - ref bounds }) => { + ty::TyTrait(ref obj) => { write!(w, "x["); - enc_trait_ref(w, cx, principal.0); - enc_existential_bounds(w, cx, bounds); + enc_existential_trait_ref(w, cx, obj.principal.0); + enc_builtin_bounds(w, cx, &obj.builtin_bounds); + + enc_region(w, cx, obj.region_bound); + + // Encode projection_bounds in a stable order + let mut projection_bounds: Vec<_> = obj.projection_bounds + .iter() + .map(|b| (b.item_name().as_str(), b)) + .collect(); + projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); + + for tp in projection_bounds.iter().map(|&(_, tp)| tp) { + write!(w, "P"); + enc_existential_projection(w, cx, &tp.0); + } + + write!(w, "."); write!(w, "]"); } ty::TyTuple(ts) => { @@ -344,6 +359,12 @@ pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, enc_substs(w, cx, s.substs); } +fn enc_existential_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, + s: ty::ExistentialTraitRef<'tcx>) { + write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id)); + enc_substs(w, cx, s.substs); +} + fn enc_unsafety(w: &mut Cursor>, p: hir::Unsafety) { match p { hir::Unsafety::Normal => write!(w, "n"), @@ -386,7 +407,7 @@ fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, enc_ty(w, cx, fsig.0.output); } -pub fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBounds) { +fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBounds) { for bound in bs { match bound { ty::BoundSend => write!(w, "S"), @@ -399,28 +420,6 @@ pub fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinB write!(w, "."); } -pub fn enc_existential_bounds<'a,'tcx>(w: &mut Cursor>, - cx: &ctxt<'a,'tcx>, - bs: &ty::ExistentialBounds<'tcx>) { - enc_builtin_bounds(w, cx, &bs.builtin_bounds); - - enc_region(w, cx, bs.region_bound); - - // Encode projection_bounds in a stable order - let mut projection_bounds: Vec<_> = bs.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - - for tp in projection_bounds.iter().map(|&(_, tp)| tp) { - write!(w, "P"); - enc_projection_predicate(w, cx, &tp.0); - } - - write!(w, "."); -} - pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { write!(w, "{}:{}|{}|{}|{}|", @@ -489,7 +488,9 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, } ty::Predicate::Projection(ty::Binder(ref data)) => { write!(w, "p"); - enc_projection_predicate(w, cx, data); + enc_trait_ref(w, cx, data.projection_ty.trait_ref); + write!(w, "{}|", data.projection_ty.item_name); + enc_ty(w, cx, data.ty); } ty::Predicate::WellFormed(data) => { write!(w, "w"); @@ -509,10 +510,10 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, } } -fn enc_projection_predicate<'a, 'tcx>(w: &mut Cursor>, - cx: &ctxt<'a, 'tcx>, - data: &ty::ProjectionPredicate<'tcx>) { - enc_trait_ref(w, cx, data.projection_ty.trait_ref); - write!(w, "{}|", data.projection_ty.item_name); +fn enc_existential_projection<'a, 'tcx>(w: &mut Cursor>, + cx: &ctxt<'a, 'tcx>, + data: &ty::ExistentialProjection<'tcx>) { + enc_existential_trait_ref(w, cx, data.trait_ref); + write!(w, "{}|", data.item_name); enc_ty(w, cx, data.ty); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0dcac188bb024..749a7495421ed 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -562,14 +562,9 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, // change to the vtable. old_info.expect("unsized_info: missing old info for trait upcast") } - (_, &ty::TyTrait(box ty::TraitTy { ref principal, .. })) => { - // Note that we preserve binding levels here: - let substs = principal.0.substs.with_self_ty(source).erase_regions(); - let substs = ccx.tcx().mk_substs(substs); - let trait_ref = ty::Binder(ty::TraitRef { - def_id: principal.def_id(), - substs: substs, - }); + (_, &ty::TyTrait(ref data)) => { + let trait_ref = data.principal.with_self_ty(ccx.tcx(), source); + let trait_ref = ccx.tcx().erase_regions(&trait_ref); consts::ptrcast(meth::get_vtable(ccx, trait_ref), Type::vtable_ptr(ccx)) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ffacbae1afd6f..277110347d01d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1055,8 +1055,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, assert!(!trait_ty.needs_subst() && !impl_ty.needs_subst()); if let ty::TyTrait(ref trait_ty) = trait_ty.sty { - let poly_trait_ref = trait_ty.principal_trait_ref_with_self_ty(scx.tcx(), - impl_ty); + let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty); // Walk all methods of the trait, including those of its supertraits for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 3fe8b2b66791a..6a99f12b2788c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -627,7 +627,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // But it does not describe the trait's methods. let def_id = match trait_type.sty { - ty::TyTrait(ref data) => data.principal_def_id(), + ty::TyTrait(ref data) => data.principal.def_id(), _ => { bug!("debuginfo: Unexpected trait-object type in \ trait_pointer_metadata(): {:?}", diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index c1149279b4ddd..2dd07cf440553 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -476,10 +476,10 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push(']'); }, ty::TyTrait(ref trait_data) => { - push_item_name(tcx, trait_data.principal.skip_binder().def_id, output); + push_item_name(tcx, trait_data.principal.def_id(), output); push_type_params(tcx, &trait_data.principal.skip_binder().substs.types, - &trait_data.bounds.projection_bounds, + &trait_data.projection_bounds, output); }, ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | @@ -562,7 +562,7 @@ fn push_item_name(tcx: TyCtxt, fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, types: &'tcx subst::VecPerParamSpace>, - projections: &[ty::PolyProjectionPredicate<'tcx>], + projections: &[ty::PolyExistentialProjection<'tcx>], output: &mut String) { if types.is_empty() && projections.is_empty() { return; @@ -577,7 +577,7 @@ fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for projection in projections { let projection = projection.skip_binder(); - let name = &projection.projection_ty.item_name.as_str(); + let name = &projection.item_name.as_str(); output.push_str(name); output.push_str("="); push_unique_type_name(tcx, projection.ty, output); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ea7b447632c07..ed4ea3c937b90 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -169,6 +169,11 @@ struct ConvertedBinding<'tcx> { type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); +/// Dummy type used for the `Self` of a `TraitRef` created for converting +/// a trait object, and which gets removed in `ExistentialTraitRef`. +/// This type must not appear anywhere in other converted types. +const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0)); + pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime) -> ty::Region { let r = match tcx.named_region_map.defs.get(&lifetime.id) { @@ -478,48 +483,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { type_substs.len() <= formal_ty_param_count); let mut substs = region_substs; - substs.types.extend(TypeSpace, type_substs.into_iter()); - match self_ty { - None => { - // If no self-type is provided, it's still possible that - // one was declared, because this could be an object type. - } - Some(ty) => { - // If a self-type is provided, one should have been - // "declared" (in other words, this should be a - // trait-ref). - assert!(decl_generics.types.get_self().is_some()); - substs.types.push(SelfSpace, ty); - } - } + // If a self-type was declared, one should be provided. + assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some()); + substs.types.extend(SelfSpace, self_ty.into_iter()); + substs.types.extend(TypeSpace, type_substs.into_iter()); + let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let actual_supplied_ty_param_count = substs.types.len(TypeSpace); for param in &ty_param_defs[actual_supplied_ty_param_count..] { - if let Some(default) = param.default { + let default = if let Some(default) = param.default { // If we are converting an object type, then the // `Self` parameter is unknown. However, some of the // other type parameters may reference `Self` in their // defaults. This will lead to an ICE if we are not // careful! - if self_ty.is_none() && default.has_self_ty() { + if is_object && default.has_self_ty() { span_err!(tcx.sess, span, E0393, "the type parameter `{}` must be explicitly specified \ in an object type because its default value `{}` references \ the type `Self`", param.name, default); - substs.types.push(TypeSpace, tcx.types.err); + tcx.types.err } else { // This is a default type parameter. - let default = default.subst_spanned(tcx, - &substs, - Some(span)); - substs.types.push(TypeSpace, default); + default.subst_spanned(tcx, &substs, Some(span)) } } else { span_bug!(span, "extra parameter without default"); - } + }; + substs.types.push(TypeSpace, default); } debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", @@ -539,11 +533,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self_ty: Option>) -> Vec> { + let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let use_default = |p: &ty::TypeParameterDef<'tcx>| { if let Some(ref default) = p.default { - if self_ty.is_none() && default.has_self_ty() { + if is_object && default.has_self_ty() { // There is no suitable inference default for a type parameter - // that references self with no self-type provided. + // that references self, in an object type. return false; } } @@ -709,7 +704,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn instantiate_poly_trait_ref(&self, rscope: &RegionScope, ast_trait_ref: &hir::PolyTraitRef, - self_ty: Option>, + self_ty: Ty<'tcx>, poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { @@ -734,7 +729,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn instantiate_mono_trait_ref(&self, rscope: &RegionScope, trait_ref: &hir::TraitRef, - self_ty: Option>) + self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { let trait_def_id = self.trait_def_id(trait_ref); @@ -760,32 +755,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - fn object_path_to_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - trait_def_id: DefId, - trait_path_ref_id: ast::NodeId, - trait_segment: &hir::PathSegment, - mut projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> - { - self.ast_path_to_poly_trait_ref(rscope, - span, - param_mode, - trait_def_id, - None, - trait_path_ref_id, - trait_segment, - projections) - } - fn ast_path_to_poly_trait_ref(&self, rscope: &RegionScope, span: Span, param_mode: PathParamMode, trait_def_id: DefId, - self_ty: Option>, + self_ty: Ty<'tcx>, path_id: ast::NodeId, trait_segment: &hir::PathSegment, poly_projections: &mut Vec>) @@ -808,21 +783,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { trait_segment); let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs)); - { - let converted_bindings = - assoc_bindings - .iter() - .filter_map(|binding| { - // specify type to assert that error was already reported in Err case: - let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate(path_id, - poly_trait_ref.clone(), - self_ty, - binding); - predicate.ok() // ok to ignore Err() because ErrorReported (see above) - }); - poly_projections.extend(converted_bindings); - } + poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { + // specify type to assert that error was already reported in Err case: + let predicate: Result<_, ErrorReported> = + self.ast_type_binding_to_poly_projection_predicate(path_id, + poly_trait_ref, + binding); + predicate.ok() // ok to ignore Err() because ErrorReported (see above) + })); debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", trait_segment, poly_projections, poly_trait_ref); @@ -834,7 +802,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: Span, param_mode: PathParamMode, trait_def_id: DefId, - self_ty: Option>, + self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment) -> ty::TraitRef<'tcx> { @@ -854,7 +822,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: Span, param_mode: PathParamMode, trait_def_id: DefId, - self_ty: Option>, + self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment) -> (&'tcx Substs<'tcx>, Vec>) { @@ -902,7 +870,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let substs = self.create_substs_for_ast_path(span, param_mode, &trait_def.generics, - self_ty, + Some(self_ty), types, regions); @@ -912,8 +880,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn ast_type_binding_to_poly_projection_predicate( &self, path_id: ast::NodeId, - mut trait_ref: ty::PolyTraitRef<'tcx>, - self_ty: Option>, + trait_ref: ty::PolyTraitRef<'tcx>, binding: &ConvertedBinding<'tcx>) -> Result, ErrorReported> { @@ -967,62 +934,39 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Simple case: X is defined in the current trait. if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { - return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+ - projection_ty: ty::ProjectionTy { // | - trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+ - item_name: binding.item_name, - }, - ty: binding.ty, + return Ok(trait_ref.map_bound(|trait_ref| { + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: binding.item_name, + }, + ty: binding.ty, + } })); } // Otherwise, we have to walk through the supertraits to find - // those that do. This is complicated by the fact that, for an - // object type, the `Self` type is not present in the - // substitutions (after all, it's being constructed right now), - // but the `supertraits` iterator really wants one. To handle - // this, we currently insert a dummy type and then remove it - // later. Yuck. - - let dummy_self_ty = tcx.mk_infer(ty::FreshTy(0)); - if self_ty.is_none() { // if converting for an object type - let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ - assert!(dummy_substs.self_ty().is_none()); // | - dummy_substs.types.push(SelfSpace, dummy_self_ty); // | - trait_ref = ty::Binder(ty::TraitRef::new(trait_ref.def_id(), // <------------+ - tcx.mk_substs(dummy_substs))); - } - + // those that do. self.ensure_super_predicates(binding.span, trait_ref.def_id())?; - let mut candidates: Vec = + let candidates: Vec = traits::supertraits(tcx, trait_ref.clone()) .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)) .collect(); - // If converting for an object type, then remove the dummy-ty from `Self` now. - // Yuckety yuck. - if self_ty.is_none() { - for candidate in &mut candidates { - let mut dummy_substs = candidate.0.substs.clone(); - assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); - dummy_substs.types.pop(SelfSpace); - *candidate = ty::Binder(ty::TraitRef::new(candidate.def_id(), - tcx.mk_substs(dummy_substs))); - } - } - let candidate = self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(), &binding.item_name.as_str(), binding.span)?; - Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ - projection_ty: ty::ProjectionTy { // | - trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+ - item_name: binding.item_name, - }, - ty: binding.ty, + Ok(candidate.map_bound(|trait_ref| { + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: binding.item_name, + }, + ty: binding.ty, + } })) } @@ -1059,11 +1003,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl_ty.subst(self.tcx(), &substs) } - fn ast_ty_to_trait_ref(&self, - rscope: &RegionScope, - ty: &hir::Ty, - bounds: &[hir::TyParamBound]) - -> Result, ErrorReported> + fn ast_ty_to_object_trait_ref(&self, + rscope: &RegionScope, + span: Span, + ty: &hir::Ty, + bounds: &[hir::TyParamBound]) + -> Ty<'tcx> { /*! * In a type like `Foo + Send`, we want to wait to collect the @@ -1076,33 +1021,32 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { * name, and reports an error otherwise. */ + let tcx = self.tcx(); match ty.node { hir::TyPath(None, ref path) => { - let resolution = self.tcx().expect_resolution(ty.id); + let resolution = tcx.expect_resolution(ty.id); match resolution.base_def { Def::Trait(trait_def_id) if resolution.depth == 0 => { - let mut projection_bounds = Vec::new(); - let trait_ref = - self.object_path_to_poly_trait_ref(rscope, - path.span, - PathParamMode::Explicit, - trait_def_id, - ty.id, - path.segments.last().unwrap(), - &mut projection_bounds); - Ok((trait_ref, projection_bounds)) + self.trait_path_to_object_type(rscope, + path.span, + PathParamMode::Explicit, + trait_def_id, + ty.id, + path.segments.last().unwrap(), + span, + partition_bounds(tcx, span, bounds)) } _ => { - struct_span_err!(self.tcx().sess, ty.span, E0172, + struct_span_err!(tcx.sess, ty.span, E0172, "expected a reference to a trait") .span_label(ty.span, &format!("expected a trait")) .emit(); - Err(ErrorReported) + tcx.types.err } } } _ => { - let mut err = struct_span_err!(self.tcx().sess, ty.span, E0178, + let mut err = struct_span_err!(tcx.sess, ty.span, E0178, "expected a path on the left-hand side \ of `+`, not `{}`", pprust::ty_to_string(ty)); @@ -1141,44 +1085,93 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } err.emit(); - Err(ErrorReported) + tcx.types.err } } } - fn trait_ref_to_object_type(&self, - rscope: &RegionScope, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, - bounds: &[hir::TyParamBound]) - -> Ty<'tcx> - { - let existential_bounds = self.conv_existential_bounds(rscope, - span, - trait_ref.clone(), - projection_bounds, - bounds); - - let result = self.make_object_type(span, trait_ref, existential_bounds); - debug!("trait_ref_to_object_type: result={:?}", - result); - - result + /// Transform a PolyTraitRef into a PolyExistentialTraitRef by + /// removing the dummy Self type (TRAIT_OBJECT_DUMMY_SELF). + fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>) + -> ty::ExistentialTraitRef<'tcx> { + assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF); + ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) } - fn make_object_type(&self, - span: Span, - principal: ty::PolyTraitRef<'tcx>, - bounds: ty::ExistentialBounds<'tcx>) - -> Ty<'tcx> { + fn trait_path_to_object_type(&self, + rscope: &RegionScope, + path_span: Span, + param_mode: PathParamMode, + trait_def_id: DefId, + trait_path_ref_id: ast::NodeId, + trait_segment: &hir::PathSegment, + span: Span, + partitioned_bounds: PartitionedBounds) + -> Ty<'tcx> { let tcx = self.tcx(); - let object = ty::TraitTy { - principal: principal, - bounds: bounds + + let mut projection_bounds = vec![]; + let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); + let principal = self.ast_path_to_poly_trait_ref(rscope, + path_span, + param_mode, + trait_def_id, + dummy_self, + trait_path_ref_id, + trait_segment, + &mut projection_bounds); + + let PartitionedBounds { builtin_bounds, + trait_bounds, + region_bounds } = + partitioned_bounds; + + if !trait_bounds.is_empty() { + let b = &trait_bounds[0]; + let span = b.trait_ref.path.span; + struct_span_err!(self.tcx().sess, span, E0225, + "only the builtin traits can be used as closure or object bounds") + .span_label(span, &format!("non-builtin trait used as bounds")) + .emit(); + } + + // Erase the dummy_self (TRAIT_OBJECT_DUMMY_SELF) used above. + let existential_principal = principal.map_bound(|trait_ref| { + self.trait_ref_to_existential(trait_ref) + }); + let existential_projections = projection_bounds.iter().map(|bound| { + bound.map_bound(|b| { + let p = b.projection_ty; + ty::ExistentialProjection { + trait_ref: self.trait_ref_to_existential(p.trait_ref), + item_name: p.item_name, + ty: b.ty + } + }) + }).collect(); + + let region_bound = + self.compute_object_lifetime_bound(span, + ®ion_bounds, + existential_principal, + builtin_bounds); + + let region_bound = match region_bound { + Some(r) => r, + None => { + match rscope.object_lifetime_default(span) { + Some(r) => r, + None => { + span_err!(self.tcx().sess, span, E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound"); + ty::ReStatic + } + } + } }; - let object_trait_ref = - object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + + debug!("region_bound: {:?}", region_bound); // ensure the super predicates and stop if we encountered an error if self.ensure_super_predicates(span, principal.def_id()).is_err() { @@ -1198,7 +1191,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } let mut associated_types: FnvHashSet<(DefId, ast::Name)> = - traits::supertraits(tcx, object_trait_ref) + traits::supertraits(tcx, principal) .flat_map(|tr| { let trait_def = tcx.lookup_trait_def(tr.def_id()); trait_def.associated_type_names @@ -1208,7 +1201,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }) .collect(); - for projection_bound in &object.bounds.projection_bounds { + for projection_bound in &projection_bounds { let pair = (projection_bound.0.projection_ty.trait_ref.def_id, projection_bound.0.projection_ty.item_name); associated_types.remove(&pair); @@ -1224,7 +1217,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); } - tcx.mk_trait(object.principal, object.bounds) + let ty = tcx.mk_trait(ty::TraitObject { + principal: existential_principal, + region_bound: region_bound, + builtin_bounds: builtin_bounds, + projection_bounds: existential_projections + }); + debug!("trait_object_type: {:?}", ty); + ty } fn report_ambiguous_associated_type(&self, @@ -1458,7 +1458,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span, param_mode, trait_def_id, - Some(self_ty), + self_ty, trait_segment); debug!("qpath_to_ty: trait_ref={:?}", trait_ref); @@ -1520,23 +1520,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::Trait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let mut projection_bounds = Vec::new(); - - let trait_ref = - self.object_path_to_poly_trait_ref(rscope, - span, - param_mode, - trait_def_id, - base_path_ref_id, - base_segments.last().unwrap(), - &mut projection_bounds); tcx.prohibit_type_params(base_segments.split_last().unwrap().1); - self.trait_ref_to_object_type(rscope, - span, - trait_ref, - projection_bounds, - &[]) + + self.trait_path_to_object_type(rscope, + span, + param_mode, + trait_def_id, + base_path_ref_id, + base_segments.last().unwrap(), + span, + partition_bounds(tcx, span, &[])) } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { tcx.prohibit_type_params(base_segments.split_last().unwrap().1); @@ -1676,18 +1670,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) } hir::TyObjectSum(ref ty, ref bounds) => { - match self.ast_ty_to_trait_ref(rscope, &ty, bounds) { - Ok((trait_ref, projection_bounds)) => { - self.trait_ref_to_object_type(rscope, - ast_ty.span, - trait_ref, - projection_bounds, - bounds) - } - Err(ErrorReported) => { - self.tcx().types.err - } - } + self.ast_ty_to_object_trait_ref(rscope, ast_ty.span, ty, bounds) } hir::TyPtr(ref mt) => { tcx.mk_ptr(ty::TypeAndMut { @@ -1764,7 +1747,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.mk_fn_ptr(bare_fn_ty) } hir::TyPolyTraitRef(ref bounds) => { - self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds) + self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds) } hir::TyImplTrait(ref bounds) => { use collect::{compute_bounds, SizedByDefault}; @@ -2091,28 +2074,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - /// Given an existential type like `Foo+'a+Bar`, this routine converts - /// the `'a` and `Bar` intos an `ExistentialBounds` struct. - /// The `main_trait_refs` argument specifies the `Foo` -- it is absent - /// for closures. Eventually this should all be normalized, I think, - /// so that there is no "main trait ref" and instead we just have a flat - /// list of bounds as the existential type. - fn conv_existential_bounds(&self, - rscope: &RegionScope, - span: Span, - principal_trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, - ast_bounds: &[hir::TyParamBound]) - -> ty::ExistentialBounds<'tcx> - { - let partitioned_bounds = - partition_bounds(self.tcx(), span, ast_bounds); - - self.conv_existential_bounds_from_partitioned_bounds( - rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) - } - - fn conv_ty_poly_trait_ref(&self, + fn conv_object_ty_poly_trait_ref(&self, rscope: &RegionScope, span: Span, ast_bounds: &[hir::TyParamBound]) @@ -2120,75 +2082,24 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { { let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]); - let mut projection_bounds = Vec::new(); - let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { - let trait_bound = partitioned_bounds.trait_bounds.remove(0); - self.instantiate_poly_trait_ref(rscope, - trait_bound, - None, - &mut projection_bounds) + let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { + partitioned_bounds.trait_bounds.remove(0) } else { span_err!(self.tcx().sess, span, E0224, "at least one non-builtin trait is required for an object type"); return self.tcx().types.err; }; - let bounds = - self.conv_existential_bounds_from_partitioned_bounds(rscope, - span, - main_trait_bound.clone(), - projection_bounds, - partitioned_bounds); - - self.make_object_type(span, main_trait_bound, bounds) - } - - pub fn conv_existential_bounds_from_partitioned_bounds(&self, - rscope: &RegionScope, - span: Span, - principal_trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, // Empty for boxed closures - partitioned_bounds: PartitionedBounds) - -> ty::ExistentialBounds<'tcx> - { - let PartitionedBounds { builtin_bounds, - trait_bounds, - region_bounds } = - partitioned_bounds; - - if !trait_bounds.is_empty() { - let b = &trait_bounds[0]; - let span = b.trait_ref.path.span; - struct_span_err!(self.tcx().sess, span, E0225, - "only the builtin traits can be used as closure or object bounds") - .span_label(span, &format!("non-builtin trait used as bounds")) - .emit(); - } - - let region_bound = - self.compute_object_lifetime_bound(span, - ®ion_bounds, - principal_trait_ref, - builtin_bounds); - - let region_bound = match region_bound { - Some(r) => r, - None => { - match rscope.object_lifetime_default(span) { - Some(r) => r, - None => { - span_err!(self.tcx().sess, span, E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound"); - ty::ReStatic - } - } - } - }; - - debug!("region_bound: {:?}", region_bound); - - ty::ExistentialBounds::new(region_bound, builtin_bounds, projection_bounds) + let trait_ref = &trait_bound.trait_ref; + let trait_def_id = self.trait_def_id(trait_ref); + self.trait_path_to_object_type(rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + trait_ref.ref_id, + trait_ref.path.segments.last().unwrap(), + span, + partitioned_bounds) } /// Given the bounds on an object, determines what single region bound (if any) we can @@ -2199,7 +2110,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn compute_object_lifetime_bound(&self, span: Span, explicit_region_bounds: &[&hir::Lifetime], - principal_trait_ref: ty::PolyTraitRef<'tcx>, + principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>, builtin_bounds: ty::BuiltinBounds) -> Option // if None, use the default { @@ -2230,7 +2141,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // No explicit region bound specified. Therefore, examine trait // bounds and see if we can derive region bounds from those. let derived_region_bounds = - object_region_bounds(tcx, &principal_trait_ref, builtin_bounds); + object_region_bounds(tcx, principal_trait_ref, builtin_bounds); // If there are no derived region bounds, then report back that we // can find no region bound. The caller will use the default. diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 7a4cc09a7d506..fb78d3a37ca23 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -78,7 +78,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn unsize_kind(&self, t: Ty<'tcx>) -> Option> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), - ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), + ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal.def_id())), ty::TyStruct(def, substs) => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 3acb8017eec50..8a007293e64ff 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -102,12 +102,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match expected_ty.sty { ty::TyTrait(ref object_type) => { - let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx, - self.tcx.types.err); - let sig = proj_bounds.iter() - .filter_map(|pb| self.deduce_sig_from_projection(pb)) - .next(); - let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal_def_id()); + let sig = object_type.projection_bounds.iter().filter_map(|pb| { + let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); + self.deduce_sig_from_projection(&pb) + }).next(); + let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal.def_id()); (sig, kind) } ty::TyInfer(ty::TyVar(vid)) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index d1d7259955576..250bf9265d1a4 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { probe::ObjectPick => { let trait_def_id = pick.item.container().id(); - self.extract_trait_ref(self_ty, |this, object_ty, data| { + self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| { // The object data has no entry for the Self // Type. For the purposes of this method call, we // substitute the object type itself. This @@ -222,9 +222,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // been ruled out when we deemed the trait to be // "object safe". let original_poly_trait_ref = - data.principal_trait_ref_with_self_ty(this.tcx, object_ty); + principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = - this.upcast(original_poly_trait_ref.clone(), trait_def_id); + this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref); debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", @@ -276,8 +276,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } } - fn extract_trait_ref(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R where - F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>, Ty<'tcx>, &ty::TraitTy<'tcx>) -> R, + fn extract_existential_trait_ref(&mut self, + self_ty: Ty<'tcx>, + mut closure: F) -> R + where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>, + Ty<'tcx>, + ty::PolyExistentialTraitRef<'tcx>) -> R, { // If we specified that this is an object method, then the // self-type ought to be something that can be dereferenced to @@ -288,7 +292,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { self.fcx.autoderef(self.span, self_ty) .filter_map(|(ty, _)| { match ty.sty { - ty::TyTrait(ref data) => Some(closure(self, ty, &data)), + ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)), _ => None, } }) @@ -331,9 +335,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - let type_defs = method.generics.types.as_full_slice(); - let region_defs = method.generics.regions.as_full_slice(); - subst::Substs::from_param_defs(region_defs, type_defs, |def| { + subst::Substs::from_generics(&method.generics, |def, _| { if def.space != subst::FnSpace { substs.region_for_def(def) } else { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 532a5c0de4e46..ff34f37bde0dd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -189,9 +189,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(trait_def.generics.regions.is_empty()); // Construct a trait-reference `self_ty : Trait` - let type_defs = trait_def.generics.types.as_full_slice(); - let region_defs = trait_def.generics.regions.as_full_slice(); - let substs = subst::Substs::from_param_defs(region_defs, type_defs, |def| { + let substs = subst::Substs::from_generics(&trait_def.generics, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { if def.space == subst::SelfSpace { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 44e371482c55c..f6ac3235cf33e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -290,8 +290,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { match self_ty.sty { ty::TyTrait(box ref data) => { - self.assemble_inherent_candidates_from_object(self_ty, data); - self.assemble_inherent_impl_candidates_for_type(data.principal_def_id()); + self.assemble_inherent_candidates_from_object(self_ty, data.principal); + self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } ty::TyEnum(def, _) | ty::TyStruct(def, _) => { @@ -445,7 +445,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>, - data: &ty::TraitTy<'tcx>) { + principal: ty::PolyExistentialTraitRef<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); @@ -456,7 +456,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // a substitution that replaces `Self` with the object type // itself. Hence, a `&self` method will wind up with an // argument type like `&Trait`. - let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx, self_ty); + let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); @@ -1227,15 +1227,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return impl_ty; } - let placeholder; - let mut substs = substs; - if - !method.generics.types.is_empty_in(subst::FnSpace) || - !method.generics.regions.is_empty_in(subst::FnSpace) - { - let type_defs = method.generics.types.as_full_slice(); - let region_defs = method.generics.regions.as_full_slice(); - placeholder = subst::Substs::from_param_defs(region_defs, type_defs, |def| { + // Erase any late-bound regions from the method and substitute + // in the values from the substitution. + let xform_self_ty = method.fty.sig.input(0); + let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty); + + if method.generics.types.is_empty_in(subst::FnSpace) && + method.generics.regions.is_empty_in(subst::FnSpace) { + xform_self_ty.subst(self.tcx, substs) + } else { + let substs = subst::Substs::from_generics(&method.generics, |def, _| { if def.space != subst::FnSpace { substs.region_for_def(def) } else { @@ -1250,16 +1251,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.type_var_for_def(self.span, def, cur_substs) } }); - substs = &placeholder; + xform_self_ty.subst(self.tcx, &substs) } - - // Erase any late-bound regions from the method and substitute - // in the values from the substitution. - let xform_self_ty = method.fty.sig.input(0); - let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty); - let xform_self_ty = xform_self_ty.subst(self.tcx, substs); - - xform_self_ty } /// Get the type of an impl and generate substitutions with placeholders. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 54521782474fe..dc6fa334b74fc 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -358,7 +358,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match ty.sty { ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), - ty::TyTrait(ref tr) => tr.principal_def_id().is_local(), + ty::TyTrait(ref tr) => tr.principal.def_id().is_local(), ty::TyParam(_) => true, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6f3d48282e25c..8e34b0b8c5559 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -824,11 +824,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } /*From:*/ (_, - /*To: */ &ty::TyTrait(box ty::TraitTy { ref bounds, .. })) => { + /*To: */ &ty::TyTrait(ref obj)) => { // When T is existentially quantified as a trait // `Foo+'to`, it must outlive the region bound `'to`. self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), - from_ty, bounds.region_bound); + from_ty, obj.region_bound); } /*From:*/ (&ty::TyBox(from_referent_ty), diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 9b26e95f7fa55..485e744bf916e 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -75,7 +75,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } TyTrait(ref t) => { - Some(t.principal_def_id()) + Some(t.principal.def_id()) } TyBox(_) => { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index e426f0cb643b7..97aed4d5e82f9 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -80,7 +80,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { - self.check_def_id(item, data.principal_def_id()); + self.check_def_id(item, data.principal.def_id()); } ty::TyBox(..) => { match self.tcx.lang_items.require_owned_box() { diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 46a9ef8d5babb..f60fb9583a661 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -168,14 +168,14 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { // This is something like impl Trait1 for Trait2. Illegal // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. - if !self.tcx.is_object_safe(data.principal_def_id()) { + if !self.tcx.is_object_safe(data.principal.def_id()) { // This is an error, but it will be // reported by wfcheck. Ignore it // here. This is tested by // `coherence-impl-trait-for-trait-object-safe.rs`. } else { let mut supertrait_def_ids = - traits::supertrait_def_ids(self.tcx, data.principal_def_id()); + traits::supertrait_def_ids(self.tcx, data.principal.def_id()); if supertrait_def_ids.any(|d| d == trait_def_id) { span_err!(self.tcx.sess, item.span, E0371, "the object type `{}` automatically \ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0ddc051d4a868..a2a162a7f5f74 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -722,7 +722,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { AstConv::instantiate_mono_trait_ref(&ccx.icx(&()), &ExplicitRscope, ast_trait_ref, - None); + tcx.mk_self_type()); tcx.record_trait_has_default_impl(trait_ref.def_id); @@ -752,7 +752,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), &ExplicitRscope, ast_trait_ref, - Some(selfty)) + selfty) }); tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); @@ -1815,10 +1815,12 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let mut projections = Vec::new(); let trait_ref = - conv_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)), - ty, - poly_trait_ref, - &mut projections); + AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates, + ast_generics)), + &ExplicitRscope, + poly_trait_ref, + ty, + &mut projections); result.predicates.push(trait_ref.to_predicate()); @@ -2069,7 +2071,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| { astconv.instantiate_poly_trait_ref(&rscope, bound, - Some(param_ty), + param_ty, &mut projection_bounds) }).collect(); @@ -2100,7 +2102,10 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, match *bound { hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => { let mut projections = Vec::new(); - let pred = conv_poly_trait_ref(astconv, param_ty, tr, &mut projections); + let pred = astconv.instantiate_poly_trait_ref(&ExplicitRscope, + tr, + param_ty, + &mut projections); projections.into_iter() .map(|p| p.to_predicate()) .chain(Some(pred.to_predicate())) @@ -2117,19 +2122,6 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, } } -fn conv_poly_trait_ref<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - param_ty: Ty<'tcx>, - trait_ref: &hir::PolyTraitRef, - projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> -{ - AstConv::instantiate_poly_trait_ref(astconv, - &ExplicitRscope, - trait_ref, - Some(param_ty), - projections) -} - fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, id: DefId, diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 50c568cfef8f6..6e6f9ce65c50f 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -396,19 +396,16 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyTrait(ref data) => { let poly_trait_ref = - data.principal_trait_ref_with_self_ty(self.tcx(), - self.tcx().types.err); + data.principal.with_self_ty(self.tcx(), self.tcx().types.err); // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); - self.add_constraints_from_region(generics, data.bounds.region_bound, contra); + self.add_constraints_from_region(generics, data.region_bound, contra); // Ignore the SelfSpace, it is erased. self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance); - let projections = data.projection_bounds_with_self_ty(self.tcx(), - self.tcx().types.err); - for projection in &projections { + for projection in &data.projection_bounds { self.add_constraints_from_ty(generics, projection.0.ty, self.invariant); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 284e0d4dbddf3..ffe5b9aad2fb3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -630,26 +630,6 @@ impl Clean for hir::TyParamBound { } } -impl<'tcx> Clean<(Vec, Vec)> for ty::ExistentialBounds<'tcx> { - fn clean(&self, cx: &DocContext) -> (Vec, Vec) { - let mut tp_bounds = vec![]; - self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b))); - for bb in &self.builtin_bounds { - tp_bounds.push(bb.clean(cx)); - } - - let mut bindings = vec![]; - for &ty::Binder(ref pb) in &self.projection_bounds { - bindings.push(TypeBinding { - name: pb.projection_ty.item_name.clean(cx), - ty: pb.ty.clean(cx) - }); - } - - (tp_bounds, bindings) - } -} - fn external_path_params(cx: &DocContext, trait_did: Option, bindings: Vec, substs: &subst::Substs) -> PathParameters { let lifetimes = substs.regions.get_slice(subst::TypeSpace) @@ -1848,12 +1828,26 @@ impl<'tcx> Clean for ty::Ty<'tcx> { is_generic: false, } } - ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => { - let did = principal.def_id(); + ty::TyTrait(ref obj) => { + let did = obj.principal.def_id(); inline::record_extern_fqn(cx, did, TypeTrait); - let (typarams, bindings) = bounds.clean(cx); + + let mut typarams = vec![]; + obj.region_bound.clean(cx).map(|b| typarams.push(RegionBound(b))); + for bb in &obj.builtin_bounds { + typarams.push(bb.clean(cx)); + } + + let mut bindings = vec![]; + for &ty::Binder(ref pb) in &obj.projection_bounds { + bindings.push(TypeBinding { + name: pb.item_name.clean(cx), + ty: pb.ty.clean(cx) + }); + } + let path = external_path(cx, &cx.tcx().item_name(did).as_str(), - Some(did), bindings, principal.substs()); + Some(did), bindings, obj.principal.0.substs); ResolvedPath { path: path, typarams: Some(typarams), From bfdfa1ce1d7275bbdb89ecb116bf765f19b204e1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 04:05:00 +0300 Subject: [PATCH 066/768] rustc_typeck: use Substs::from_generics instead of manually building them. --- src/librustc/infer/mod.rs | 7 - src/librustc_typeck/astconv.rs | 379 ++++++++++-------------- src/librustc_typeck/check/mod.rs | 445 ++++++++++------------------- src/librustc_typeck/diagnostics.rs | 4 +- 4 files changed, 300 insertions(+), 535 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 951570679e08e..1e360cd43da12 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1234,13 +1234,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(ty_var_id) } - pub fn region_vars_for_defs(&self, - span: Span, - defs: &[ty::RegionParameterDef]) - -> Vec { - defs.iter().map(|def| self.region_var_for_def(span, def)).collect() - } - /// Given a set of generics defined on a type or impl, returns a substitution mapping each /// type/region parameter to a fresh inference variable. pub fn fresh_substs_for_generics(&self, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ed4ea3c937b90..11ca012fdedab 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use hir::def_id::DefId; use hir::print as pprust; use middle::resolve_lifetime as rl; use rustc::lint; -use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; +use rustc::ty::subst::{TypeSpace, SelfSpace, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -350,64 +350,77 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { param_mode: PathParamMode, decl_generics: &ty::Generics<'tcx>, item_segment: &hir::PathSegment) - -> Substs<'tcx> + -> &'tcx Substs<'tcx> { let tcx = self.tcx(); - // ast_path_substs() is only called to convert paths that are - // known to refer to traits, types, or structs. In these cases, - // all type parameters defined for the item being referenced will - // be in the TypeSpace or SelfSpace. - // - // Note: in the case of traits, the self parameter is also - // defined, but we don't currently create a `type_param_def` for - // `Self` because it is implicit. - assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); - assert!(decl_generics.types.all(|d| d.space != FnSpace)); - - let (regions, types, assoc_bindings) = match item_segment.parameters { - hir::AngleBracketedParameters(ref data) => { - self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data) - } + match item_segment.parameters { + hir::AngleBracketedParameters(_) => {} hir::ParenthesizedParameters(..) => { struct_span_err!(tcx.sess, span, E0214, "parenthesized parameters may only be used with a trait") .span_label(span, &format!("only traits may use parentheses")) .emit(); - let ty_param_defs = decl_generics.types.get_slice(TypeSpace); - (Substs::empty(), - ty_param_defs.iter().map(|_| tcx.types.err).collect(), - vec![]) + return tcx.mk_substs(Substs::from_generics(decl_generics, |_, _| { + ty::ReStatic + }, |_, _| { + tcx.types.err + })); } - }; + } + + let (substs, assoc_bindings) = + self.create_substs_for_ast_path(rscope, + span, + param_mode, + decl_generics, + &item_segment.parameters, + None); assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); - self.create_substs_for_ast_path(span, - param_mode, - decl_generics, - None, - types, - regions) + substs } - fn create_region_substs(&self, + /// Given the type/region arguments provided to some path (along with + /// an implicit Self, if this is a trait reference) returns the complete + /// set of substitutions. This may involve applying defaulted type parameters. + /// + /// Note that the type listing given here is *exactly* what the user provided. + fn create_substs_for_ast_path(&self, rscope: &RegionScope, span: Span, + param_mode: PathParamMode, decl_generics: &ty::Generics<'tcx>, - regions_provided: Vec) - -> Substs<'tcx> + parameters: &hir::PathParameters, + self_ty: Option>) + -> (&'tcx Substs<'tcx>, Vec>) { let tcx = self.tcx(); + debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ + parameters={:?})", + decl_generics, self_ty, parameters); + + let (lifetimes, num_types_provided) = match *parameters { + hir::AngleBracketedParameters(ref data) => { + if param_mode == PathParamMode::Optional && data.types.is_empty() { + (&data.lifetimes[..], None) + } else { + (&data.lifetimes[..], Some(data.types.len())) + } + } + hir::ParenthesizedParameters(_) => (&[][..], Some(1)) + }; + // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). let expected_num_region_params = decl_generics.regions.len(TypeSpace); - let supplied_num_region_params = regions_provided.len(); + let supplied_num_region_params = lifetimes.len(); let regions = if expected_num_region_params == supplied_num_region_params { - regions_provided + lifetimes.iter().map(|l| ast_region_to_region(tcx, l)).collect() } else { let anon_regions = rscope.anon_regions(span, expected_num_region_params); @@ -423,176 +436,111 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect() } }; - Substs::new_type(vec![], regions) - } - /// Given the type/region arguments provided to some path (along with - /// an implicit Self, if this is a trait reference) returns the complete - /// set of substitutions. This may involve applying defaulted type parameters. - /// - /// Note that the type listing given here is *exactly* what the user provided. - /// - /// The `region_substs` should be the result of `create_region_substs` - /// -- that is, a substitution with no types but the correct number of - /// regions. - fn create_substs_for_ast_path(&self, - span: Span, - param_mode: PathParamMode, - decl_generics: &ty::Generics<'tcx>, - self_ty: Option>, - types_provided: Vec>, - region_substs: Substs<'tcx>) - -> Substs<'tcx> - { - let tcx = self.tcx(); + // If a self-type was declared, one should be provided. + assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some()); - debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ - types_provided={:?}, region_substs={:?})", - decl_generics, self_ty, types_provided, - region_substs); - - assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace)); - assert!(region_substs.types.is_empty()); - - // Convert the type parameters supplied by the user. - let ty_param_defs = decl_generics.types.get_slice(TypeSpace); - let formal_ty_param_count = ty_param_defs.len(); - let required_ty_param_count = ty_param_defs.iter() - .take_while(|x| x.default.is_none()) - .count(); - - let mut type_substs = self.get_type_substs_for_defs(span, - types_provided, - param_mode, - ty_param_defs, - region_substs.clone(), - self_ty); - - let supplied_ty_param_count = type_substs.len(); - check_type_argument_count(self.tcx(), span, supplied_ty_param_count, - required_ty_param_count, formal_ty_param_count); - - if supplied_ty_param_count < required_ty_param_count { - while type_substs.len() < required_ty_param_count { - type_substs.push(tcx.types.err); - } - } else if supplied_ty_param_count > formal_ty_param_count { - type_substs.truncate(formal_ty_param_count); + // Check the number of type parameters supplied by the user. + if let Some(num_provided) = num_types_provided { + let ty_param_defs = decl_generics.types.get_slice(TypeSpace); + check_type_argument_count(tcx, span, num_provided, ty_param_defs); } - assert!(type_substs.len() >= required_ty_param_count && - type_substs.len() <= formal_ty_param_count); - let mut substs = region_substs; + let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); + let default_needs_object_self = |p: &ty::TypeParameterDef<'tcx>| { + if let Some(ref default) = p.default { + if is_object && default.has_self_ty() { + // There is no suitable inference default for a type parameter + // that references self, in an object type. + return true; + } + } - // If a self-type was declared, one should be provided. - assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some()); - substs.types.extend(SelfSpace, self_ty.into_iter()); - substs.types.extend(TypeSpace, type_substs.into_iter()); + false + }; + + let mut output_assoc_binding = None; + let substs = Substs::from_generics(decl_generics, |def, _| { + assert_eq!(def.space, TypeSpace); + regions[def.index as usize] + }, |def, substs| { + assert!(def.space == SelfSpace || def.space == TypeSpace); + let i = def.index as usize; + if def.space == SelfSpace { + // Self, which must have been provided. + assert_eq!(i, 0); + self_ty.expect("Self type parameter missing") + } else if num_types_provided.map_or(false, |n| i < n) { + // A provided type parameter. + match *parameters { + hir::AngleBracketedParameters(ref data) => { + self.ast_ty_arg_to_ty(rscope, Some(def), substs, &data.types[i]) + } + hir::ParenthesizedParameters(ref data) => { + assert_eq!(i, 0); + let (ty, assoc) = + self.convert_parenthesized_parameters(rscope, substs, data); + output_assoc_binding = Some(assoc); + ty + } + } + } else if num_types_provided.is_none() { + // No type parameters were provided, we can infer all. + let ty_var = if !default_needs_object_self(def) { + self.ty_infer_for_def(def, substs, span) + } else { + self.ty_infer(span) + }; + ty_var + } else if let Some(default) = def.default { + // No type parameter provided, but a default exists. - let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); - let actual_supplied_ty_param_count = substs.types.len(TypeSpace); - for param in &ty_param_defs[actual_supplied_ty_param_count..] { - let default = if let Some(default) = param.default { // If we are converting an object type, then the // `Self` parameter is unknown. However, some of the // other type parameters may reference `Self` in their // defaults. This will lead to an ICE if we are not // careful! - if is_object && default.has_self_ty() { + if default_needs_object_self(def) { span_err!(tcx.sess, span, E0393, "the type parameter `{}` must be explicitly specified \ in an object type because its default value `{}` references \ the type `Self`", - param.name, + def.name, default); tcx.types.err } else { // This is a default type parameter. - default.subst_spanned(tcx, &substs, Some(span)) + default.subst_spanned(tcx, substs, Some(span)) } } else { - span_bug!(span, "extra parameter without default"); - }; - substs.types.push(TypeSpace, default); - } - - debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", - decl_generics, self_ty, substs); - - substs - } - - /// Returns types_provided if it is not empty, otherwise populating the - /// type parameters with inference variables as appropriate. - fn get_type_substs_for_defs(&self, - span: Span, - types_provided: Vec>, - param_mode: PathParamMode, - ty_param_defs: &[ty::TypeParameterDef<'tcx>], - mut substs: Substs<'tcx>, - self_ty: Option>) - -> Vec> - { - let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); - let use_default = |p: &ty::TypeParameterDef<'tcx>| { - if let Some(ref default) = p.default { - if is_object && default.has_self_ty() { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return false; - } + // We've already errored above about the mismatch. + tcx.types.err } + }); - true + let assoc_bindings = match *parameters { + hir::AngleBracketedParameters(ref data) => { + data.bindings.iter().map(|b| { + ConvertedBinding { + item_name: b.name, + ty: self.ast_ty_to_ty(rscope, &b.ty), + span: b.span + } + }).collect() + } + hir::ParenthesizedParameters(ref data) => { + vec![output_assoc_binding.unwrap_or_else(|| { + // This is an error condition, but we should + // get the associated type binding anyway. + self.convert_parenthesized_parameters(rscope, &substs, data).1 + })] + } }; - if param_mode == PathParamMode::Optional && types_provided.is_empty() { - ty_param_defs.iter().map(|def| { - let ty_var = if use_default(def) { - self.ty_infer_for_def(def, &substs, span) - } else { - self.ty_infer(span) - }; - substs.types.push(def.space, ty_var); - ty_var - }).collect() - } else { - types_provided - } - } + debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", + decl_generics, self_ty, substs); - fn convert_angle_bracketed_parameters(&self, - rscope: &RegionScope, - span: Span, - decl_generics: &ty::Generics<'tcx>, - data: &hir::AngleBracketedParameterData) - -> (Substs<'tcx>, - Vec>, - Vec>) - { - let regions: Vec<_> = - data.lifetimes.iter() - .map(|l| ast_region_to_region(self.tcx(), l)) - .collect(); - - let region_substs = - self.create_region_substs(rscope, span, decl_generics, regions); - - let types: Vec<_> = - data.types.iter() - .enumerate() - .map(|(i,t)| self.ast_ty_arg_to_ty(rscope, decl_generics, - i, ®ion_substs, t)) - .collect(); - - let assoc_bindings: Vec<_> = - data.bindings.iter() - .map(|b| ConvertedBinding { item_name: b.name, - ty: self.ast_ty_to_ty(rscope, &b.ty), - span: b.span }) - .collect(); - - (region_substs, types, assoc_bindings) + (tcx.mk_substs(substs), assoc_bindings) } /// Returns the appropriate lifetime to use for any output lifetimes @@ -657,29 +605,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn convert_parenthesized_parameters(&self, rscope: &RegionScope, - span: Span, - decl_generics: &ty::Generics<'tcx>, + region_substs: &Substs<'tcx>, data: &hir::ParenthesizedParameterData) - -> (Substs<'tcx>, - Vec>, - Vec>) + -> (Ty<'tcx>, ConvertedBinding<'tcx>) { - let region_substs = - self.create_region_substs(rscope, span, decl_generics, Vec::new()); - let anon_scope = rscope.anon_type_scope(); let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope); - let inputs = - data.inputs.iter() - .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics, - 0, ®ion_substs, a_t)) - .collect::>>(); - + let inputs: Vec<_> = data.inputs.iter().map(|a_t| { + self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t) + }).collect(); let input_params = vec![String::new(); inputs.len()]; let implied_output_region = self.find_implied_output_region(&inputs, input_params); - let input_ty = self.tcx().mk_tup(inputs); - let (output, output_span) = match data.output { Some(ref output_ty) => { (self.convert_ty_with_lifetime_elision(implied_output_region, @@ -698,7 +635,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: output_span }; - (region_substs, vec![input_ty], vec![output_binding]) + (self.tcx().mk_tup(inputs), output_binding) } pub fn instantiate_poly_trait_ref(&self, @@ -838,8 +775,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }; - let (regions, types, assoc_bindings) = match trait_segment.parameters { - hir::AngleBracketedParameters(ref data) => { + match trait_segment.parameters { + hir::AngleBracketedParameters(_) => { // For now, require that parenthetical notation be used // only with `Fn()` etc. if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar { @@ -850,10 +787,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { type parameters is subject to change. \ Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead"); } - - self.convert_angle_bracketed_parameters(rscope, span, &trait_def.generics, data) } - hir::ParenthesizedParameters(ref data) => { + hir::ParenthesizedParameters(_) => { // For now, require that parenthetical notation be used // only with `Fn()` etc. if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar { @@ -862,19 +797,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { "\ parenthetical notation is only stable when used with `Fn`-family traits"); } - - self.convert_parenthesized_parameters(rscope, span, &trait_def.generics, data) } - }; - - let substs = self.create_substs_for_ast_path(span, - param_mode, - &trait_def.generics, - Some(self_ty), - types, - regions); + } - (self.tcx().mk_substs(substs), assoc_bindings) + self.create_substs_for_ast_path(rscope, + span, + param_mode, + &trait_def.generics, + &trait_segment.parameters, + Some(self_ty)) } fn ast_type_binding_to_poly_projection_predicate( @@ -1000,7 +931,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { return self.tcx().mk_box(*substs.types.get(TypeSpace, 0)); } - decl_ty.subst(self.tcx(), &substs) + decl_ty.subst(self.tcx(), substs) } fn ast_ty_to_object_trait_ref(&self, @@ -1473,24 +1404,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// # Parameters /// /// * `this`, `rscope`: the surrounding context - /// * `decl_generics`: the generics of the struct/enum/trait declaration being - /// referenced - /// * `index`: the index of the type parameter being instantiated from the list - /// (we assume it is in the `TypeSpace`) + /// * `def`: the type parameter being instantiated (if available) /// * `region_substs`: a partial substitution consisting of /// only the region type parameters being supplied to this type. /// * `ast_ty`: the ast representation of the type being supplied - pub fn ast_ty_arg_to_ty(&self, - rscope: &RegionScope, - decl_generics: &ty::Generics<'tcx>, - index: usize, - region_substs: &Substs<'tcx>, - ast_ty: &hir::Ty) - -> Ty<'tcx> + fn ast_ty_arg_to_ty(&self, + rscope: &RegionScope, + def: Option<&ty::TypeParameterDef<'tcx>>, + region_substs: &Substs<'tcx>, + ast_ty: &hir::Ty) + -> Ty<'tcx> { let tcx = self.tcx(); - if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) { + if let Some(def) = def { let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs); let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default); self.ast_ty_to_ty(rscope1, ast_ty) @@ -2194,7 +2121,7 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, let parameters = &segments[segments.len() - 1].parameters; if !parameters.types().is_empty() { check_type_argument_count(tcx, b.trait_ref.path.span, - parameters.types().len(), 0, 0); + parameters.types().len(), &[]); } if !parameters.lifetimes().is_empty() { report_lifetime_number_error(tcx, b.trait_ref.path.span, @@ -2225,7 +2152,9 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, } fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, - required: usize, accepted: usize) { + ty_param_defs: &[ty::TypeParameterDef]) { + let accepted = ty_param_defs.len(); + let required = ty_param_defs.iter().take_while(|x| x.default.is_none()) .count(); if supplied < required { let expected = if required < accepted { "expected at least" diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b5018d51b7f56..c41bb1930d458 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,7 +88,7 @@ use hir::def::{Def, PathResolution}; use hir::def_id::DefId; use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; -use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace}; +use rustc::ty::subst::{self, Subst, Substs}; use rustc::traits::{self, Reveal}; use rustc::ty::{GenericPredicates, TypeScheme}; use rustc::ty::{ParamTy, ParameterEnvironment}; @@ -1702,7 +1702,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { PathParamMode::Optional, &type_scheme.generics, path.segments.last().unwrap()); - let substs = self.tcx.mk_substs(substs); debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.ty, substs); let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); let cause = traits::ObligationCause::new(path.span, self.body_id, @@ -4158,7 +4157,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(!segments.is_empty()); let mut ufcs_associated = None; - let mut segment_spaces: Vec<_>; + let mut type_segment = None; + let mut fn_segment = None; match def { // Case 1 and 1b. Reference to a *type* or *enum variant*. Def::SelfTy(..) | @@ -4172,40 +4172,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::TyParam(..) => { // Everything but the final segment should have no // parameters at all. - segment_spaces = vec![None; segments.len() - 1]; - segment_spaces.push(Some(subst::TypeSpace)); + type_segment = segments.last(); } // Case 2. Reference to a top-level value. Def::Fn(..) | Def::Const(..) | Def::Static(..) => { - segment_spaces = vec![None; segments.len() - 1]; - segment_spaces.push(Some(subst::FnSpace)); - } - - // Case 3. Reference to a method. - Def::Method(def_id) => { - let container = self.tcx.impl_or_trait_item(def_id).container(); - match container { - ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) - } - ty::ImplContainer(_) => {} - } - - if segments.len() >= 2 { - segment_spaces = vec![None; segments.len() - 2]; - segment_spaces.push(Some(subst::TypeSpace)); - segment_spaces.push(Some(subst::FnSpace)); - } else { - // `::method` will end up here, and so can `T::method`. - let self_ty = opt_self_ty.expect("UFCS sugared method missing Self"); - segment_spaces = vec![Some(subst::FnSpace)]; - ufcs_associated = Some((container, self_ty)); - } + fn_segment = segments.last(); } + // Case 3. Reference to a method or associated const. + Def::Method(def_id) | Def::AssociatedConst(def_id) => { let container = self.tcx.impl_or_trait_item(def_id).container(); match container { @@ -4216,15 +4194,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if segments.len() >= 2 { - segment_spaces = vec![None; segments.len() - 2]; - segment_spaces.push(Some(subst::TypeSpace)); - segment_spaces.push(None); + type_segment = Some(&segments[segments.len() - 2]); } else { - // `::CONST` will end up here, and so can `T::CONST`. - let self_ty = opt_self_ty.expect("UFCS sugared const missing Self"); - segment_spaces = vec![None]; + // `::assoc` will end up here, and so can `T::assoc`. + let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self"); ufcs_associated = Some((container, self_ty)); } + fn_segment = segments.last(); } // Other cases. Various nonsense that really shouldn't show up @@ -4234,51 +4210,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::ForeignMod(..) | Def::Local(..) | Def::Label(..) | - Def::Upvar(..) => { - segment_spaces = vec![None; segments.len()]; - } + Def::Upvar(..) => {} Def::Err => { self.set_tainted_by_errors(); - segment_spaces = vec![None; segments.len()]; } } - assert_eq!(segment_spaces.len(), segments.len()); // In `>::method`, `A` and `B` are mandatory, but // `opt_self_ty` can also be Some for `Foo::method`, where Foo's // type parameters are not mandatory. let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none(); - debug!("segment_spaces={:?}", segment_spaces); - - // Next, examine the definition, and determine how many type - // parameters we expect from each space. - let type_defs = &type_scheme.generics.types; - let region_defs = &type_scheme.generics.regions; + debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment); // Now that we have categorized what space the parameters for each // segment belong to, let's sort out the parameters that the user // provided (if any) into their appropriate spaces. We'll also report // errors if type parameters are provided in an inappropriate place. - let mut substs = Substs::empty(); - for (&opt_space, segment) in segment_spaces.iter().zip(segments) { - if let Some(space) = opt_space { - self.push_explicit_parameters_from_segment_to_substs(space, - span, - type_defs, - region_defs, - segment, - &mut substs); - } else { - self.tcx.prohibit_type_params(slice::ref_slice(segment)); - } - } - if let Some(self_ty) = opt_self_ty { - if type_defs.len(subst::SelfSpace) == 1 { - substs.types.push(subst::SelfSpace, self_ty); - } - } + let poly_segments = type_segment.is_some() as usize + + fn_segment.is_some() as usize; + self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]); // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user @@ -4286,19 +4238,77 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] { - self.adjust_type_parameters(span, space, type_defs, - require_type_space, &mut substs); - assert_eq!(substs.types.len(space), type_defs.len(space)); + self.check_path_parameter_count(subst::TypeSpace, + span, + &type_scheme.generics, + !require_type_space, + &mut type_segment); + self.check_path_parameter_count(subst::FnSpace, + span, + &type_scheme.generics, + true, + &mut fn_segment); + + let substs = Substs::from_generics(&type_scheme.generics, |def, _| { + let i = def.index as usize; + let segment = match def.space { + subst::SelfSpace => None, + subst::TypeSpace => type_segment, + subst::FnSpace => fn_segment + }; + let lifetimes = match segment.map(|s| &s.parameters) { + Some(&hir::AngleBracketedParameters(ref data)) => &data.lifetimes[..], + Some(&hir::ParenthesizedParameters(_)) => bug!(), + None => &[] + }; - self.adjust_region_parameters(span, space, region_defs, &mut substs); - assert_eq!(substs.regions.len(space), region_defs.len(space)); - } + if let Some(ast_lifetime) = lifetimes.get(i) { + ast_region_to_region(self.tcx, ast_lifetime) + } else { + self.region_var_for_def(span, def) + } + }, |def, substs| { + let i = def.index as usize; + let segment = match def.space { + subst::SelfSpace => None, + subst::TypeSpace => type_segment, + subst::FnSpace => fn_segment + }; + let types = match segment.map(|s| &s.parameters) { + Some(&hir::AngleBracketedParameters(ref data)) => &data.types[..], + Some(&hir::ParenthesizedParameters(_)) => bug!(), + None => &[] + }; + let can_omit = def.space != subst::TypeSpace || !require_type_space; + let default = if can_omit && types.len() == 0 { + def.default + } else { + None + }; + + if def.space == subst::SelfSpace && opt_self_ty.is_some() { + // Self, which has been provided. + assert_eq!(i, 0); + opt_self_ty.unwrap() + } else if let Some(ast_ty) = types.get(i) { + // A provided type parameter. + self.to_ty(ast_ty) + } else if let Some(default) = default { + // No type parameter provided, but a default exists. + default.subst_spanned(self.tcx, substs, Some(span)) + } else { + // No type parameters were provided, we can infer all. + // This can also be reached in some error cases: + // We prefer to use inference variables instead of + // TyError to let type inference recover somewhat. + self.type_var_for_def(span, def, substs) + } + }); // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. let substs = self.tcx.mk_substs(substs); - assert!(!substs.has_regions_escaping_depth(0)); + assert!(!substs.has_escaping_regions()); assert!(!type_scheme.has_escaping_regions()); // Add all the obligations that are required, substituting and @@ -4349,246 +4359,79 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty_substituted } - /// Finds the parameters that the user provided and adds them to `substs`. If too many - /// parameters are provided, then reports an error and clears the output vector. - /// - /// We clear the output vector because that will cause the `adjust_XXX_parameters()` later to - /// use inference variables. This seems less likely to lead to derived errors. - /// - /// Note that we *do not* check for *too few* parameters here. Due to the presence of defaults - /// etc that is more complicated. I wanted however to do the reporting of *too many* parameters - /// here because we can easily use the precise span of the N+1'th parameter. - fn push_explicit_parameters_from_segment_to_substs(&self, - space: subst::ParamSpace, - span: Span, - type_defs: &VecPerParamSpace>, - region_defs: &VecPerParamSpace, - segment: &hir::PathSegment, - substs: &mut Substs<'tcx>) - { - match segment.parameters { - hir::AngleBracketedParameters(ref data) => { - self.push_explicit_angle_bracketed_parameters_from_segment_to_substs( - space, type_defs, region_defs, data, substs); - } - - hir::ParenthesizedParameters(ref data) => { - span_err!(self.tcx.sess, span, E0238, - "parenthesized parameters may only be used with a trait"); - self.push_explicit_parenthesized_parameters_from_segment_to_substs( - space, span, type_defs, data, substs); - } - } - } - - fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(&self, - space: subst::ParamSpace, - type_defs: &VecPerParamSpace>, - region_defs: &VecPerParamSpace, - data: &hir::AngleBracketedParameterData, - substs: &mut Substs<'tcx>) - { - { - let type_count = type_defs.len(space); - assert_eq!(substs.types.len(space), 0); - for (i, typ) in data.types.iter().enumerate() { - let t = self.to_ty(&typ); - if i < type_count { - substs.types.push(space, t); - } else if i == type_count { - struct_span_err!(self.tcx.sess, typ.span, E0087, - "too many type parameters provided: \ - expected at most {} parameter{}, \ - found {} parameter{}", - type_count, - if type_count == 1 {""} else {"s"}, - data.types.len(), - if data.types.len() == 1 {""} else {"s"}) - .span_label(typ.span , &format!("expected {} parameter{}", - type_count, - if type_count == 1 {""} else {"s"})).emit(); - substs.types.truncate(space, 0); - break; - } + /// Report errors if the provided parameters are too few or too many. + fn check_path_parameter_count(&self, + space: subst::ParamSpace, + span: Span, + generics: &ty::Generics<'tcx>, + can_omit: bool, + segment: &mut Option<&hir::PathSegment>) { + let (lifetimes, types, bindings) = match segment.map(|s| &s.parameters) { + Some(&hir::AngleBracketedParameters(ref data)) => { + (&data.lifetimes[..], &data.types[..], &data.bindings[..]) } - } - - if !data.bindings.is_empty() { - span_err!(self.tcx.sess, data.bindings[0].span, E0182, - "unexpected binding of associated item in expression path \ - (only allowed in type paths)"); - } - - { - let region_count = region_defs.len(space); - assert_eq!(substs.regions.len(space), 0); - for (i, lifetime) in data.lifetimes.iter().enumerate() { - let r = ast_region_to_region(self.tcx, lifetime); - if i < region_count { - substs.regions.push(space, r); - } else if i == region_count { - span_err!(self.tcx.sess, lifetime.span, E0088, - "too many lifetime parameters provided: \ - expected {} parameter{}, found {} parameter{}", - region_count, - if region_count == 1 {""} else {"s"}, - data.lifetimes.len(), - if data.lifetimes.len() == 1 {""} else {"s"}); - substs.regions.truncate(space, 0); - break; - } + Some(&hir::ParenthesizedParameters(_)) => { + span_bug!(span, "parenthesized parameters cannot appear in ExprPath"); } - } - } - - /// As with - /// `push_explicit_angle_bracketed_parameters_from_segment_to_substs`, - /// but intended for `Foo(A,B) -> C` form. This expands to - /// roughly the same thing as `Foo<(A,B),C>`. One important - /// difference has to do with the treatment of anonymous - /// regions, which are translated into bound regions (NYI). - fn push_explicit_parenthesized_parameters_from_segment_to_substs(&self, - space: subst::ParamSpace, - span: Span, - type_defs: &VecPerParamSpace>, - data: &hir::ParenthesizedParameterData, - substs: &mut Substs<'tcx>) - { - let type_count = type_defs.len(space); - if type_count < 2 { - span_err!(self.tcx.sess, span, E0167, - "parenthesized form always supplies 2 type parameters, \ - but only {} parameter(s) were expected", - type_count); - } - - let input_tys: Vec = - data.inputs.iter().map(|ty| self.to_ty(&ty)).collect(); - - let tuple_ty = self.tcx.mk_tup(input_tys); - - if type_count >= 1 { - substs.types.push(space, tuple_ty); - } - - let output_ty: Option = - data.output.as_ref().map(|ty| self.to_ty(&ty)); - - let output_ty = - output_ty.unwrap_or(self.tcx.mk_nil()); + None => (&[][..], &[][..], &[][..]) + }; - if type_count >= 2 { - substs.types.push(space, output_ty); - } - } + let count = |n| { + format!("{} parameter{}", n, if n == 1 { "" } else { "s" }) + }; - fn adjust_type_parameters(&self, - span: Span, - space: ParamSpace, - defs: &VecPerParamSpace>, - require_type_space: bool, - substs: &mut Substs<'tcx>) - { - let provided_len = substs.types.len(space); - let desired = defs.get_slice(space); - let required_len = desired.iter() - .take_while(|d| d.default.is_none()) - .count(); - - debug!("adjust_type_parameters(space={:?}, \ - provided_len={}, \ - desired_len={}, \ - required_len={})", - space, - provided_len, - desired.len(), - required_len); - - // Enforced by `push_explicit_parameters_from_segment_to_substs()`. - assert!(provided_len <= desired.len()); - - // Nothing specified at all: supply inference variables for - // everything. - if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { - substs.types.replace(space, Vec::new()); - for def in desired { - let ty_var = self.type_var_for_def(span, def, substs); - substs.types.push(def.space, ty_var); - } - return; + // Check provided lifetime parameters. + let lifetime_defs = generics.regions.get_slice(space); + if lifetimes.len() > lifetime_defs.len() { + let span = lifetimes[lifetime_defs.len()].span; + span_err!(self.tcx.sess, span, E0088, + "too many lifetime parameters provided: \ + expected {}, found {}", + count(lifetime_defs.len()), + count(lifetimes.len())); + } else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() { + span_err!(self.tcx.sess, span, E0090, + "too few lifetime parameters provided: \ + expected {}, found {}", + count(lifetime_defs.len()), + count(lifetimes.len())); } - // Too few parameters specified: report an error and use Err - // for everything. - if provided_len < required_len { + // Check provided type parameters. + let type_defs = generics.types.get_slice(space); + let required_len = type_defs.iter() + .take_while(|d| d.default.is_none()) + .count(); + if types.len() > type_defs.len() { + let span = types[type_defs.len()].span; + struct_span_err!(self.tcx.sess, span, E0087, + "too many type parameters provided: \ + expected at most {}, found {}", + count(type_defs.len()), + count(types.len())) + .span_label(span, &format!("expected {}", + count(type_defs.len()))).emit(); + + // To prevent derived errors to accumulate due to extra + // type parameters, we force instantiate_value_path to + // use inference variables instead of the provided types. + *segment = None; + } else if !(can_omit && types.len() == 0) && types.len() < required_len { let qualifier = - if desired.len() != required_len { "at least " } else { "" }; + if type_defs.len() != required_len { "at least " } else { "" }; span_err!(self.tcx.sess, span, E0089, - "too few type parameters provided: expected {}{} parameter{}, \ - found {} parameter{}", - qualifier, required_len, - if required_len == 1 {""} else {"s"}, - provided_len, - if provided_len == 1 {""} else {"s"}); - substs.types.replace(space, vec![self.tcx.types.err; desired.len()]); - return; - } - - // Otherwise, add in any optional parameters that the user - // omitted. The case of *too many* parameters is handled - // already by - // push_explicit_parameters_from_segment_to_substs(). Note - // that the *default* type are expressed in terms of all prior - // parameters, so we have to substitute as we go with the - // partial substitution that we have built up. - for i in provided_len..desired.len() { - let default = desired[i].default.unwrap(); - let default = default.subst_spanned(self.tcx, substs, Some(span)); - substs.types.push(space, default); - } - assert_eq!(substs.types.len(space), desired.len()); - - debug!("Final substs: {:?}", substs); - } - - fn adjust_region_parameters(&self, - span: Span, - space: ParamSpace, - defs: &VecPerParamSpace, - substs: &mut Substs) - { - let provided_len = substs.regions.len(space); - let desired = defs.get_slice(space); - - // Enforced by `push_explicit_parameters_from_segment_to_substs()`. - assert!(provided_len <= desired.len()); - - // If nothing was provided, just use inference variables. - if provided_len == 0 { - substs.regions.replace( - space, - self.region_vars_for_defs(span, desired)); - return; + "too few type parameters provided: \ + expected {}{}, found {}", + qualifier, + count(required_len), + count(types.len())); } - // If just the right number were provided, everybody is happy. - if provided_len == desired.len() { - return; + if !bindings.is_empty() { + span_err!(self.tcx.sess, bindings[0].span, E0182, + "unexpected binding of associated item in expression path \ + (only allowed in type paths)"); } - - // Otherwise, too few were provided. Report an error and then - // use inference variables. - span_err!(self.tcx.sess, span, E0090, - "too few lifetime parameters provided: expected {} parameter{}, \ - found {} parameter{}", - desired.len(), - if desired.len() == 1 {""} else {"s"}, - provided_len, - if provided_len == 1 {""} else {"s"}); - - substs.regions.replace( - space, - self.region_vars_for_defs(span, desired)); } fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 337b87ce994ad..fe1cb3d6badcd 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4018,7 +4018,7 @@ register_diagnostics! { // E0141, // E0159, // use of trait `{}` as struct constructor // E0163, // merged into E0071 - E0167, +// E0167, // E0168, // E0173, // manual implementations of unboxed closure traits are experimental // E0174, @@ -4053,7 +4053,7 @@ register_diagnostics! { // E0235, // structure constructor specifies a structure of type but // E0236, // no lang item for range syntax // E0237, // no lang item for range syntax - E0238, // parenthesized parameters may only be used with a trait +// E0238, // parenthesized parameters may only be used with a trait // E0239, // `next` method of `Iterator` trait has unexpected type // E0240, // E0241, From 4158673ad7150f4fa02fbea3654e8cf1628beb0b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 8 Aug 2016 23:39:49 +0300 Subject: [PATCH 067/768] rustc: reduce Substs and Generics to a simple immutable API. --- src/librustc/infer/error_reporting.rs | 2 +- src/librustc/infer/mod.rs | 44 +- src/librustc/middle/cstore.rs | 16 +- src/librustc/middle/dead.rs | 25 +- src/librustc/mir/repr.rs | 9 +- src/librustc/traits/error_reporting.rs | 4 +- src/librustc/traits/fulfill.rs | 3 +- src/librustc/traits/mod.rs | 4 +- src/librustc/traits/object_safety.rs | 19 +- src/librustc/traits/select.rs | 49 +- src/librustc/traits/specialize/mod.rs | 13 +- .../traits/specialize/specialization_graph.rs | 19 +- src/librustc/traits/util.rs | 22 +- src/librustc/ty/context.rs | 14 +- src/librustc/ty/flags.rs | 4 +- src/librustc/ty/fold.rs | 6 +- src/librustc/ty/maps.rs | 5 +- src/librustc/ty/mod.rs | 170 +++-- src/librustc/ty/relate.rs | 114 +-- src/librustc/ty/structural_impls.rs | 26 +- src/librustc/ty/sty.rs | 32 +- src/librustc/ty/subst.rs | 347 ++++----- src/librustc/ty/trait_def.rs | 4 +- src/librustc/ty/util.rs | 9 +- src/librustc/util/ppaux.rs | 128 ++-- .../borrowck/mir/elaborate_drops.rs | 5 +- src/librustc_const_eval/eval.rs | 16 +- src/librustc_driver/test.rs | 14 +- src/librustc_lint/builtin.rs | 11 +- src/librustc_metadata/astencode.rs | 18 +- src/librustc_metadata/common.rs | 13 +- src/librustc_metadata/csearch.rs | 15 +- src/librustc_metadata/decoder.rs | 80 +-- src/librustc_metadata/encoder.rs | 55 +- src/librustc_metadata/tls_context.rs | 2 +- src/librustc_metadata/tydecode.rs | 53 +- src/librustc_metadata/tyencode.rs | 27 +- src/librustc_mir/build/scope.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 6 +- src/librustc_save_analysis/lib.rs | 3 +- src/librustc_trans/_match.rs | 2 +- src/librustc_trans/adt.rs | 4 +- src/librustc_trans/base.rs | 10 +- src/librustc_trans/callee.rs | 26 +- src/librustc_trans/collector.rs | 51 +- src/librustc_trans/common.rs | 4 +- src/librustc_trans/consts.rs | 8 +- src/librustc_trans/context.rs | 20 +- src/librustc_trans/controlflow.rs | 4 +- src/librustc_trans/debuginfo/metadata.rs | 8 +- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 4 +- src/librustc_trans/expr.rs | 2 +- src/librustc_trans/glue.rs | 4 +- src/librustc_trans/intrinsic.rs | 5 +- src/librustc_trans/meth.rs | 27 +- src/librustc_trans/mir/constant.rs | 9 +- src/librustc_trans/monomorphize.rs | 5 +- src/librustc_trans/partitioning.rs | 4 +- src/librustc_trans/trans_item.rs | 7 +- src/librustc_trans/type_of.rs | 5 +- src/librustc_typeck/astconv.rs | 46 +- src/librustc_typeck/check/_match.rs | 19 +- src/librustc_typeck/check/autoderef.rs | 2 +- src/librustc_typeck/check/compare_method.rs | 20 +- src/librustc_typeck/check/dropck.rs | 17 +- src/librustc_typeck/check/intrinsic.rs | 8 +- src/librustc_typeck/check/method/confirm.rs | 31 +- src/librustc_typeck/check/method/mod.rs | 6 +- src/librustc_typeck/check/method/probe.rs | 59 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 120 ++-- src/librustc_typeck/check/writeback.rs | 41 +- src/librustc_typeck/collect.rs | 662 ++++++++---------- src/librustc_typeck/lib.rs | 4 +- src/librustc_typeck/rscope.rs | 31 +- src/librustc_typeck/variance/constraints.rs | 9 +- src/librustc_typeck/variance/solve.rs | 30 +- src/librustdoc/clean/inline.rs | 20 +- src/librustdoc/clean/mod.rs | 24 +- 80 files changed, 1226 insertions(+), 1548 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index b0dec3277a996..21fccd2c6132d 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1366,7 +1366,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { hir::TyPath(ref maybe_qself, ref path) => { match self.tcx.expect_def(cur_ty.id) { Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { - let generics = self.tcx.lookup_item_type(did).generics; + let generics = self.tcx.lookup_generics(did); let expected = generics.regions.len(subst::TypeSpace) as u32; diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1e360cd43da12..1b65b5dae0748 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -25,9 +25,7 @@ use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::region::CodeExtent; use mir::tcx::LvalueTy; -use ty::subst; -use ty::subst::Substs; -use ty::subst::Subst; +use ty::subst::{Subst, Substs}; use ty::adjustment; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; @@ -1236,43 +1234,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Given a set of generics defined on a type or impl, returns a substitution mapping each /// type/region parameter to a fresh inference variable. - pub fn fresh_substs_for_generics(&self, - span: Span, - generics: &ty::Generics<'tcx>) - -> &'tcx subst::Substs<'tcx> - { - let substs = Substs::from_generics(generics, |def, _| { + pub fn fresh_substs_for_item(&self, + span: Span, + def_id: DefId) + -> &'tcx Substs<'tcx> { + Substs::for_item(self.tcx, def_id, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { self.type_var_for_def(span, def, substs) - }); - - self.tcx.mk_substs(substs) - } - - /// Given a set of generics defined on a trait, returns a substitution mapping each output - /// type/region parameter to a fresh inference variable, and mapping the self type to - /// `self_ty`. - pub fn fresh_substs_for_trait(&self, - span: Span, - generics: &ty::Generics<'tcx>, - self_ty: Ty<'tcx>) - -> &'tcx subst::Substs<'tcx> - { - assert!(generics.types.len(subst::SelfSpace) == 1); - assert!(generics.types.len(subst::FnSpace) == 0); - - let substs = Substs::from_generics(generics, |def, _| { - self.region_var_for_def(span, def) - }, |def, substs| { - if def.space == subst::SelfSpace { - self_ty - } else { - self.type_var_for_def(span, def, substs) - } - }); - - self.tcx.mk_substs(substs) + }) } pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 481fd332404ba..abb22783ddc84 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -154,7 +154,7 @@ pub trait CrateStore<'tcx> { fn item_variances(&self, def: DefId) -> ty::ItemVariances; fn repr_attrs(&self, def: DefId) -> Vec; fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> ty::TypeScheme<'tcx>; + -> Ty<'tcx>; fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap>; fn item_name(&self, def: DefId) -> ast::Name; fn opt_item_name(&self, def: DefId) -> Option; @@ -162,6 +162,8 @@ pub trait CrateStore<'tcx> { -> ty::GenericPredicates<'tcx>; fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; + fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx ty::Generics<'tcx>; fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; @@ -187,8 +189,7 @@ pub trait CrateStore<'tcx> { fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info - fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option; + fn trait_of_item(&self, def_id: DefId) -> Option; fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; @@ -334,7 +335,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn item_variances(&self, def: DefId) -> ty::ItemVariances { bug!("item_variances") } fn repr_attrs(&self, def: DefId) -> Vec { bug!("repr_attrs") } fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> ty::TypeScheme<'tcx> { bug!("item_type") } + -> Ty<'tcx> { bug!("item_type") } fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { bug!("visible_parent_map") } @@ -344,6 +345,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> ty::GenericPredicates<'tcx> { bug!("item_predicates") } fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } + fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx ty::Generics<'tcx> { bug!("item_generics") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx> { bug!("trait_def") } @@ -379,8 +382,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info - fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option { bug!("trait_of_item") } + fn trait_of_item(&self, def_id: DefId) -> Option { bug!("trait_of_item") } fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("impl_or_trait_item") } @@ -583,7 +585,7 @@ pub mod tls { pub trait DecodingContext<'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx>; - fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> Substs<'tcx>; + fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>; fn translate_def_id(&self, def_id: DefId) -> DefId; } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2b59e603cc897..7412b5fc8048f 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -18,7 +18,7 @@ use hir::{self, pat_util, PatKind}; use hir::intravisit::{self, Visitor}; use middle::privacy; -use ty::{self, TyCtxt}; +use ty::{self, subst, TyCtxt}; use hir::def::Def; use hir::def_id::{DefId}; use lint; @@ -88,15 +88,24 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn lookup_and_handle_definition(&mut self, id: ast::NodeId) { use ty::TypeVariants::{TyEnum, TyStruct}; + let def = self.tcx.expect_def(id); + // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar` - self.tcx.tables.borrow().item_substs.get(&id) - .and_then(|substs| substs.substs.self_ty()) - .map(|ty| match ty.sty { - TyEnum(tyid, _) | TyStruct(tyid, _) => self.check_def_id(tyid.did), - _ => (), - }); + match def { + Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) + if self.tcx.trait_of_item(def.def_id()).is_some() => { + if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { + match substs.substs.types.get(subst::SelfSpace, 0).sty { + TyEnum(tyid, _) | TyStruct(tyid, _) => { + self.check_def_id(tyid.did) + } + _ => {} + } + } + } + _ => {} + } - let def = self.tcx.expect_def(id); match def { Def::Const(_) | Def::AssociatedConst(..) => { self.check_def_id(def.def_id()); diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 2bde3d6554fee..f511d820fac58 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1073,10 +1073,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let variant_def = &adt_def.variants[variant]; ppaux::parameterized(fmt, substs, variant_def.did, - ppaux::Ns::Value, &[], - |tcx| { - Some(tcx.lookup_item_type(variant_def.did).generics) - })?; + ppaux::Ns::Value, &[])?; match variant_def.kind { ty::VariantKind::Unit => Ok(()), @@ -1169,9 +1166,7 @@ impl<'tcx> Debug for Literal<'tcx> { use self::Literal::*; match *self { Item { def_id, substs } => { - ppaux::parameterized( - fmt, substs, def_id, ppaux::Ns::Value, &[], - |tcx| Some(tcx.lookup_item_type(def_id).generics)) + ppaux::parameterized(fmt, substs, def_id, ppaux::Ns::Value, &[]) } Value { ref value } => { write!(fmt, "const ")?; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5d50eac1716a3..e67c0ba8053d7 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -221,9 +221,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lookup_trait_def(trait_ref.def_id) .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| { - let ity = tcx.lookup_item_type(def_id); - let impl_substs = self.fresh_substs_for_generics(obligation.cause.span, - &ity.generics); + let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); let impl_trait_ref = tcx .impl_trait_ref(def_id) .unwrap() diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 1ee1dc50b717d..3698027dca887 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -160,10 +160,9 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { // We can resolve the `impl Trait` to its concrete type. if let Some(ty_scheme) = tcx.opt_lookup_item_type(def_id) { let concrete_ty = ty_scheme.ty.subst(tcx, substs); - let concrete_substs = Substs::new_trait(vec![], vec![], concrete_ty); let predicate = ty::TraitRef { def_id: self.predicate.def_id(), - substs: tcx.mk_substs(concrete_substs) + substs: Substs::new_trait(tcx, vec![], vec![], concrete_ty) }.to_predicate(); let original_obligation = Obligation::new(self.cause.clone(), diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index dc0807ba38fae..b86a54f01cf49 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -17,7 +17,7 @@ pub use self::ObligationCauseCode::*; use hir::def_id::DefId; use middle::free_region::FreeRegionMap; -use ty::subst; +use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable}; use infer::InferCtxt; @@ -272,7 +272,7 @@ pub enum Vtable<'tcx, N> { #[derive(Clone, PartialEq, Eq)] pub struct VtableImplData<'tcx, N> { pub impl_def_id: DefId, - pub substs: &'tcx subst::Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, pub nested: Vec } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 8ddb14e08e31e..ecfa7930d0294 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -166,25 +166,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } fn trait_has_sized_self(self, trait_def_id: DefId) -> bool { - let trait_def = self.lookup_trait_def(trait_def_id); - let trait_predicates = self.lookup_predicates(trait_def_id); - self.generics_require_sized_self(&trait_def.generics, &trait_predicates) + self.generics_require_sized_self(trait_def_id) } - fn generics_require_sized_self(self, - generics: &ty::Generics<'gcx>, - predicates: &ty::GenericPredicates<'gcx>) - -> bool - { + fn generics_require_sized_self(self, def_id: DefId) -> bool { let sized_def_id = match self.lang_items.sized_trait() { Some(def_id) => def_id, None => { return false; /* No Sized trait, can't require it! */ } }; // Search for a predicate like `Self : Sized` amongst the trait bounds. - let free_substs = self.construct_free_substs(generics, + let free_substs = self.construct_free_substs(def_id, self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = predicates.instantiate(self, &free_substs).predicates; + let predicates = self.lookup_predicates(def_id); + let predicates = predicates.instantiate(self, free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { match predicate { @@ -214,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { // Any method that has a `Self : Sized` requisite is otherwise // exempt from the regulations. - if self.generics_require_sized_self(&method.generics, &method.predicates) { + if self.generics_require_sized_self(method.def_id) { return None; } @@ -231,7 +226,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> bool { // Any method that has a `Self : Sized` requisite can't be called. - if self.generics_require_sized_self(&method.generics, &method.predicates) { + if self.generics_require_sized_self(method.def_id) { return false; } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 73108e7d37f88..9099d6cd740d1 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -42,6 +42,7 @@ use traits; use ty::fast_reject; use ty::relate::TypeRelation; +use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec}; use std::cell::RefCell; use std::fmt; @@ -1935,7 +1936,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // for `PhantomData`, we pass `T` ty::TyStruct(def, substs) if def.is_phantom_data() => { - substs.types.get_slice(TypeSpace).to_vec() + substs.types.as_full_slice().to_vec() } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2584,17 +2585,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } else { return Err(Unimplemented); }; - let mut ty_params = vec![]; + let mut ty_params = BitVector::new(substs_a.types.len(TypeSpace)); + let mut found = false; for ty in field.walk() { if let ty::TyParam(p) = ty.sty { assert!(p.space == TypeSpace); - let idx = p.idx as usize; - if !ty_params.contains(&idx) { - ty_params.push(idx); - } + ty_params.insert(p.idx as usize); + found = true; } } - if ty_params.is_empty() { + if !found { return Err(Unimplemented); } @@ -2602,12 +2602,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // TyError and ensure they do not affect any other fields. // This could be checked after type collection for any struct // with a potentially unsized trailing field. - let mut new_substs = substs_a.clone(); - for &i in &ty_params { - new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; - } + let types = substs_a.types.map_enumerated(|(_, i, ty)| { + if ty_params.contains(i) { + tcx.types.err + } else { + ty + } + }); + let substs = Substs::new(tcx, types, substs_a.regions.clone()); for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, &new_substs).references_error() { + if ty.subst(tcx, substs).references_error() { return Err(Unimplemented); } } @@ -2618,11 +2622,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Check that the source structure with the target's // type parameters is a subtype of the target. - for &i in &ty_params { - let param_b = *substs_b.types.get(TypeSpace, i); - new_substs.types.get_mut_slice(TypeSpace)[i] = param_b; - } - let new_struct = tcx.mk_struct(def, tcx.mk_substs(new_substs)); + let types = substs_a.types.map_enumerated(|(_, i, ty)| { + if ty_params.contains(i) { + *substs_b.types.get(TypeSpace, i) + } else { + ty + } + }); + let substs = Substs::new(tcx, types, substs_a.regions.clone()); + let new_struct = tcx.mk_struct(def, substs); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) @@ -2691,12 +2699,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { snapshot); let skol_obligation_trait_ref = skol_obligation.trait_ref; - let impl_substs = util::fresh_type_vars_for_impl(self.infcx, - obligation.cause.span, - impl_def_id); + let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, + impl_def_id); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), - &impl_substs); + impl_substs); let impl_trait_ref = project::normalize_with_depth(self, diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 38cccb9753df6..42865ca927de3 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -18,7 +18,7 @@ // fits together with the rest of the trait machinery. use super::{SelectionContext, FulfillmentContext}; -use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig}; +use super::util::impl_trait_ref_and_oblig; use rustc_data_structures::fnv::FnvHashMap; use hir::def_id::DefId; @@ -101,7 +101,7 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, }; // directly inherent the method generics, since those do not vary across impls - infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs)) + source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) } /// Is impl1 a specialization of impl2? @@ -141,11 +141,8 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // create a parameter environment corresponding to a (skolemized) instantiation of impl1 - let scheme = tcx.lookup_item_type(impl1_def_id); - let predicates = tcx.lookup_predicates(impl1_def_id); let mut penv = tcx.construct_parameter_environment(DUMMY_SP, - &scheme.generics, - &predicates, + impl1_def_id, region::DUMMY_CODE_EXTENT); let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id) .unwrap() @@ -188,10 +185,10 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_impl: DefId) -> Result<&'tcx Substs<'tcx>, ()> { let selcx = &mut SelectionContext::new(&infcx); - let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl); + let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, target_impl, - &target_substs); + target_substs); // do the impls unify? If not, no specialization. if let Err(_) = infcx.eq_trait_refs(true, diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index a47cd23c64aa6..13193e1b2d71b 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -122,19 +122,18 @@ impl<'a, 'gcx, 'tcx> Children { if le == ge { // overlap, but no specialization; error out let trait_ref = impl_header.trait_ref.unwrap(); + let self_ty = trait_ref.self_ty(); Err(OverlapError { with_impl: possible_sibling, trait_desc: trait_ref.to_string(), - self_desc: trait_ref.substs.self_ty().and_then(|ty| { - // only report the Self type if it has at least - // some outer concrete shell; otherwise, it's - // not adding much information. - if ty.has_concrete_skeleton() { - Some(ty.to_string()) - } else { - None - } - }) + // only report the Self type if it has at least + // some outer concrete shell; otherwise, it's + // not adding much information. + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + } }) } else { Ok((le, ge)) diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 80a3ad9122bd1..1954ce1993c5e 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -9,10 +9,8 @@ // except according to those terms. use hir::def_id::DefId; -use infer::InferCtxt; use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; -use syntax_pos::Span; use util::common::ErrorReported; use util::nodemap::FnvHashSet; @@ -349,19 +347,6 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, (impl_trait_ref, impl_obligations) } -// determine the `self` type, using fresh variables for all variables -// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` -// would return ($0, $1) where $0 and $1 are freshly instantiated type -// variables. -pub fn fresh_type_vars_for_impl<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - span: Span, - impl_def_id: DefId) - -> &'tcx Substs<'tcx> -{ - let impl_generics = infcx.tcx.lookup_item_type(impl_def_id).generics; - infcx.fresh_substs_for_generics(span, &impl_generics) -} - /// See `super::obligations_for_generics` pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, recursion_depth: usize, @@ -401,7 +386,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Ok(def_id) => { Ok(ty::TraitRef { def_id: def_id, - substs: self.mk_substs(Substs::empty().with_self_ty(param_ty)) + substs: Substs::new_trait(self, vec![], vec![], param_ty) }) } Err(e) => { @@ -421,7 +406,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let trait_ref = ty::TraitRef { def_id: trait_def_id, - substs: self.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) + substs: Substs::new_trait(self, ty_params, vec![], param_ty) }; predicate_for_trait_ref(cause, trait_ref, recursion_depth) } @@ -509,10 +494,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { TupleArgumentsFlag::No => sig.0.inputs[0], TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()), }; - let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, - substs: self.mk_substs(trait_substs), + substs: Substs::new_trait(self, vec![arguments_tuple], vec![], self_ty), }; ty::Binder((trait_ref, sig.0.output)) } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index dfb5482ad873b..9356b408a51cb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -63,6 +63,7 @@ pub struct CtxtArenas<'tcx> { layout: TypedArena, // references + generics: TypedArena>, trait_defs: TypedArena>, adt_defs: TypedArena>, } @@ -78,6 +79,7 @@ impl<'tcx> CtxtArenas<'tcx> { stability: TypedArena::new(), layout: TypedArena::new(), + generics: TypedArena::new(), trait_defs: TypedArena::new(), adt_defs: TypedArena::new() } @@ -341,7 +343,8 @@ pub struct GlobalCtxt<'tcx> { pub adt_defs: RefCell>>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its - /// associated predicates. + /// associated generics and predicates. + pub generics: RefCell>>, pub predicates: RefCell>>, /// Maps from the def-id of a trait to the list of @@ -583,13 +586,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().node_types.insert(id, ty); } + pub fn alloc_generics(self, generics: ty::Generics<'gcx>) + -> &'gcx ty::Generics<'gcx> { + self.global_interners.arenas.generics.alloc(generics) + } + pub fn intern_trait_def(self, def: ty::TraitDef<'gcx>) -> &'gcx ty::TraitDef<'gcx> { let did = def.trait_ref.def_id; - let interned = self.global_interners.arenas.trait_defs.alloc(def); + let interned = self.alloc_trait_def(def); if let Some(prev) = self.trait_defs.borrow_mut().insert(did, interned) { bug!("Tried to overwrite interned TraitDef: {:?}", prev) } + self.generics.borrow_mut().insert(did, interned.generics); interned } @@ -711,6 +720,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + generics: RefCell::new(DepTrackingMap::new(dep_graph.clone())), predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), fulfilled_predicates: RefCell::new(fulfilled_predicates), diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 6cc759c420d29..312b09cd27dfc 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::subst; +use ty::subst::{self, Substs}; use ty::{self, Ty, TypeFlags, TypeFoldable}; pub struct FlagComputation { @@ -207,7 +207,7 @@ impl FlagComputation { self.add_substs(projection_ty.trait_ref.substs); } - fn add_substs(&mut self, substs: &subst::Substs) { + fn add_substs(&mut self, substs: &Substs) { self.add_tys(substs.types.as_full_slice()); for &r in substs.regions.as_full_slice() { self.add_region(r); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 597261cca72bf..2e114a801d6ed 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -40,7 +40,7 @@ //! and does not need to visit anything else. use middle::region; -use ty::subst; +use ty::subst::Substs; use ty::adjustment; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; @@ -145,8 +145,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { } fn fold_substs(&mut self, - substs: &'tcx subst::Substs<'tcx>) - -> &'tcx subst::Substs<'tcx> { + substs: &'tcx Substs<'tcx>) + -> &'tcx Substs<'tcx> { substs.super_fold_with(self) } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 57b1dd66bea9d..d5686906e6a7b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,7 +10,7 @@ use dep_graph::{DepNode, DepTrackingMapConfig}; use hir::def_id::DefId; -use ty; +use ty::{self, Ty}; use std::marker::PhantomData; use std::rc::Rc; use syntax::{attr, ast}; @@ -30,7 +30,8 @@ macro_rules! dep_map_ty { } dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> } -dep_map_ty! { Tcache: ItemSignature(DefId) -> ty::TypeScheme<'tcx> } +dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } +dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6ac57a877a759..36784e4006461 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -173,15 +173,14 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { -> ImplHeader<'tcx> { let tcx = selcx.tcx(); - let impl_generics = tcx.lookup_item_type(impl_def_id).generics; - let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics); + let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); let header = ImplHeader { impl_def_id: impl_def_id, self_ty: tcx.lookup_item_type(impl_def_id).ty, trait_ref: tcx.impl_trait_ref(impl_def_id), predicates: tcx.lookup_predicates(impl_def_id).predicates - }.subst(tcx, &impl_substs); + }.subst(tcx, impl_substs); let traits::Normalized { value: mut header, obligations } = traits::normalize(selcx, traits::ObligationCause::dummy(), &header); @@ -348,7 +347,7 @@ impl Visibility { #[derive(Clone, Debug)] pub struct Method<'tcx> { pub name: Name, - pub generics: Generics<'tcx>, + pub generics: &'tcx Generics<'tcx>, pub predicates: GenericPredicates<'tcx>, pub fty: &'tcx BareFnTy<'tcx>, pub explicit_self: ExplicitSelfCategory, @@ -360,7 +359,7 @@ pub struct Method<'tcx> { impl<'tcx> Method<'tcx> { pub fn new(name: Name, - generics: ty::Generics<'tcx>, + generics: &'tcx ty::Generics<'tcx>, predicates: GenericPredicates<'tcx>, fty: &'tcx BareFnTy<'tcx>, explicit_self: ExplicitSelfCategory, @@ -453,7 +452,7 @@ pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. pub def_id: DefId, pub ty: Ty<'tcx>, - pub substs: &'tcx subst::Substs<'tcx> + pub substs: &'tcx Substs<'tcx> } /// With method calls, we store some extra information in @@ -760,6 +759,7 @@ impl RegionParameterDef { pub struct Generics<'tcx> { pub types: VecPerParamSpace>, pub regions: VecPerParamSpace, + pub has_self: bool, } impl<'tcx> Generics<'tcx> { @@ -767,6 +767,7 @@ impl<'tcx> Generics<'tcx> { Generics { types: VecPerParamSpace::empty(), regions: VecPerParamSpace::empty(), + has_self: false, } } @@ -1224,7 +1225,7 @@ impl<'tcx> TraitRef<'tcx> { } pub fn self_ty(&self) -> Ty<'tcx> { - self.substs.self_ty().unwrap() + *self.substs.types.get(subst::SelfSpace, 0) } pub fn input_types(&self) -> &[Ty<'tcx>] { @@ -1298,23 +1299,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { // so for now just grab environment for the impl let impl_id = tcx.map.get_parent(id); let impl_def_id = tcx.map.local_def_id(impl_id); - let scheme = tcx.lookup_item_type(impl_def_id); - let predicates = tcx.lookup_predicates(impl_def_id); tcx.construct_parameter_environment(impl_item.span, - &scheme.generics, - &predicates, + impl_def_id, tcx.region_maps.item_extent(id)) } hir::ImplItemKind::Method(_, ref body) => { let method_def_id = tcx.map.local_def_id(id); match tcx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; tcx.construct_parameter_environment( impl_item.span, - method_generics, - method_bounds, + method_ty.def_id, tcx.region_maps.call_site_extent(id, body.id)) } _ => { @@ -1332,11 +1327,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { // so for now just grab environment for the trait let trait_id = tcx.map.get_parent(id); let trait_def_id = tcx.map.local_def_id(trait_id); - let trait_def = tcx.lookup_trait_def(trait_def_id); - let predicates = tcx.lookup_predicates(trait_def_id); tcx.construct_parameter_environment(trait_item.span, - &trait_def.generics, - &predicates, + trait_def_id, tcx.region_maps.item_extent(id)) } hir::MethodTraitItem(_, ref body) => { @@ -1346,8 +1338,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { let method_def_id = tcx.map.local_def_id(id); match tcx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; let extent = if let Some(ref body) = *body { // default impl: use call_site extent as free_id_outlive bound. tcx.region_maps.call_site_extent(id, body.id) @@ -1357,8 +1347,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { }; tcx.construct_parameter_environment( trait_item.span, - method_generics, - method_bounds, + method_ty.def_id, extent) } _ => { @@ -1375,13 +1364,10 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { hir::ItemFn(_, _, _, _, _, ref body) => { // We assume this is a function. let fn_def_id = tcx.map.local_def_id(id); - let fn_scheme = tcx.lookup_item_type(fn_def_id); - let fn_predicates = tcx.lookup_predicates(fn_def_id); tcx.construct_parameter_environment( item.span, - &fn_scheme.generics, - &fn_predicates, + fn_def_id, tcx.region_maps.call_site_extent(id, body.id)) } hir::ItemEnum(..) | @@ -1391,20 +1377,14 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { hir::ItemConst(..) | hir::ItemStatic(..) => { let def_id = tcx.map.local_def_id(id); - let scheme = tcx.lookup_item_type(def_id); - let predicates = tcx.lookup_predicates(def_id); tcx.construct_parameter_environment(item.span, - &scheme.generics, - &predicates, + def_id, tcx.region_maps.item_extent(id)) } hir::ItemTrait(..) => { let def_id = tcx.map.local_def_id(id); - let trait_def = tcx.lookup_trait_def(def_id); - let predicates = tcx.lookup_predicates(def_id); tcx.construct_parameter_environment(item.span, - &trait_def.generics, - &predicates, + def_id, tcx.region_maps.item_extent(id)) } _ => { @@ -1425,11 +1405,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } Some(ast_map::NodeForeignItem(item)) => { let def_id = tcx.map.local_def_id(id); - let scheme = tcx.lookup_item_type(def_id); - let predicates = tcx.lookup_predicates(def_id); tcx.construct_parameter_environment(item.span, - &scheme.generics, - &predicates, + def_id, ROOT_CODE_EXTENT) } _ => { @@ -1462,7 +1439,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { /// `lookup_predicates`. #[derive(Clone, Debug)] pub struct TypeScheme<'tcx> { - pub generics: Generics<'tcx>, + pub generics: &'tcx Generics<'tcx>, pub ty: Ty<'tcx>, } @@ -1917,9 +1894,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { }; let sized_predicate = Binder(TraitRef { def_id: sized_trait, - substs: tcx.mk_substs(Substs::new_trait( - vec![], vec![], ty - )) + substs: Substs::new_trait(tcx, vec![], vec![], ty) }).to_predicate(); let predicates = tcx.lookup_predicates(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { @@ -2170,7 +2145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> { match self.tables.borrow().item_substs.get(&id) { None => ItemSubsts { - substs: self.global_tcx().mk_substs(Substs::empty()) + substs: Substs::empty(self.global_tcx()) }, Some(ts) => ts.clone(), } @@ -2508,27 +2483,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // Register a given item type - pub fn register_item_type(self, did: DefId, ty: TypeScheme<'gcx>) { - self.tcache.borrow_mut().insert(did, ty); + pub fn register_item_type(self, did: DefId, scheme: TypeScheme<'gcx>) { + self.tcache.borrow_mut().insert(did, scheme.ty); + self.generics.borrow_mut().insert(did, scheme.generics); } // If the given item is in an external crate, looks up its type and adds it to // the type cache. Returns the type parameters and type. pub fn lookup_item_type(self, did: DefId) -> TypeScheme<'gcx> { - lookup_locally_or_in_crate_store( + let ty = lookup_locally_or_in_crate_store( "tcache", did, &self.tcache, - || self.sess.cstore.item_type(self.global_tcx(), did)) + || self.sess.cstore.item_type(self.global_tcx(), did)); + + TypeScheme { + ty: ty, + generics: self.lookup_generics(did) + } } pub fn opt_lookup_item_type(self, did: DefId) -> Option> { - if let Some(scheme) = self.tcache.borrow_mut().get(&did) { - return Some(scheme.clone()); + if did.krate != LOCAL_CRATE { + return Some(self.lookup_item_type(did)); } - if did.krate == LOCAL_CRATE { - None + if let Some(ty) = self.tcache.borrow().get(&did).cloned() { + Some(TypeScheme { + ty: ty, + generics: self.lookup_generics(did) + }) } else { - Some(self.sess.cstore.item_type(self.global_tcx(), did)) + None } } @@ -2557,6 +2541,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.lookup_adt_def_master(did) } + /// Given the did of an item, returns its generics. + pub fn lookup_generics(self, did: DefId) -> &'gcx Generics<'gcx> { + lookup_locally_or_in_crate_store( + "generics", did, &self.generics, + || self.sess.cstore.item_generics(self.global_tcx(), did)) + } + /// Given the did of an item, returns its full set of predicates. pub fn lookup_predicates(self, did: DefId) -> GenericPredicates<'gcx> { lookup_locally_or_in_crate_store( @@ -2812,18 +2803,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// If the given def ID describes an item belonging to a trait (either a - /// default method or an implementation of a trait method), return the ID of - /// the trait that the method belongs to. Otherwise, return `None`. + /// If the given def ID describes an item belonging to a trait, + /// return the ID of the trait that the trait item belongs to. + /// Otherwise, return `None`. pub fn trait_of_item(self, def_id: DefId) -> Option { if def_id.krate != LOCAL_CRATE { - return self.sess.cstore.trait_of_item(self.global_tcx(), def_id); + return self.sess.cstore.trait_of_item(def_id); } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + match self.impl_or_trait_items.borrow().get(&def_id) { Some(impl_or_trait_item) => { match impl_or_trait_item.container() { TraitContainer(def_id) => Some(def_id), - ImplContainer(def_id) => self.trait_id_of_impl(def_id), + ImplContainer(_) => None } } None => None @@ -2837,18 +2828,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// the same). /// Otherwise, return `None`. pub fn trait_item_of_item(self, def_id: DefId) -> Option { - let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) { + let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) { Some(m) => m.clone(), None => return None, }; - let name = impl_item.name(); - match self.trait_of_item(def_id) { - Some(trait_did) => { - self.trait_items(trait_did).iter() - .find(|item| item.name() == name) - .map(|item| item.id()) + match impl_or_trait_item.container() { + TraitContainer(_) => Some(impl_or_trait_item.id()), + ImplContainer(def_id) => { + self.trait_id_of_impl(def_id).and_then(|trait_did| { + let name = impl_or_trait_item.name(); + self.trait_items(trait_did).iter() + .find(|item| item.name() == name) + .map(|item| item.id()) + }) } - None => None } } @@ -2860,7 +2853,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // regions, so it shouldn't matter what we use for the free id let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); ty::ParameterEnvironment { - free_substs: self.mk_substs(Substs::empty()), + free_substs: Substs::empty(self), caller_bounds: Vec::new(), implicit_region_bound: ty::ReEmpty, free_id_outlive: free_id_outlive @@ -2872,28 +2865,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// In general, this means converting from bound parameters to /// free parameters. Since we currently represent bound/free type /// parameters in the same way, this only has an effect on regions. - pub fn construct_free_substs(self, generics: &Generics<'gcx>, - free_id_outlive: CodeExtent) -> Substs<'gcx> { - // map T => T - let types = generics.types.map(|def| { - debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", - def); + pub fn construct_free_substs(self, def_id: DefId, + free_id_outlive: CodeExtent) + -> &'gcx Substs<'gcx> { + + let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| { + // map bound 'a => free 'a + ReFree(FreeRegion { scope: free_id_outlive, + bound_region: def.to_bound_region() }) + }, |def, _| { + // map T => T self.global_tcx().mk_param_from_def(def) }); - // map bound 'a => free 'a - let regions = generics.regions.map(|def| { - let region = - ReFree(FreeRegion { scope: free_id_outlive, - bound_region: def.to_bound_region() }); - debug!("push_region_params {:?}", region); - region - }); - - Substs { - types: types, - regions: regions, - } + debug!("construct_parameter_environment: {:?}", substs); + substs } /// See `ParameterEnvironment` struct def'n for details. @@ -2901,8 +2887,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// for the `free_id_outlive` parameter. (But note that that is not always quite right.) pub fn construct_parameter_environment(self, span: Span, - generics: &ty::Generics<'gcx>, - generic_predicates: &ty::GenericPredicates<'gcx>, + def_id: DefId, free_id_outlive: CodeExtent) -> ParameterEnvironment<'gcx> { @@ -2910,14 +2895,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Construct the free substs. // - let free_substs = self.construct_free_substs(generics, free_id_outlive); + let free_substs = self.construct_free_substs(def_id, free_id_outlive); // // Compute the bounds on Self and the type parameters. // let tcx = self.global_tcx(); - let bounds = generic_predicates.instantiate(tcx, &free_substs); + let generic_predicates = tcx.lookup_predicates(def_id); + let bounds = generic_predicates.instantiate(tcx, free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates; @@ -2935,7 +2921,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // let unnormalized_env = ty::ParameterEnvironment { - free_substs: tcx.mk_substs(free_substs), + free_substs: free_substs, implicit_region_bound: ty::ReScope(free_id_outlive), caller_bounds: predicates, free_id_outlive: free_id_outlive, diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index aa48474e50cf1..388e8926403fd 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -14,7 +14,7 @@ //! type equality, etc. use hir::def_id::DefId; -use ty::subst::{ParamSpace, Substs}; +use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; use std::rc::Rc; @@ -145,82 +145,44 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, -> RelateResult<'tcx, &'tcx Substs<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let mut substs = Substs::empty(); - - for &space in &ParamSpace::all() { - let a_tps = a_subst.types.get_slice(space); - let b_tps = b_subst.types.get_slice(space); - let t_variances = variances.map(|v| v.types.get_slice(space)); - let tps = relate_type_params(relation, t_variances, a_tps, b_tps)?; - substs.types.replace(space, tps); - } - - for &space in &ParamSpace::all() { - let a_regions = a_subst.regions.get_slice(space); - let b_regions = b_subst.regions.get_slice(space); - let r_variances = variances.map(|v| v.regions.get_slice(space)); - let regions = relate_region_params(relation, - r_variances, - a_regions, - b_regions)?; - substs.regions.replace(space, regions); - } - - Ok(relation.tcx().mk_substs(substs)) -} - -fn relate_type_params<'a, 'gcx, 'tcx, R>(relation: &mut R, - variances: Option<&[ty::Variance]>, - a_tys: &[Ty<'tcx>], - b_tys: &[Ty<'tcx>]) - -> RelateResult<'tcx, Vec>> - where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a -{ - if a_tys.len() != b_tys.len() { - return Err(TypeError::TyParamSize(expected_found(relation, - &a_tys.len(), - &b_tys.len()))); - } - - (0 .. a_tys.len()) - .map(|i| { - let a_ty = a_tys[i]; - let b_ty = b_tys[i]; - let v = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(v, &a_ty, &b_ty) - }) - .collect() -} + let tcx = relation.tcx(); + let mut result = Ok(()); + + let types = a_subst.types.map_enumerated(|(space, i, a_ty)| { + if result.is_err() { return tcx.types.err; } + + let b_ty = b_subst.types.get(space, i); + let variance = variances.map_or(ty::Invariant, |v| { + *v.types.get(space, i) + }); + match relation.relate_with_variance(variance, a_ty, b_ty) { + Ok(ty) => ty, + Err(e) => { + result = Err(e); + tcx.types.err + } + } + }); + result?; + + let regions = a_subst.regions.map_enumerated(|(space, i, a_r)| { + if result.is_err() { return ty::ReStatic; } + + let b_r = b_subst.regions.get(space, i); + let variance = variances.map_or(ty::Invariant, |v| { + *v.regions.get(space, i) + }); + match relation.relate_with_variance(variance, a_r, b_r) { + Ok(r) => r, + Err(e) => { + result = Err(e); + ty::ReStatic + } + } + }); + result?; -fn relate_region_params<'a, 'gcx, 'tcx, R>(relation: &mut R, - variances: Option<&[ty::Variance]>, - a_rs: &[ty::Region], - b_rs: &[ty::Region]) - -> RelateResult<'tcx, Vec> - where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a -{ - let num_region_params = a_rs.len(); - - debug!("relate_region_params(a_rs={:?}, \ - b_rs={:?}, variances={:?})", - a_rs, - b_rs, - variances); - - assert_eq!(num_region_params, - variances.map_or(num_region_params, - |v| v.len())); - - assert_eq!(num_region_params, b_rs.len()); - - (0..a_rs.len()) - .map(|i| { - let a_r = a_rs[i]; - let b_r = b_rs[i]; - let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, &a_r, &b_r) - }) - .collect() + Ok(Substs::new(tcx, types, regions)) } impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 14005c1bd8b76..9021b0587a013 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,7 +9,7 @@ // except according to those terms. use infer::type_variable; -use ty::subst::{self, VecPerParamSpace}; +use ty::subst::{Substs, VecPerParamSpace}; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -702,13 +702,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx subst::Substs<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let substs = subst::Substs { - regions: self.regions.fold_with(folder), - types: self.types.fold_with(folder) - }; - folder.tcx().mk_substs(substs) + let types = self.types.fold_with(folder); + let regions = self.regions.fold_with(folder); + Substs::new(folder.tcx(), types, regions) } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -839,6 +837,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { ty::Generics { types: self.types.fold_with(folder), regions: self.regions.fold_with(folder), + has_self: self.has_self } } @@ -1018,19 +1017,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::TypeScheme { - generics: self.generics.fold_with(folder), - ty: self.ty.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.generics.visit_with(visitor) || self.ty.visit_with(visitor) - } -} - impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::error::ExpectedFound { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 91214873f193d..f31b844f04fe6 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -359,18 +359,7 @@ pub struct ExistentialTraitRef<'tcx> { pub substs: &'tcx Substs<'tcx>, } -impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { - pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_ref: ty::TraitRef<'tcx>) - -> ty::ExistentialTraitRef<'tcx> { - let mut substs = trait_ref.substs.clone(); - substs.types.pop(subst::SelfSpace); - ty::ExistentialTraitRef { - def_id: trait_ref.def_id, - substs: tcx.mk_substs(substs) - } - } - +impl<'tcx> ExistentialTraitRef<'tcx> { pub fn input_types(&self) -> &[Ty<'tcx>] { // Select only the "input types" from a trait-reference. For // now this is all the types that appear in the @@ -382,7 +371,7 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { pub type PolyExistentialTraitRef<'tcx> = Binder>; -impl<'a, 'gcx, 'tcx> PolyExistentialTraitRef<'tcx> { +impl<'tcx> PolyExistentialTraitRef<'tcx> { pub fn def_id(&self) -> DefId { self.0.def_id } @@ -391,23 +380,6 @@ impl<'a, 'gcx, 'tcx> PolyExistentialTraitRef<'tcx> { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } - - /// Object types don't have a self-type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self-type. A common choice is `mk_err()` - /// or some skolemized type. - pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - self_ty: Ty<'tcx>) - -> ty::PolyTraitRef<'tcx> - { - // otherwise the escaping regions would be captured by the binder - assert!(!self_ty.has_escaping_regions()); - - self.map_bound(|trait_ref| TraitRef { - def_id: trait_ref.def_id, - substs: tcx.mk_substs(trait_ref.substs.with_self_ty(self_ty)), - }) - } } /// Binder is a binder for higher-ranked lifetimes. It is part of the diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 34e7899e2fddb..00537f9d6c5dc 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -34,43 +34,45 @@ pub struct Substs<'tcx> { } impl<'a, 'gcx, 'tcx> Substs<'tcx> { - pub fn new(t: VecPerParamSpace>, + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, + t: VecPerParamSpace>, r: VecPerParamSpace) - -> Substs<'tcx> + -> &'tcx Substs<'tcx> { - Substs { types: t, regions: r } + tcx.mk_substs(Substs { types: t, regions: r }) } - pub fn new_fn(t: Vec>, + pub fn new_fn(tcx: TyCtxt<'a, 'gcx, 'tcx>, + t: Vec>, r: Vec) - -> Substs<'tcx> + -> &'tcx Substs<'tcx> { - Substs::new(VecPerParamSpace::new(vec![], vec![], t), + Substs::new(tcx, VecPerParamSpace::new(vec![], vec![], t), VecPerParamSpace::new(vec![], vec![], r)) } - pub fn new_type(t: Vec>, + pub fn new_type(tcx: TyCtxt<'a, 'gcx, 'tcx>, + t: Vec>, r: Vec) - -> Substs<'tcx> + -> &'tcx Substs<'tcx> { - Substs::new(VecPerParamSpace::new(vec![], t, vec![]), + Substs::new(tcx, VecPerParamSpace::new(vec![], t, vec![]), VecPerParamSpace::new(vec![], r, vec![])) } - pub fn new_trait(t: Vec>, + pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>, + t: Vec>, r: Vec, s: Ty<'tcx>) - -> Substs<'tcx> + -> &'tcx Substs<'tcx> { - Substs::new(VecPerParamSpace::new(vec![s], t, vec![]), + Substs::new(tcx, VecPerParamSpace::new(vec![s], t, vec![]), VecPerParamSpace::new(vec![], r, vec![])) } - pub fn empty() -> Substs<'tcx> { - Substs { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), - } + pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { + Substs::new(tcx, VecPerParamSpace::empty(), + VecPerParamSpace::empty()) } /// Creates a Substs for generic parameter definitions, @@ -78,26 +80,57 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { /// The closures get to observe the Substs as they're /// being built, which can be used to correctly /// substitute defaults of type parameters. - pub fn from_generics(generics: &ty::Generics<'tcx>, - mut mk_region: FR, - mut mk_type: FT) - -> Substs<'tcx> + pub fn for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + mut mk_region: FR, + mut mk_type: FT) + -> &'tcx Substs<'tcx> where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { - let mut substs = Substs::empty(); + let defs = tcx.lookup_generics(def_id); + let mut substs = Substs { + types: VecPerParamSpace { + self_limit: 0, + type_limit: 0, + content: Vec::with_capacity(defs.types.content.len()) + }, + regions: VecPerParamSpace { + self_limit: 0, + type_limit: 0, + content: Vec::with_capacity(defs.regions.content.len()) + } + }; + for &space in &ParamSpace::all() { - for def in generics.regions.get_slice(space) { + for def in defs.regions.get_slice(space) { + assert_eq!(def.space, space); + assert!(space != SelfSpace); + let region = mk_region(def, &substs); - assert_eq!(substs.regions.len(def.space), def.index as usize); - substs.regions.push(def.space, region); + substs.regions.content.push(region); + + if space == TypeSpace { + substs.regions.type_limit += 1; + } } - for def in generics.types.get_slice(space) { + + for def in defs.types.get_slice(space) { + assert_eq!(def.space, space); + let ty = mk_type(def, &substs); - assert_eq!(substs.types.len(def.space), def.index as usize); - substs.types.push(def.space, ty); + substs.types.content.push(ty); + + if space == SelfSpace { + substs.types.self_limit += 1; + } + + if space <= TypeSpace { + substs.types.type_limit += 1; + } } } - substs + + Substs::new(tcx, substs.types, substs.regions) } pub fn is_noop(&self) -> bool { @@ -112,66 +145,32 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { *self.regions.get(def.space, def.index as usize) } - pub fn self_ty(&self) -> Option> { - self.types.get_self().cloned() - } - - pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> { - assert!(self.self_ty().is_none()); - let mut s = (*self).clone(); - s.types.push(SelfSpace, self_ty); - s - } - - pub fn erase_regions(self) -> Substs<'tcx> { - let Substs { types, regions } = self; - let regions = regions.map(|_| ty::ReErased); - Substs { types: types, regions: regions } - } - - pub fn with_method(self, - m_types: Vec>, - m_regions: Vec) - -> Substs<'tcx> - { - let Substs { types, regions } = self; - let types = types.with_slice(FnSpace, &m_types); - let regions = regions.with_slice(FnSpace, &m_regions); - Substs { types: types, regions: regions } - } - - pub fn with_method_from(&self, - meth_substs: &Substs<'tcx>) - -> Substs<'tcx> - { - let Substs { types, regions } = self.clone(); - let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace)); - let regions = regions.with_slice(FnSpace, meth_substs.regions.get_slice(FnSpace)); - Substs { types: types, regions: regions } - } - - pub fn with_method_from_subst(&self, other: &Substs<'tcx>) -> Substs<'tcx> { - let Substs { types, regions } = self.clone(); - let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace)); - let regions = regions.with_slice(FnSpace, other.regions.get_slice(FnSpace)); - Substs { types: types, regions: regions } - } - - /// Creates a trait-ref out of this substs, ignoring the FnSpace substs - pub fn to_trait_ref(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_id: DefId) - -> ty::TraitRef<'tcx> { - let Substs { mut types, mut regions } = self.clone(); - types.truncate(FnSpace, 0); - regions.truncate(FnSpace, 0); - - ty::TraitRef { - def_id: trait_id, - substs: tcx.mk_substs(Substs { types: types, regions: regions }) - } + /// Transform from substitutions for a child of `source_ancestor` + /// (e.g. a trait or impl) to substitutions for the same child + /// in a different item, with `target_substs` as the base for + /// the target impl/trait, with the source child-specific + /// parameters (e.g. method parameters) on top of that base. + pub fn rebase_onto(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + source_ancestor: DefId, + target_substs: &Substs<'tcx>) + -> &'tcx Substs<'tcx> { + let defs = tcx.lookup_generics(source_ancestor); + assert_eq!(self.types.len(SelfSpace), defs.types.len(SelfSpace)); + assert_eq!(self.types.len(TypeSpace), defs.types.len(TypeSpace)); + assert_eq!(target_substs.types.len(FnSpace), 0); + assert_eq!(defs.types.len(FnSpace), 0); + assert_eq!(self.regions.len(TypeSpace), defs.regions.len(TypeSpace)); + assert_eq!(target_substs.regions.len(FnSpace), 0); + assert_eq!(defs.regions.len(FnSpace), 0); + + let Substs { mut types, mut regions } = target_substs.clone(); + types.content.extend(&self.types.as_full_slice()[defs.types.content.len()..]); + regions.content.extend(&self.regions.as_full_slice()[defs.regions.content.len()..]); + Substs::new(tcx, types, regions) } } -impl<'tcx> Encodable for Substs<'tcx> { +impl<'tcx> Encodable for &'tcx Substs<'tcx> { fn encode(&self, s: &mut S) -> Result<(), S::Error> { cstore::tls::with_encoding_context(s, |ecx, rbml_w| { ecx.encode_substs(rbml_w, self); @@ -180,19 +179,10 @@ impl<'tcx> Encodable for Substs<'tcx> { } } -impl<'tcx> Decodable for Substs<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - Ok(dcx.decode_substs(rbml_r)) - }) - } -} - impl<'tcx> Decodable for &'tcx Substs<'tcx> { fn decode(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> { let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - let substs = dcx.decode_substs(rbml_r); - dcx.tcx().mk_substs(substs) + dcx.decode_substs(rbml_r) }); Ok(substs) @@ -307,70 +297,6 @@ impl VecPerParamSpace { } } - /// Appends `value` to the vector associated with `space`. - /// - /// Unlike the `push` method in `Vec`, this should not be assumed - /// to be a cheap operation (even when amortized over many calls). - pub fn push(&mut self, space: ParamSpace, value: T) { - let (_, limit) = self.limits(space); - match space { - SelfSpace => { self.type_limit += 1; self.self_limit += 1; } - TypeSpace => { self.type_limit += 1; } - FnSpace => { } - } - self.content.insert(limit, value); - } - - /// Appends `values` to the vector associated with `space`. - /// - /// Unlike the `extend` method in `Vec`, this should not be assumed - /// to be a cheap operation (even when amortized over many calls). - pub fn extend>(&mut self, space: ParamSpace, values: I) { - // This could be made more efficient, obviously. - for item in values { - self.push(space, item); - } - } - - pub fn pop(&mut self, space: ParamSpace) -> Option { - let (start, limit) = self.limits(space); - if start == limit { - None - } else { - match space { - SelfSpace => { self.type_limit -= 1; self.self_limit -= 1; } - TypeSpace => { self.type_limit -= 1; } - FnSpace => {} - } - if self.content.is_empty() { - None - } else { - Some(self.content.remove(limit - 1)) - } - } - } - - pub fn truncate(&mut self, space: ParamSpace, len: usize) { - // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n). - while self.len(space) > len { - self.pop(space); - } - } - - pub fn replace(&mut self, space: ParamSpace, elems: Vec) { - // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n). - self.truncate(space, 0); - for t in elems { - self.push(space, t); - } - } - - pub fn get_self<'a>(&'a self) -> Option<&'a T> { - let v = self.get_slice(SelfSpace); - assert!(v.len() <= 1); - if v.is_empty() { None } else { Some(&v[0]) } - } - pub fn len(&self, space: ParamSpace) -> usize { self.get_slice(space).len() } @@ -384,19 +310,6 @@ impl VecPerParamSpace { &self.content[start.. limit] } - pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] { - let (start, limit) = self.limits(space); - &mut self.content[start.. limit] - } - - pub fn opt_get<'a>(&'a self, - space: ParamSpace, - index: usize) - -> Option<&'a T> { - let v = self.get_slice(space); - if index < v.len() { Some(&v[index]) } else { None } - } - pub fn get<'a>(&'a self, space: ParamSpace, index: usize) -> &'a T { &self.get_slice(space)[index] } @@ -409,12 +322,6 @@ impl VecPerParamSpace { &self.content } - pub fn all_vecs

(&self, mut pred: P) -> bool where - P: FnMut(&[T]) -> bool, - { - ParamSpace::all().iter().all(|&space| { pred(self.get_slice(space)) }) - } - pub fn all

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { self.as_full_slice().iter().all(pred) } @@ -424,7 +331,7 @@ impl VecPerParamSpace { } pub fn is_empty(&self) -> bool { - self.all_vecs(|v| v.is_empty()) + self.content.is_empty() } pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { @@ -442,18 +349,6 @@ impl VecPerParamSpace { self.self_limit, self.type_limit) } - - pub fn with_slice(mut self, space: ParamSpace, slice: &[T]) - -> VecPerParamSpace - where T: Clone - { - assert!(self.is_empty_in(space)); - for t in slice { - self.push(space, t.clone()); - } - - self - } } #[derive(Clone)] @@ -581,7 +476,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { // the specialized routine `ty::replace_late_regions()`. match r { ty::ReEarlyBound(data) => { - match self.substs.regions.opt_get(data.space, data.index as usize) { + match self.substs.regions.get_slice(data.space).get(data.index as usize) { Some(&r) => { self.shift_region_through_binders(r) } @@ -637,7 +532,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.types.opt_get(p.space, p.idx as usize); + let opt_ty = self.substs.types.get_slice(p.space).get(p.idx as usize); let ty = match opt_ty { Some(t) => *t, None => { @@ -718,3 +613,67 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { ty::fold::shift_region(region, self.region_binders_passed) } } + +// Helper methods that modify substitutions. + +impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { + pub fn from_method(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_id: DefId, + substs: &Substs<'tcx>) + -> ty::TraitRef<'tcx> { + let Substs { mut types, mut regions } = substs.clone(); + let defs = tcx.lookup_generics(trait_id); + types.content.truncate(defs.types.type_limit); + regions.content.truncate(defs.regions.type_limit); + + ty::TraitRef { + def_id: trait_id, + substs: Substs::new(tcx, types, regions) + } + } +} + +impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { + pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_ref: ty::TraitRef<'tcx>) + -> ty::ExistentialTraitRef<'tcx> { + let Substs { mut types, regions } = trait_ref.substs.clone(); + + assert_eq!(types.self_limit, 1); + types.self_limit = 0; + types.type_limit -= 1; + types.content.remove(0); + + ty::ExistentialTraitRef { + def_id: trait_ref.def_id, + substs: Substs::new(tcx, types, regions) + } + } +} + +impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyTraitRef<'tcx> { + // otherwise the escaping regions would be captured by the binder + assert!(!self_ty.has_escaping_regions()); + + self.map_bound(|trait_ref| { + let Substs { mut types, regions } = trait_ref.substs.clone(); + + assert_eq!(types.self_limit, 0); + types.self_limit = 1; + types.type_limit += 1; + types.content.insert(0, self_ty); + + ty::TraitRef { + def_id: trait_ref.def_id, + substs: Substs::new(tcx, types, regions) + } + }) + } +} diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index a76dfc35dc1d3..61285e8f8b0a5 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -34,7 +34,7 @@ pub struct TraitDef<'tcx> { /// `Eq`, there is a single bound `Self : Eq`). This is so that /// default methods get to assume that the `Self` parameters /// implements the trait. - pub generics: ty::Generics<'tcx>, + pub generics: &'tcx ty::Generics<'tcx>, pub trait_ref: ty::TraitRef<'tcx>, @@ -76,7 +76,7 @@ pub struct TraitDef<'tcx> { impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { pub fn new(unsafety: hir::Unsafety, paren_sugar: bool, - generics: ty::Generics<'tcx>, + generics: &'tcx ty::Generics<'tcx>, trait_ref: ty::TraitRef<'tcx>, associated_type_names: Vec) -> TraitDef<'tcx> { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 3c1f6e9199220..5a73439beac6e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -11,7 +11,6 @@ //! misc. type-system utilities too small to deserve their own file use hir::def_id::DefId; -use ty::subst; use infer::InferCtxt; use hir::pat_util; use traits::{self, Reveal}; @@ -695,12 +694,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { return false; } - let types_a = substs_a.types.get_slice(subst::TypeSpace); - let types_b = substs_b.types.get_slice(subst::TypeSpace); + let types_a = substs_a.types.as_full_slice(); + let types_b = substs_b.types.as_full_slice(); - let mut pairs = types_a.iter().zip(types_b); - - pairs.all(|(&a, &b)| same_type(a, b)) + types_a.iter().zip(types_b).all(|(&a, &b)| same_type(a, b)) } _ => { a == b diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index fb0b6413fab40..cdbd307052364 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; -use ty::subst::{self, Subst}; +use ty::subst::{self, Subst, Substs}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyStruct, TyEnum}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; @@ -65,69 +65,57 @@ pub enum Ns { fn number_of_supplied_defaults<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &subst::Substs, space: subst::ParamSpace, - generics: ty::Generics<'tcx>) + generics: &ty::Generics<'tcx>) -> usize { - let has_self = substs.self_ty().is_some(); let ty_params = generics.types.get_slice(space); let tps = substs.types.get_slice(space); if ty_params.last().map_or(false, |def| def.default.is_some()) { let substs = tcx.lift(&substs); ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| { - match def.default { - Some(default) => { - if !has_self && default.has_self_ty() { - // In an object type, there is no `Self`, and - // thus if the default value references Self, - // the user will be required to give an - // explicit value. We can't even do the - // substitution below to check without causing - // an ICE. (#18956). - false - } else { - let default = tcx.lift(&default); - substs.and_then(|substs| default.subst(tcx, substs)) - == Some(actual) - } - } - None => false - } + substs.and_then(|substs| def.default.subst(tcx, substs)) + == Some(actual) }).count() } else { 0 } } -pub fn parameterized(f: &mut fmt::Formatter, - substs: &subst::Substs, - did: DefId, - ns: Ns, - projections: &[ty::ProjectionPredicate], - get_generics: GG) - -> fmt::Result - where GG: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) - -> Option> -{ - if let (Ns::Value, Some(self_ty)) = (ns, substs.self_ty()) { - write!(f, "<{} as ", self_ty)?; - } +pub fn parameterized(f: &mut fmt::Formatter, + substs: &subst::Substs, + did: DefId, + ns: Ns, + projections: &[ty::ProjectionPredicate]) + -> fmt::Result { + let (fn_trait_kind, verbose, item_name, is_in_trait) = ty::tls::with(|tcx| { + let is_in_trait = ns == Ns::Value && tcx.trait_of_item(did).is_some(); + if is_in_trait { + write!(f, "<{} as ", substs.types.get(subst::SelfSpace, 0))?; + } - let (fn_trait_kind, verbose, item_name) = ty::tls::with(|tcx| { let (did, item_name) = if ns == Ns::Value { // Try to get the impl/trait parent, if this is an // associated value item (method or constant). - tcx.trait_of_item(did).or_else(|| tcx.impl_of_method(did)) - .map_or((did, None), |parent| (parent, Some(tcx.item_name(did)))) + tcx.trait_of_item(did).or_else(|| { + // An impl could be a trait impl or an inherent one. + tcx.impl_of_method(did).map(|impl_def_id| { + tcx.trait_id_of_impl(impl_def_id) + .unwrap_or(impl_def_id) + }) + }).map_or((did, None), |parent| (parent, Some(tcx.item_name(did)))) } else { (did, None) }; write!(f, "{}", tcx.item_path_str(did))?; - Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose(), item_name)) + Ok((tcx.lang_items.fn_trait_kind(did), + tcx.sess.verbose(), + item_name, + is_in_trait)) })?; if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { let projection_ty = projections[0].ty; - if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty { + if let TyTuple(ref args) = substs.types.get(subst::TypeSpace, 0).sty { return fn_sig(f, args, false, projection_ty); } } @@ -176,11 +164,8 @@ pub fn parameterized(f: &mut fmt::Formatter, 0 } else { ty::tls::with(|tcx| { - if let Some(generics) = get_generics(tcx) { - number_of_supplied_defaults(tcx, substs, subst::TypeSpace, generics) - } else { - 0 - } + let generics = tcx.lookup_generics(did); + number_of_supplied_defaults(tcx, substs, subst::TypeSpace, generics) }) }; @@ -204,7 +189,7 @@ pub fn parameterized(f: &mut fmt::Formatter, if ns == Ns::Value { empty.set(true); - if substs.self_ty().is_some() { + if is_in_trait { write!(f, ">")?; } @@ -288,7 +273,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, /// projection bounds, so we just stuff them altogether. But in /// reality we should eventually sort things out better. #[derive(Clone, Debug)] -struct TraitAndProjections<'tcx>(ty::ExistentialTraitRef<'tcx>, +struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec>); impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> { @@ -307,8 +292,7 @@ impl<'tcx> fmt::Display for TraitAndProjections<'tcx> { parameterized(f, trait_ref.substs, trait_ref.def_id, Ns::Type, - projection_bounds, - |tcx| Some(tcx.lookup_trait_def(trait_ref.def_id).generics.clone())) + projection_bounds) } } @@ -316,12 +300,16 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Generate the main trait ref, including associated types. ty::tls::with(|tcx| { - let principal = tcx.lift(&self.principal.0) - .expect("could not lift TraitRef for printing"); + // Use a type that can't appear in defaults of type parameters. + let dummy_self = tcx.mk_infer(ty::FreshTy(0)); + + let principal = tcx.lift(&self.principal) + .expect("could not lift TraitRef for printing") + .with_self_ty(tcx, dummy_self).0; let projections = self.projection_bounds.iter().map(|p| { - let projection = tcx.lift(p) - .expect("could not lift projection for printing"); - projection.with_self_ty(tcx, tcx.types.err).0 + tcx.lift(p) + .expect("could not lift projection for printing") + .with_self_ty(tcx, dummy_self).0 }).collect(); let tap = ty::Binder(TraitAndProjections(principal, projections)); @@ -380,7 +368,7 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { } } -impl<'tcx> fmt::Debug for subst::Substs<'tcx> { +impl<'tcx> fmt::Debug for Substs<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Substs[types={:?}, regions={:?}]", self.types, self.regions) @@ -404,7 +392,14 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", *self) + ty::tls::with(|tcx| { + let dummy_self = tcx.mk_infer(ty::FreshTy(0)); + + let trait_ref = tcx.lift(&ty::Binder(*self)) + .expect("could not lift TraitRef for printing") + .with_self_ty(tcx, dummy_self).0; + parameterized(f, trait_ref.substs, trait_ref.def_id, Ns::Type, &[]) + }) } } @@ -813,15 +808,7 @@ impl fmt::Display for ty::Binder> impl<'tcx> fmt::Display for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - parameterized(f, self.substs, self.def_id, Ns::Type, &[], - |tcx| Some(tcx.lookup_trait_def(self.def_id).generics.clone())) - } -} - -impl<'tcx> fmt::Display for ty::ExistentialTraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - parameterized(f, self.substs, self.def_id, Ns::Type, &[], - |tcx| Some(tcx.lookup_trait_def(self.def_id).generics.clone())) + parameterized(f, self.substs, self.def_id, Ns::Type, &[]) } } @@ -874,9 +861,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } write!(f, "{} {{", bare_fn.sig.0)?; - parameterized( - f, substs, def_id, Ns::Value, &[], - |tcx| tcx.opt_lookup_item_type(def_id).map(|t| t.generics))?; + parameterized(f, substs, def_id, Ns::Value, &[])?; write!(f, "}}") } TyFnPtr(ref bare_fn) => { @@ -899,12 +884,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { !tcx.tcache.borrow().contains_key(&def.did) { write!(f, "{}<..>", tcx.item_path_str(def.did)) } else { - parameterized( - f, substs, def.did, Ns::Type, &[], - |tcx| { - tcx.opt_lookup_item_type(def.did). - map(|t| t.generics) - }) + parameterized(f, substs, def.did, Ns::Type, &[]) } }) } @@ -916,7 +896,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { // by looking up the projections associated with the def_id. let item_predicates = tcx.lookup_predicates(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { - tcx.mk_substs(subst::Substs::empty()) + Substs::empty(tcx) }); let bounds = item_predicates.instantiate(tcx, substs); diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index f6e9484eda1a4..df91ec2b98d5d 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -859,10 +859,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil())); let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = tcx.mk_substs(Substs::new( + let substs = Substs::new(tcx, VecPerParamSpace::new(vec![], vec![], vec![ty]), - VecPerParamSpace::new(vec![], vec![], vec![]) - )); + VecPerParamSpace::new(vec![], vec![], vec![])); let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); self.patch.new_block(BasicBlockData { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 73b54c4374ffb..d71add3258fbd 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -22,8 +22,9 @@ use rustc::traits; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::pat_util::def_to_path; -use rustc::ty::{self, Ty, TyCtxt, subst}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; +use rustc::ty::subst::Substs; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; @@ -93,7 +94,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// This generally happens in late/trans const evaluation. pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, - substs: Option<&'tcx subst::Substs<'tcx>>) + substs: Option<&'tcx Substs<'tcx>>) -> Option<(&'tcx Expr, Option>)> { if let Some(node_id) = tcx.map.as_local_node_id(def_id) { match tcx.map.find(node_id) { @@ -110,7 +111,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we have a trait item and the substitutions for it, // `resolve_trait_associated_const` will select an impl // or the default. - let trait_id = tcx.trait_of_item(def_id).unwrap(); + let trait_id = tcx.map.get_parent(node_id); + let trait_id = tcx.map.local_def_id(trait_id); resolve_trait_associated_const(tcx, ti, trait_id, substs) } else { // Technically, without knowing anything about the @@ -1045,16 +1047,14 @@ fn infer<'a, 'tcx>(i: ConstInt, fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ti: &'tcx hir::TraitItem, trait_id: DefId, - rcvr_substs: &'tcx subst::Substs<'tcx>) + rcvr_substs: &'tcx Substs<'tcx>) -> Option<(&'tcx Expr, Option>)> { - let trait_ref = ty::Binder( - rcvr_substs.clone().erase_regions().to_trait_ref(tcx, trait_id) - ); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); + tcx.populate_implementations_for_trait_if_necessary(trait_id); tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 7711091685d38..c84b195dd4b30 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -21,7 +21,7 @@ use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; use rustc::ty::subst; -use rustc::ty::subst::Subst; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; @@ -678,8 +678,8 @@ fn subst_ty_renumber_bound() { env.t_fn(&[t_param], env.t_nil()) }; - let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]); - let t_substituted = t_source.subst(env.infcx.tcx, &substs); + let substs = Substs::new_type(env.infcx.tcx, vec![t_rptr_bound1], vec![]); + let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) let t_expected = { @@ -713,8 +713,8 @@ fn subst_ty_renumber_some_bounds() { env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) }; - let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]); - let t_substituted = t_source.subst(env.infcx.tcx, &substs); + let substs = Substs::new_type(env.infcx.tcx, vec![t_rptr_bound1], vec![]); + let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = (&'a isize, fn(&'a isize)) // @@ -775,8 +775,8 @@ fn subst_region_renumber_region() { env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) }; - let substs = subst::Substs::new_type(vec![], vec![re_bound1]); - let t_substituted = t_source.subst(env.infcx.tcx, &substs); + let substs = Substs::new_type(env.infcx.tcx, vec![], vec![re_bound1]); + let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) // diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ed17f3533d49f..61d927239828b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -465,16 +465,14 @@ impl LateLintPass for MissingCopyImplementations { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_struct(def, - cx.tcx.mk_substs(Substs::empty()))) + (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_enum(def, - cx.tcx.mk_substs(Substs::empty()))) + (def, cx.tcx.mk_enum(def, Substs::empty(cx.tcx))) } _ => return, }; @@ -898,7 +896,7 @@ impl LateLintPass for UnconditionalRecursion { // A trait method, from any number of possible sources. // Attempt to select a concrete impl before checking. ty::TraitContainer(trait_def_id) => { - let trait_ref = callee_substs.to_trait_ref(tcx, trait_def_id); + let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); let trait_ref = ty::Binder(trait_ref); let span = tcx.map.span(expr_id); let obligation = @@ -918,8 +916,7 @@ impl LateLintPass for UnconditionalRecursion { // If `T` is `Self`, then this call is inside // a default method definition. Ok(Some(traits::VtableParam(_))) => { - let self_ty = callee_substs.self_ty(); - let on_self = self_ty.map_or(false, |t| t.is_self()); + let on_self = trait_ref.self_ty().is_self(); // We can only be recurring in a default // method if we're being called literally // on the `Self` type. diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index c552e612504e9..1b00eee76f69b 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -34,7 +34,7 @@ use middle::const_qualif::ConstQualif; use rustc::hir::def::{self, Def}; use rustc::hir::def_id::DefId; use middle::region; -use rustc::ty::subst; +use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; @@ -507,7 +507,7 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { Ok(this.read_ty(dcx)) }).unwrap(), substs: this.read_struct_field("substs", 3, |this| { - Ok(dcx.tcx.mk_substs(this.read_substs(dcx))) + Ok(this.read_substs(dcx)) }).unwrap() })) }).unwrap() @@ -525,7 +525,7 @@ trait rbml_writer_helpers<'tcx> { fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - substs: &subst::Substs<'tcx>); + substs: &Substs<'tcx>); fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, adj: &adjustment::AutoAdjustment<'tcx>); @@ -569,7 +569,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - substs: &subst::Substs<'tcx>) { + substs: &Substs<'tcx>) { self.emit_opaque(|this| Ok(tyencode::enc_substs(&mut this.cursor, &ecx.ty_str_ctxt(), substs))); @@ -839,7 +839,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::Predicate<'tcx>; fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> subst::Substs<'tcx>; + -> &'tcx Substs<'tcx>; fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture; fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -859,7 +859,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { cdata: &cstore::CrateMetadata) -> Vec>; fn read_substs_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: &cstore::CrateMetadata) - -> subst::Substs<'tcx>; + -> &'tcx Substs<'tcx>; } impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { @@ -884,7 +884,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_substs_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, cdata: &cstore::CrateMetadata) - -> subst::Substs<'tcx> + -> &'tcx Substs<'tcx> { self.read_opaque(|_, doc| { Ok( @@ -946,7 +946,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> subst::Substs<'tcx> { + -> &'tcx Substs<'tcx> { self.read_opaque(|_, doc| { Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc, &mut |d| convert_def_id(dcx, d)) @@ -1140,7 +1140,7 @@ fn decode_side_tables(dcx: &DecodeContext, } c::tag_table_item_subst => { let item_substs = ty::ItemSubsts { - substs: dcx.tcx.mk_substs(val_dsr.read_substs(dcx)) + substs: val_dsr.read_substs(dcx) }; dcx.tcx.tables.borrow_mut().item_substs.insert( id, item_substs); diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 0011b59c70ed3..99a3f3b00c8b0 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -196,16 +196,11 @@ pub const tag_attribute_is_sugared_doc: usize = 0x8c; // GAP 0x8d pub const tag_items_data_region: usize = 0x8e; -pub const tag_region_param_def: usize = 0x8f; -pub const tag_region_param_def_ident: usize = 0x90; -pub const tag_region_param_def_def_id: usize = 0x91; -pub const tag_region_param_def_space: usize = 0x92; -pub const tag_region_param_def_index: usize = 0x93; +pub const tag_item_generics: usize = 0x8f; +// GAP 0x90, 0x91, 0x92, 0x93, 0x94 -pub const tag_type_param_def: usize = 0x94; - -pub const tag_item_generics: usize = 0x95; -pub const tag_method_ty_generics: usize = 0x96; +pub const tag_item_predicates: usize = 0x95; +// GAP 0x96 pub const tag_predicate: usize = 0x97; // GAP 0x98, 0x99 diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 2cdbd1b86012d..f6d698eb969d8 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -86,7 +86,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> ty::TypeScheme<'tcx> + -> Ty<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); @@ -109,6 +109,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_super_predicates(&cdata, def.index, tcx) } + fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx ty::Generics<'tcx> + { + self.dep_graph.read(DepNode::MetaData(def)); + let cdata = self.get_crate_data(def.krate); + decoder::get_generics(&cdata, def.index, tcx) + } + fn item_attrs(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); @@ -231,11 +239,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_parent_impl(&*cdata, impl_def.index) } - fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option - { + fn trait_of_item(&self, def_id: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); - decoder::get_trait_of_item(&cdata, def_id.index, tcx) + decoder::get_trait_of_item(&cdata, def_id.index) } fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index eeb1859c01311..e42825ef1e549 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -264,11 +264,6 @@ fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: }) } -pub fn item_type<'a, 'tcx>(_item_id: DefId, item: rbml::Doc, - tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> { - doc_type(item, tcx, cdata) -} - fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> ty::TraitRef<'tcx> { TyDecoder::with_doc(tcx, cdata.cnum, doc, @@ -383,7 +378,7 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> { let item_doc = cdata.lookup_item(item_id); - let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); + let generics = doc_generics(item_doc, tcx, cdata); let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); @@ -493,7 +488,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, // from the ctor. debug!("evaluating the ctor-type of {:?}", variant.name); - let ctor_ty = get_type(cdata, variant.did.index, tcx).ty; + let ctor_ty = get_type(cdata, variant.did.index, tcx); debug!("evaluating the ctor-type of {:?}.. {:?}", variant.name, ctor_ty); @@ -513,7 +508,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, } else { for field in &variant.fields { debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); - let ty = get_type(cdata, field.did.index, tcx).ty; + let ty = get_type(cdata, field.did.index, tcx); field.fulfill_ty(ty); debug!("evaluating the type of {:?}::{:?}: {:?}", variant.name, field.name, ty); @@ -530,7 +525,7 @@ pub fn get_predicates<'a, 'tcx>(cdata: Cmd, -> ty::GenericPredicates<'tcx> { let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, tag_item_generics) + doc_predicates(item_doc, tcx, cdata, tag_item_predicates) } pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd, @@ -542,17 +537,20 @@ pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd, doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates) } +pub fn get_generics<'a, 'tcx>(cdata: Cmd, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> &'tcx ty::Generics<'tcx> +{ + let item_doc = cdata.lookup_item(item_id); + doc_generics(item_doc, tcx, cdata) +} + pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::TypeScheme<'tcx> + -> Ty<'tcx> { let item_doc = cdata.lookup_item(id); - let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx, - cdata); - let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); - ty::TypeScheme { - generics: generics, - ty: t - } + doc_type(item_doc, tcx, cdata) } pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { @@ -960,8 +958,8 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a })) } Some('r') | Some('p') => { - let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics); - let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); + let generics = doc_generics(item_doc, tcx, cdata); + let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates); let ity = tcx.lookup_item_type(def_id).ty; let fty = match ity.sty { ty::TyFnDef(_, _, fty) => fty, @@ -1393,10 +1391,7 @@ pub fn each_implementation_for_trait(cdata: Cmd, } } -pub fn get_trait_of_item<'a, 'tcx>(cdata: Cmd, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option { +pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option { let item_doc = cdata.lookup_item(id); let parent_item_id = match item_parent_item(cdata, item_doc) { None => return None, @@ -1405,10 +1400,6 @@ pub fn get_trait_of_item<'a, 'tcx>(cdata: Cmd, let parent_item_doc = cdata.lookup_item(parent_item_id.index); match item_family(parent_item_doc) { Trait => Some(item_def_id(parent_item_doc, cdata)), - Impl | DefaultImpl => { - reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref) - .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id) - } _ => None } } @@ -1537,11 +1528,7 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, }; let applicable = match item_family(item_doc) { ImmStatic | MutStatic => true, - Fn => { - let ty::TypeScheme { generics, .. } = get_type(cdata, id, tcx); - let no_generics = generics.types.is_empty(); - no_generics - }, + Fn => get_generics(cdata, id, tcx).types.is_empty(), _ => false, }; @@ -1573,30 +1560,13 @@ pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: Cmd, - tag: usize) - -> ty::Generics<'tcx> + cdata: Cmd) + -> &'tcx ty::Generics<'tcx> { - let doc = reader::get_doc(base_doc, tag); - - let mut generics = ty::Generics::empty(); - for p in reader::tagged_docs(doc, tag_type_param_def) { - let bd = - TyDecoder::with_doc(tcx, cdata.cnum, p, - &mut |did| translate_def_id(cdata, did)) - .parse_type_param_def(); - generics.types.push(bd.space, bd); - } - - for p in reader::tagged_docs(doc, tag_region_param_def) { - let bd = - TyDecoder::with_doc(tcx, cdata.cnum, p, - &mut |did| translate_def_id(cdata, did)) - .parse_region_param_def(); - generics.regions.push(bd.space, bd); - } - - generics + let doc = reader::get_doc(base_doc, tag_item_generics); + TyDecoder::with_doc(tcx, cdata.cnum, doc, + &mut |did| translate_def_id(cdata, did)) + .parse_generics() } fn doc_predicate<'a, 'tcx>(cdata: Cmd, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d19eb6391820a..1e74b3c1ef48f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -175,8 +175,7 @@ fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, index: &mut CrateIndex<'a, 'tcx>, scheme: &ty::TypeScheme<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - encode_generics(rbml_w, ecx, index, - &scheme.generics, &predicates, tag_item_generics); + encode_generics(rbml_w, ecx, index, &scheme.generics, &predicates); encode_type(ecx, rbml_w, scheme.ty); } @@ -510,50 +509,26 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, index: &mut CrateIndex<'a, 'tcx>, generics: &ty::Generics<'tcx>, - predicates: &ty::GenericPredicates<'tcx>, - tag: usize) + predicates: &ty::GenericPredicates<'tcx>) { - rbml_w.start_tag(tag); - - for param in generics.types.as_full_slice() { - rbml_w.start_tag(tag_type_param_def); - tyencode::enc_type_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); - } - - // Region parameters - for param in generics.regions.as_full_slice() { - rbml_w.start_tag(tag_region_param_def); - tyencode::enc_region_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); - } - - encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); - + rbml_w.start_tag(tag_item_generics); + tyencode::enc_generics(rbml_w.writer, &ecx.ty_str_ctxt(), generics); + rbml_w.mark_stable_position(); rbml_w.end_tag(); -} -fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, - _ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'a, 'tcx>, - predicates: &ty::GenericPredicates<'tcx>) -{ - for predicate in &predicates.predicates { - rbml_w.wr_tagged_u32(tag_predicate, - index.add_xref(XRef::Predicate(predicate.clone()))); - } + encode_predicates(rbml_w, index, predicates, tag_item_predicates); } fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a,'tcx>, index: &mut CrateIndex<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { rbml_w.start_tag(tag); - encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); + for predicate in &predicates.predicates { + rbml_w.wr_tagged_u32(tag_predicate, + index.add_xref(XRef::Predicate(predicate.clone()))); + } rbml_w.end_tag(); } @@ -564,8 +539,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.name); encode_generics(rbml_w, ecx, index, - &method_ty.generics, &method_ty.predicates, - tag_method_ty_generics); + &method_ty.generics, &method_ty.predicates); encode_visibility(rbml_w, method_ty.vis); encode_explicit_self(rbml_w, &method_ty.explicit_self); match method_ty.explicit_self { @@ -695,7 +669,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &ii.attrs); encode_defaultness(rbml_w, ii.defaultness); } else { - encode_predicates(rbml_w, ecx, index, + encode_predicates(rbml_w, index, &ecx.tcx.lookup_predicates(associated_type.def_id), tag_item_generics); } @@ -1134,9 +1108,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); encode_associated_type_names(rbml_w, &trait_def.associated_type_names); encode_generics(rbml_w, ecx, index, - &trait_def.generics, &trait_predicates, - tag_item_generics); - encode_predicates(rbml_w, ecx, index, + &trait_def.generics, &trait_predicates); + encode_predicates(rbml_w, index, &tcx.lookup_super_predicates(def_id), tag_item_super_predicates); encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs index 23142ca80ef0e..6e78cbcd28e73 100644 --- a/src/librustc_metadata/tls_context.rs +++ b/src/librustc_metadata/tls_context.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> { ty } - fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> Substs<'tcx> { + fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx> { let def_id_convert = &mut |did| { decoder::translate_def_id(self.crate_metadata, did) }; diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 11c155cbd5b9f..3f0fa9073aa36 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -20,8 +20,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use middle::region; -use rustc::ty::subst; -use rustc::ty::subst::VecPerParamSpace; +use rustc::ty::subst::{self, Substs, VecPerParamSpace}; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rbml; @@ -132,21 +131,31 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { fn parse_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T, { - let mut r = VecPerParamSpace::empty(); - for &space in &subst::ParamSpace::all() { + let (mut a, mut b, mut c) = (vec![], vec![], vec![]); + for r in &mut [&mut a, &mut b, &mut c] { assert_eq!(self.next(), '['); while self.peek() != ']' { - r.push(space, f(self)); + r.push(f(self)); } assert_eq!(self.next(), ']'); } - r + VecPerParamSpace::new(a, b, c) } - pub fn parse_substs(&mut self) -> subst::Substs<'tcx> { + pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { let regions = self.parse_vec_per_param_space(|this| this.parse_region()); let types = self.parse_vec_per_param_space(|this| this.parse_ty()); - subst::Substs { types: types, regions: regions } + Substs::new(self.tcx, types, regions) + } + + pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> { + let regions = self.parse_vec_per_param_space(|this| this.parse_region_param_def()); + let types = self.parse_vec_per_param_space(|this| this.parse_type_param_def()); + self.tcx.alloc_generics(ty::Generics { + regions: regions, + types: types, + has_self: self.next() == 'S' + }) } fn parse_bound_region(&mut self) -> ty::BoundRegion { @@ -302,15 +311,17 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { - let def = self.parse_def(); - let substs = self.tcx.mk_substs(self.parse_substs()); - ty::TraitRef {def_id: def, substs: substs} + ty::TraitRef { + def_id: self.parse_def(), + substs: self.parse_substs() + } } pub fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> { - let def = self.parse_def(); - let substs = self.tcx.mk_substs(self.parse_substs()); - ty::ExistentialTraitRef {def_id: def, substs: substs} + ty::ExistentialTraitRef { + def_id: self.parse_def(), + substs: self.parse_substs() + } } pub fn parse_ty(&mut self) -> Ty<'tcx> { @@ -342,7 +353,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); - return tcx.mk_enum(def, self.tcx.mk_substs(substs)); + return tcx.mk_enum(def, substs); } 'x' => { assert_eq!(self.next(), '['); @@ -406,7 +417,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'F' => { let def_id = self.parse_def(); - let substs = self.tcx.mk_substs(self.parse_substs()); + let substs = self.parse_substs(); return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty()); } 'G' => { @@ -452,7 +463,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_struct(def, self.tcx.mk_substs(substs)); + return self.tcx.mk_struct(def, substs); } 'k' => { assert_eq!(self.next(), '['); @@ -464,7 +475,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } assert_eq!(self.next(), '.'); assert_eq!(self.next(), ']'); - return self.tcx.mk_closure(did, self.tcx.mk_substs(substs), tys); + return self.tcx.mk_closure(did, substs, tys); } 'P' => { assert_eq!(self.next(), '['); @@ -477,7 +488,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let def_id = self.parse_def(); let substs = self.parse_substs(); assert_eq!(self.next(), ']'); - return self.tcx.mk_anon(def_id, self.tcx.mk_substs(substs)); + return self.tcx.mk_anon(def_id, substs); } 'e' => { return tcx.types.err; @@ -622,7 +633,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { + fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { let name = self.parse_name(':'); let def_id = self.parse_def(); let space = self.parse_param_space(); @@ -644,7 +655,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { + fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { let name = self.parse_name(':'); let def_id = self.parse_def(); let space = self.parse_param_space(); diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 8deb1eb6ac31d..130d15485829a 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -19,8 +19,7 @@ use std::io::prelude::*; use rustc::hir::def_id::DefId; use middle::region; -use rustc::ty::subst; -use rustc::ty::subst::VecPerParamSpace; +use rustc::ty::subst::{self, Substs, VecPerParamSpace}; use rustc::ty::ParamTy; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FnvHashMap; @@ -266,13 +265,27 @@ fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Cursor>, } pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - substs: &subst::Substs<'tcx>) { + substs: &Substs<'tcx>) { enc_vec_per_param_space(w, cx, &substs.regions, |w, cx, &r| enc_region(w, cx, r)); enc_vec_per_param_space(w, cx, &substs.types, |w, cx, &ty| enc_ty(w, cx, ty)); } +pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, + generics: &ty::Generics<'tcx>) { + enc_vec_per_param_space(w, cx, &generics.regions, + |w, cx, r| enc_region_param_def(w, cx, r)); + enc_vec_per_param_space(w, cx, &generics.types, + |w, cx, ty| enc_type_param_def(w, cx, ty)); + + if generics.has_self { + write!(w, "S"); + } else { + write!(w, "N"); + } +} + pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: ty::Region) { match r { ty::ReLateBound(id, br) => { @@ -420,8 +433,8 @@ fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBound write!(w, "."); } -pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - v: &ty::TypeParameterDef<'tcx>) { +fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, + v: &ty::TypeParameterDef<'tcx>) { write!(w, "{}:{}|{}|{}|{}|", v.name, (cx.ds)(cx.tcx, v.def_id), v.space.to_uint(), v.index, (cx.ds)(cx.tcx, v.default_def_id)); @@ -429,8 +442,8 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx> enc_object_lifetime_default(w, cx, v.object_lifetime_default); } -pub fn enc_region_param_def(w: &mut Cursor>, cx: &ctxt, - v: &ty::RegionParameterDef) { +fn enc_region_param_def(w: &mut Cursor>, cx: &ctxt, + v: &ty::RegionParameterDef) { write!(w, "{}:{}|{}|{}|", v.name, (cx.ds)(cx.tcx, v.def_id), v.space.to_uint(), v.index); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 6af9ad02b91ba..229890483882c 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -750,7 +750,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> TerminatorKind<'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = tcx.mk_substs(Substs::new_fn(vec![data.item_ty], vec![])); + let substs = Substs::new_fn(tcx, vec![data.item_ty], vec![]); TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index df1fec75939b5..972e7f5be7075 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -147,16 +147,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { params: Vec>) -> (Ty<'tcx>, Literal<'tcx>) { let method_name = token::intern(method_name); - let substs = Substs::new_trait(params, vec![], self_ty); + let substs = Substs::new_trait(self.tcx, params, vec![], self_ty); for trait_item in self.tcx.trait_items(trait_def_id).iter() { match *trait_item { ty::ImplOrTraitItem::MethodTraitItem(ref method) => { if method.name == method_name { let method_ty = self.tcx.lookup_item_type(method.def_id); - let method_ty = method_ty.ty.subst(self.tcx, &substs); + let method_ty = method_ty.ty.subst(self.tcx, substs); return (method_ty, Literal::Item { def_id: method.def_id, - substs: self.tcx.mk_substs(substs), + substs: substs, }); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 16cd9186ce9bb..6c9cf1a5625b2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -299,8 +299,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = String::from("<"); result.push_str(&rustc::hir::print::ty_to_string(&ty)); - if let Some(def_id) = self.tcx - .trait_of_item(self.tcx.map.local_def_id(id)) { + if let Some(def_id) = self.tcx.trait_id_of_impl(impl_id) { result.push_str(" as "); result.push_str(&self.tcx.item_path_str(def_id)); } diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 27a8c1f1df476..d6866b27f98a5 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -895,7 +895,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, &format!("comparison of `{}`", rhs_t), StrEqFnLangItem); let args = [lhs_data, lhs_len, rhs_data, rhs_len]; - Callee::def(bcx.ccx(), did, bcx.tcx().mk_substs(Substs::empty())) + Callee::def(bcx.ccx(), did, Substs::empty(bcx.tcx())) .call(bcx, debug_loc, ArgVals(&args), None) } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 23c4258caf7bd..d48ec98a20dfb 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -48,7 +48,7 @@ use std; use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; -use rustc::ty::subst; +use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; use syntax::attr; @@ -544,7 +544,7 @@ impl<'tcx> Case<'tcx> { fn get_cases<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, adt: ty::AdtDef<'tcx>, - substs: &subst::Substs<'tcx>) + substs: &Substs<'tcx>) -> Vec> { adt.variants.iter().map(|vi| { let field_tys = vi.fields.iter().map(|field| { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 749a7495421ed..ee5d1d11fa0a6 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -218,7 +218,7 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Allocate space: let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem); - let r = Callee::def(bcx.ccx(), def_id, bcx.tcx().mk_substs(Substs::empty())) + let r = Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx())) .call(bcx, debug_loc, ArgVals(&[size, align]), None); Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) @@ -670,11 +670,9 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> CustomCoerceUnsized { - let trait_substs = Substs::new_trait(vec![target_ty], vec![], source_ty); - let trait_ref = ty::Binder(ty::TraitRef { def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), - substs: scx.tcx().mk_substs(trait_substs) + substs: Substs::new_trait(scx.tcx(), vec![target_ty], vec![], source_ty) }); match fulfill_obligation(scx, DUMMY_SP, trait_ref) { @@ -1410,7 +1408,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { common::validate_substs(instance.substs); (instance.substs, Some(instance.def), Some(inlined_id)) } - None => (ccx.tcx().mk_substs(Substs::empty()), None, None) + None => (Substs::empty(ccx.tcx()), None, None) }; let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id)); @@ -2175,7 +2173,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { Ok(id) => id, Err(s) => ccx.sess().fatal(&s) }; - let empty_substs = ccx.tcx().mk_substs(Substs::empty()); + let empty_substs = Substs::empty(ccx.tcx()); let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx).val; let args = { let opaque_rust_main = diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index aaec2a47025a2..d50959b5ab302 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -22,7 +22,7 @@ use back::symbol_names; use llvm::{self, ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; use rustc::hir::def_id::DefId; -use rustc::ty::subst; +use rustc::ty::subst::Substs; use rustc::traits; use rustc::hir::map as hir_map; use abi::{Abi, FnType}; @@ -105,13 +105,12 @@ impl<'tcx> Callee<'tcx> { /// Function or method definition. pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, - substs: &'tcx subst::Substs<'tcx>) + substs: &'tcx Substs<'tcx>) -> Callee<'tcx> { let tcx = ccx.tcx(); - if substs.self_ty().is_some() { - // Only trait methods can have a Self parameter. - return Callee::trait_method(ccx, def_id, substs); + if let Some(trait_id) = tcx.trait_of_item(def_id) { + return Callee::trait_method(ccx, trait_id, def_id, substs); } let maybe_node_id = inline::get_local_instance(ccx, def_id) @@ -144,24 +143,21 @@ impl<'tcx> Callee<'tcx> { /// Trait method, which has to be resolved to an impl method. pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>, + trait_id: DefId, def_id: DefId, - substs: &'tcx subst::Substs<'tcx>) + substs: &'tcx Substs<'tcx>) -> Callee<'tcx> { let tcx = ccx.tcx(); - let method_item = tcx.impl_or_trait_item(def_id); - let trait_id = method_item.container().id(); - let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); - let trait_ref = tcx.normalize_associated_type(&trait_ref); + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, substs); + let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref)); match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(vtable_impl) => { let impl_did = vtable_impl.impl_def_id; let mname = tcx.item_name(def_id); // create a concatenated set of substitutions which includes // those from the impl and those from the method: - let impl_substs = vtable_impl.substs.with_method_from(&substs); - let substs = tcx.mk_substs(impl_substs); - let mth = meth::get_impl_method(tcx, impl_did, substs, mname); + let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname); // Translate the function, bypassing Callee::def. // That is because default methods have the same ID as the @@ -275,7 +271,7 @@ impl<'tcx> Callee<'tcx> { /// Given a DefId and some Substs, produces the monomorphic item type. fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, - substs: &'tcx subst::Substs<'tcx>) + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { let ty = tcx.lookup_item_type(def_id).ty; monomorphize::apply_param_substs(tcx, substs, &ty) @@ -427,7 +423,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( /// - `substs`: values for each of the fn/method's parameters fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, - substs: &'tcx subst::Substs<'tcx>) + substs: &'tcx Substs<'tcx>) -> Datum<'tcx, Rvalue> { let tcx = ccx.tcx(); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 277110347d01d..82c86928783bc 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -732,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, create_fn_trans_item(scx.tcx(), exchange_free_fn_def_id, fn_substs, - scx.tcx().mk_substs(Substs::empty())); + Substs::empty(scx.tcx())); output.push(exchange_free_fn_trans_item); } @@ -753,8 +753,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, .drop_trait() .unwrap(); - let self_type_substs = scx.tcx().mk_substs( - Substs::empty().with_self_ty(ty)); + let self_type_substs = Substs::new_trait(scx.tcx(), vec![], vec![], ty); let trait_ref = ty::TraitRef { def_id: drop_trait_def_id, @@ -770,7 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let trans_item = create_fn_trans_item(scx.tcx(), destructor_did, substs, - scx.tcx().mk_substs(Substs::empty())); + Substs::empty(scx.tcx())); output.push(trans_item); } @@ -854,26 +853,15 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn_substs, param_substs); - let is_trait_method = scx.tcx().trait_of_item(fn_def_id).is_some(); - - if is_trait_method { + if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { match scx.tcx().impl_or_trait_item(fn_def_id) { ty::MethodTraitItem(ref method) => { - match method.container { - ty::TraitContainer(trait_def_id) => { - debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(scx, - method, - trait_def_id, - fn_substs, - param_substs) - } - ty::ImplContainer(_) => { - // This is already a concrete implementation - debug!(" => impl method"); - Some((fn_def_id, fn_substs)) - } - } + debug!(" => trait method, attempting to find impl"); + do_static_trait_method_dispatch(scx, + method, + trait_def_id, + fn_substs, + param_substs) } _ => bug!() } @@ -903,13 +891,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, callee_substs, param_substs); + let rcvr_substs = monomorphize::apply_param_substs(tcx, param_substs, &callee_substs); - - let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); - let trait_ref = tcx.normalize_associated_type(&trait_ref); - let vtbl = fulfill_obligation(scx, DUMMY_SP, trait_ref); + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); + let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -919,10 +906,10 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, substs: impl_substs, nested: _ }) => { - let callee_substs = impl_substs.with_method_from(&rcvr_substs); let impl_method = meth::get_impl_method(tcx, + rcvr_substs, impl_did, - tcx.mk_substs(callee_substs), + impl_substs, trait_method.name); Some((impl_method.method.def_id, &impl_method.substs)) } @@ -1076,7 +1063,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, Some(create_fn_trans_item(scx.tcx(), impl_method.method.def_id, impl_method.substs, - scx.tcx().mk_substs(Substs::empty()))) + Substs::empty(scx.tcx()))) } else { None } @@ -1248,9 +1235,13 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. + let impl_substs = Substs::for_item(tcx, impl_def_id, + |_, _| ty::ReErased, + |_, _| tcx.types.err); let mth = meth::get_impl_method(tcx, - impl_def_id, callee_substs, + impl_def_id, + impl_substs, default_impl.name); assert!(mth.is_provided); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 79cf77cd9d35d..b1aaea7d984c9 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let tcx = ccx.tcx(); match tcx.lang_items.eh_personality() { Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => { - Callee::def(ccx, def_id, tcx.mk_substs(Substs::empty())).reify(ccx).val + Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx).val } _ => { if let Some(llpersonality) = ccx.eh_personality().get() { @@ -550,7 +550,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let tcx = ccx.tcx(); assert!(ccx.sess().target.target.options.custom_unwind_resume); if let Some(def_id) = tcx.lang_items.eh_unwind_resume() { - return Callee::def(ccx, def_id, tcx.mk_substs(Substs::empty())); + return Callee::def(ccx, def_id, Substs::empty(tcx)); } let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 3ecba3691d279..0e9898896778c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -208,7 +208,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let arg_ids = args.iter().map(|arg| arg.pat.id); let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect(); - let substs = ccx.tcx().mk_substs(substs.clone().erase_regions()); + let substs = ccx.tcx().erase_regions(&substs); let substs = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &substs); @@ -222,7 +222,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, param_substs: &'tcx Substs<'tcx>) -> &'tcx hir::Expr { let substs = ccx.tcx().node_id_item_substs(ref_expr.id).substs; - let substs = ccx.tcx().mk_substs(substs.clone().erase_regions()); + let substs = ccx.tcx().erase_regions(&substs); let substs = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &substs); @@ -271,7 +271,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, param_substs: &'tcx Substs<'tcx>) -> Result { let expr = get_const_expr(ccx, def_id, ref_expr, param_substs); - let empty_substs = ccx.tcx().mk_substs(Substs::empty()); + let empty_substs = Substs::empty(ccx.tcx()); match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) { Err(Runtime(err)) => { report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit(); @@ -1160,7 +1160,7 @@ pub fn trans_static(ccx: &CrateContext, let v = if use_mir { ::mir::trans_static_initializer(ccx, def_id) } else { - let empty_substs = ccx.tcx().mk_substs(Substs::empty()); + let empty_substs = Substs::empty(ccx.tcx()); const_expr(ccx, expr, empty_substs, None, TrueConst::Yes) .map(|(v, _)| v) }.map_err(|e| e.into_inner())?; diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 65eea1bbb6337..c31dbf8943e08 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -30,7 +30,7 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use trans_item::TransItem; use type_::{Type, TypeNames}; -use rustc::ty::subst::{Substs, VecPerParamSpace}; +use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; use session::Session; @@ -571,16 +571,9 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { - let scheme = self.tcx().lookup_item_type(item_def_id); - self.empty_substs_for_scheme(&scheme) - } - - pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>) - -> &'tcx Substs<'tcx> { - assert!(scheme.generics.types.is_empty()); - self.tcx().mk_substs( - Substs::new(VecPerParamSpace::empty(), - scheme.generics.regions.map(|_| ty::ReErased))) + Substs::for_item(self.tcx(), item_def_id, |_, _| ty::ReErased, |_, _| { + bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) + }) } pub fn symbol_hasher(&self) -> &RefCell { @@ -999,11 +992,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { self.shared().empty_substs_for_def_id(item_def_id) } - - pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>) - -> &'tcx Substs<'tcx> { - self.shared().empty_substs_for_scheme(scheme) - } } pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); diff --git a/src/librustc_trans/controlflow.rs b/src/librustc_trans/controlflow.rs index 8845f124218bc..8b3a8a2bfccfb 100644 --- a/src/librustc_trans/controlflow.rs +++ b/src/librustc_trans/controlflow.rs @@ -401,7 +401,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc"); let args = vec!(expr_file_line); let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicFnLangItem); - Callee::def(ccx, did, ccx.tcx().mk_substs(Substs::empty())) + Callee::def(ccx, did, Substs::empty(ccx.tcx())) .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx } @@ -429,6 +429,6 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc"); let args = vec!(file_line, index, len); let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicBoundsCheckFnLangItem); - Callee::def(ccx, did, ccx.tcx().mk_substs(Substs::empty())) + Callee::def(ccx, did, Substs::empty(ccx.tcx())) .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 6a99f12b2788c..e80dd28c5e502 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -27,7 +27,7 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; use rustc::hir::def_id::DefId; use rustc::hir::pat_util; -use rustc::ty::subst; +use rustc::ty::subst::Substs; use rustc::hir::map as hir_map; use rustc::hir::{self, PatKind}; use {type_of, adt, machine, monomorphize}; @@ -315,7 +315,7 @@ impl<'tcx> TypeMap<'tcx> { fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>, cx: &CrateContext<'a, 'tcx>, def_id: DefId, - substs: &subst::Substs<'tcx>, + substs: &Substs<'tcx>, output: &mut String) { // First, find out the 'real' def_id of the type. Items inlined from // other crates have to be mapped back to their source. @@ -346,7 +346,7 @@ impl<'tcx> TypeMap<'tcx> { // Add the def-index as the second part output.push_str(&format!("{:x}", def_id.index.as_usize())); - let tps = substs.types.get_slice(subst::TypeSpace); + let tps = substs.types.as_full_slice(); if !tps.is_empty() { output.push('<'); @@ -1086,7 +1086,7 @@ impl<'tcx> MemberDescriptionFactory<'tcx> { // Creates MemberDescriptions for the fields of a struct struct StructMemberDescriptionFactory<'tcx> { variant: ty::VariantDef<'tcx>, - substs: &'tcx subst::Substs<'tcx>, + substs: &'tcx Substs<'tcx>, is_simd: bool, span: Span, } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 1aae3b3127faa..963cc09e1ab95 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -266,7 +266,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let generics = cx.tcx().lookup_item_type(fn_def_id).generics; + let generics = cx.tcx().lookup_generics(fn_def_id); let template_parameters = get_template_parameters(cx, &generics, instance.substs, diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 4bca091ef95ac..20dbc8ac78eaf 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -12,7 +12,7 @@ use common::CrateContext; use rustc::hir::def_id::DefId; -use rustc::ty::subst; +use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; use rustc::hir; @@ -173,7 +173,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // would be possible but with inlining and LTO we have to use the least // common denominator - otherwise we would run into conflicts. fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - substs: &subst::Substs<'tcx>, + substs: &Substs<'tcx>, output: &mut String) { if substs.types.is_empty() { return; diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index 6c894ddad1a94..beb589c80bfc5 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -175,7 +175,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, hir::ExprPath(..) => { match bcx.tcx().expect_def(expr.id) { Def::Const(did) | Def::AssociatedConst(did) => { - let empty_substs = bcx.tcx().mk_substs(Substs::empty()); + let empty_substs = Substs::empty(bcx.tcx()); let const_expr = consts::get_const_expr(bcx.ccx(), did, expr, empty_substs); // Temporarily get cleanup scopes out of the way, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 93e5f4ba1e205..080844782f205 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -50,7 +50,7 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem); let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align]; - Callee::def(bcx.ccx(), def_id, bcx.tcx().mk_substs(Substs::empty())) + Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx())) .call(bcx, debug_loc, ArgVals(&args), None).bcx } @@ -356,7 +356,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let trait_ref = ty::Binder(ty::TraitRef { def_id: tcx.lang_items.drop_trait().unwrap(), - substs: tcx.mk_substs(Substs::empty().with_self_ty(t)) + substs: Substs::new_trait(tcx, vec![], vec![], t) }); let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data, diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 7be173d17b487..133a98a2470f0 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -15,8 +15,7 @@ use intrinsics::{self, Intrinsic}; use libc; use llvm; use llvm::{ValueRef, TypeKind}; -use rustc::ty::subst; -use rustc::ty::subst::FnSpace; +use rustc::ty::subst::{FnSpace, Substs}; use abi::{Abi, FnType}; use adt; use base::*; @@ -1284,7 +1283,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { fn generic_simd_intrinsic<'blk, 'tcx, 'a> (bcx: Block<'blk, 'tcx>, name: &str, - substs: &'tcx subst::Substs<'tcx>, + substs: &'tcx Substs<'tcx>, callee_ty: Ty<'tcx>, args: Option<&[P]>, llargs: &[ValueRef], diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 169242fbf7270..b051028ebda6b 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -15,8 +15,7 @@ use arena::TypedArena; use back::symbol_names; use llvm::{ValueRef, get_params}; use rustc::hir::def_id::DefId; -use rustc::ty::subst::{FnSpace, Subst, Substs}; -use rustc::ty::subst; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, Reveal}; use abi::FnType; use base::*; @@ -221,20 +220,20 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_id: DefId, - substs: &'tcx subst::Substs<'tcx>) + substs: &'tcx Substs<'tcx>) -> Vec>> { debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs); - let trt_id = match tcx.impl_trait_ref(impl_id) { + let trait_id = match tcx.impl_trait_ref(impl_id) { Some(t_id) => t_id.def_id, None => bug!("make_impl_vtable: don't know how to \ make a vtable for a type impl!") }; - tcx.populate_implementations_for_trait_if_necessary(trt_id); + tcx.populate_implementations_for_trait_if_necessary(trait_id); - let trait_item_def_ids = tcx.trait_item_def_ids(trt_id); + let trait_item_def_ids = tcx.trait_item_def_ids(trait_id); trait_item_def_ids .iter() @@ -260,7 +259,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let name = trait_method_type.name; // Some methods cannot be called on an object; skip those. - if !tcx.is_vtable_safe_method(trt_id, &trait_method_type) { + if !tcx.is_vtable_safe_method(trait_id, &trait_method_type) { debug!("get_vtable_methods: not vtable safe"); return None; } @@ -270,15 +269,13 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the method may have some early-bound lifetimes, add // regions for those - let num_dummy_regions = trait_method_type.generics.regions.len(FnSpace); - let dummy_regions = vec![ty::ReErased; num_dummy_regions]; - let method_substs = substs.clone() - .with_method(vec![], dummy_regions); - let method_substs = tcx.mk_substs(method_substs); + let method_substs = Substs::for_item(tcx, trait_method_def_id, + |_, _| ty::ReErased, + |_, _| tcx.types.err); // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. - let mth = get_impl_method(tcx, impl_id, method_substs, name); + let mth = get_impl_method(tcx, method_substs, impl_id, substs, name); debug!("get_vtable_methods: mth={:?}", mth); @@ -309,8 +306,9 @@ pub struct ImplMethod<'tcx> { /// Locates the applicable definition of a method, given its name. pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_def_id: DefId, substs: &'tcx Substs<'tcx>, + impl_def_id: DefId, + impl_substs: &'tcx Substs<'tcx>, name: Name) -> ImplMethod<'tcx> { @@ -322,6 +320,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() { Some(node_item) => { let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs); let substs = traits::translate_substs(&infcx, impl_def_id, substs, node_item.node); tcx.lift(&substs).unwrap_or_else(|| { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 31fee560fe369..4da973bb7f946 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -232,12 +232,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { args: IndexVec>) -> Result, ConstEvalFailure> { // Try to resolve associated constants. - if instance.substs.self_ty().is_some() { - // Only trait items can have a Self parameter. - let trait_item = ccx.tcx().impl_or_trait_item(instance.def); - let trait_id = trait_item.container().id(); - let substs = instance.substs; - let trait_ref = ty::Binder(substs.to_trait_ref(ccx.tcx(), trait_id)); + if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) { + let trait_ref = ty::TraitRef::new(trait_id, instance.substs); + let trait_ref = ty::Binder(trait_ref); let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); if let traits::VtableImpl(vtable_impl) = vtable { let name = ccx.tcx().item_name(instance.def); diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 663c5167d1492..26278e886c29a 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -12,7 +12,6 @@ use llvm::ValueRef; use llvm; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; -use rustc::ty::subst; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; use attributes; @@ -33,7 +32,7 @@ use trans_item::TransItem; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, - psubsts: &'tcx subst::Substs<'tcx>) + psubsts: &'tcx Substs<'tcx>) -> (ValueRef, Ty<'tcx>) { debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts); assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); @@ -174,7 +173,7 @@ pub struct Instance<'tcx> { impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[], |_| None) + ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[]) } } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index ade6e8abeb32a..f24ab0f65578c 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -125,6 +125,7 @@ use rustc::hir::map::DefPathData; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::TyCtxt; use rustc::ty::item_path::characteristic_def_id_of_type; +use rustc::ty::subst; use std::cmp::Ordering; use std::hash::{Hash, Hasher, SipHasher}; use std::sync::Arc; @@ -486,7 +487,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // its self-type. If the self-type does not provide a characteristic // DefId, we use the location of the impl after all. - if let Some(self_ty) = instance.substs.self_ty() { + if tcx.trait_of_item(instance.def).is_some() { + let self_ty = *instance.substs.types.get(subst::SelfSpace, 0); // This is an implementation of a trait method. return characteristic_def_id_of_type(self_ty).or(Some(instance.def)); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 2dd07cf440553..ebd4a80deb9ab 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -28,7 +28,7 @@ use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::subst; +use rustc::ty::subst::{Substs, VecPerParamSpace}; use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; @@ -352,8 +352,7 @@ impl<'a, 'tcx> TransItem<'tcx> { }, TransItem::Static(node_id) => { let def_id = hir_map.local_def_id(node_id); - let instance = Instance::new(def_id, - tcx.mk_substs(subst::Substs::empty())); + let instance = Instance::new(def_id, Substs::empty(tcx)); to_string_internal(tcx, "static ", instance) }, }; @@ -561,7 +560,7 @@ fn push_item_name(tcx: TyCtxt, } fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - types: &'tcx subst::VecPerParamSpace>, + types: &'tcx VecPerParamSpace>, projections: &[ty::PolyExistentialProjection<'tcx>], output: &mut String) { if types.is_empty() && projections.is_empty() { diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index e6794149fcb3b..7e592d1b74d7c 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -11,7 +11,6 @@ #![allow(non_camel_case_types)] use rustc::hir::def_id::DefId; -use rustc::ty::subst; use abi::FnType; use adt; use common::*; @@ -257,7 +256,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. let repr = adt::represent_type(cx, t); - let tps = substs.types.get_slice(subst::TypeSpace); + let tps = substs.types.as_full_slice(); let name = llvm_type_name(cx, def.did, tps); adt::incomplete_type_of(cx, &repr, &name[..]) } @@ -336,7 +335,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // in *after* placing it into the type cache. This prevents // infinite recursion with recursive struct types. let repr = adt::represent_type(cx, t); - let tps = substs.types.get_slice(subst::TypeSpace); + let tps = substs.types.as_full_slice(); let name = llvm_type_name(cx, def.did, tps); adt::incomplete_type_of(cx, &repr, &name[..]) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 11ca012fdedab..5655c7c8e7291 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -81,6 +81,10 @@ pub trait AstConv<'gcx, 'tcx> { /// A cache used for the result of `ast_ty_to_ty_cache` fn ast_ty_to_ty_cache(&self) -> &RefCell>>; + /// Returns the generic type and lifetime parameters for an item. + fn get_generics(&self, span: Span, id: DefId) + -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>; + /// Identify the type scheme for an item with a type, like a type /// alias, fn, or struct. This allows you to figure out the set of /// type parameters defined on the item. @@ -348,7 +352,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope: &RegionScope, span: Span, param_mode: PathParamMode, - decl_generics: &ty::Generics<'tcx>, + def_id: DefId, item_segment: &hir::PathSegment) -> &'tcx Substs<'tcx> { @@ -362,11 +366,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .span_label(span, &format!("only traits may use parentheses")) .emit(); - return tcx.mk_substs(Substs::from_generics(decl_generics, |_, _| { + return Substs::for_item(tcx, def_id, |_, _| { ty::ReStatic }, |_, _| { tcx.types.err - })); + }); } } @@ -374,7 +378,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.create_substs_for_ast_path(rscope, span, param_mode, - decl_generics, + def_id, &item_segment.parameters, None); @@ -392,16 +396,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope: &RegionScope, span: Span, param_mode: PathParamMode, - decl_generics: &ty::Generics<'tcx>, + def_id: DefId, parameters: &hir::PathParameters, self_ty: Option>) -> (&'tcx Substs<'tcx>, Vec>) { let tcx = self.tcx(); - debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ + debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ parameters={:?})", - decl_generics, self_ty, parameters); + def_id, self_ty, parameters); let (lifetimes, num_types_provided) = match *parameters { hir::AngleBracketedParameters(ref data) => { @@ -417,6 +421,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). + let decl_generics = match self.get_generics(span, def_id) { + Ok(generics) => generics, + Err(ErrorReported) => { + // No convenient way to recover from a cycle here. Just bail. Sorry! + self.tcx().sess.abort_if_errors(); + bug!("ErrorReported returned, but no errors reports?") + } + }; let expected_num_region_params = decl_generics.regions.len(TypeSpace); let supplied_num_region_params = lifetimes.len(); let regions = if expected_num_region_params == supplied_num_region_params { @@ -438,7 +450,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; // If a self-type was declared, one should be provided. - assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some()); + assert_eq!(decl_generics.has_self, self_ty.is_some()); // Check the number of type parameters supplied by the user. if let Some(num_provided) = num_types_provided { @@ -460,7 +472,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let mut output_assoc_binding = None; - let substs = Substs::from_generics(decl_generics, |def, _| { + let substs = Substs::for_item(tcx, def_id, |def, _| { assert_eq!(def.space, TypeSpace); regions[def.index as usize] }, |def, substs| { @@ -532,7 +544,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { vec![output_assoc_binding.unwrap_or_else(|| { // This is an error condition, but we should // get the associated type binding anyway. - self.convert_parenthesized_parameters(rscope, &substs, data).1 + self.convert_parenthesized_parameters(rscope, substs, data).1 })] } }; @@ -540,7 +552,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", decl_generics, self_ty, substs); - (tcx.mk_substs(substs), assoc_bindings) + (substs, assoc_bindings) } /// Returns the appropriate lifetime to use for any output lifetimes @@ -803,7 +815,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.create_substs_for_ast_path(rscope, span, param_mode, - &trait_def.generics, + trait_def_id, &trait_segment.parameters, Some(self_ty)) } @@ -910,10 +922,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> Ty<'tcx> { let tcx = self.tcx(); - let (generics, decl_ty) = match self.get_item_type_scheme(span, did) { - Ok(ty::TypeScheme { generics, ty: decl_ty }) => { - (generics, decl_ty) - } + let decl_ty = match self.get_item_type_scheme(span, did) { + Ok(type_scheme) => type_scheme.ty, Err(ErrorReported) => { return tcx.types.err; } @@ -922,7 +932,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let substs = self.ast_path_substs_for_ty(rscope, span, param_mode, - &generics, + did, item_segment); // FIXME(#12938): This is a hack until we have full support for DST. @@ -1682,7 +1692,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Create the anonymized type. let def_id = tcx.map.local_def_id(ast_ty.id); if let Some(anon_scope) = rscope.anon_type_scope() { - let substs = anon_scope.fresh_substs(tcx); + let substs = anon_scope.fresh_substs(self, ast_ty.span); let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs); // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 04f22b195110f..af24a7b51176c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -547,10 +547,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Type check the path. - let scheme = tcx.lookup_item_type(def.def_id()); - let predicates = tcx.lookup_predicates(def.def_id()); - let pat_ty = self.instantiate_value_path(segments, scheme, &predicates, - opt_ty, def, pat.span, pat.id); + let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); self.demand_suptype(pat.span, expected, pat_ty); } @@ -607,18 +604,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Type check the path. - let scheme = tcx.lookup_item_type(def.def_id()); - let scheme = if scheme.ty.is_fn() { + let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); + + let pat_ty = if pat_ty.is_fn() { // Replace constructor type with constructed type for tuple struct patterns. - let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap(); - ty::TypeScheme { ty: fn_ret, generics: scheme.generics } + tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap() } else { // Leave the type as is for unit structs (backward compatibility). - scheme + pat_ty }; - let predicates = tcx.lookup_predicates(def.def_id()); - let pat_ty = self.instantiate_value_path(segments, scheme, &predicates, - opt_ty, def, pat.span, pat.id); + self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 265422468fe2a..9a3cbabe55331 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { Some(f) => f, None => return None }, - substs: tcx.mk_substs(Substs::new_trait(vec![], vec![], self.cur_ty)) + substs: Substs::new_trait(tcx, vec![], vec![], self.cur_ty) }; let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index d501a8a184cee..3cb528eba63e0 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -194,10 +194,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Create mapping from trait to skolemized. let trait_to_skol_substs = - trait_to_impl_substs - .subst(tcx, impl_to_skol_substs).clone() - .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(), - impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec()); + impl_to_skol_substs.rebase_onto(tcx, impl_m.container_id(), + trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); @@ -208,7 +206,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m, &trait_m.generics, &impl_m.generics, - &trait_to_skol_substs, + trait_to_skol_substs, impl_to_skol_substs) { return; } @@ -226,7 +224,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut fulfillment_cx = traits::FulfillmentContext::new(); // Normalize the associated types in the trait_bounds. - let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs); + let trait_bounds = trait_m.predicates.instantiate(tcx, trait_to_skol_substs); // Create obligations for each predicate declared by the impl // definition in the context of the trait's parameter @@ -323,7 +321,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, infcx.parameter_environment.free_id_outlive, &trait_m.fty.sig); let trait_sig = - trait_sig.subst(tcx, &trait_to_skol_substs); + trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = assoc::normalize_associated_types_in(&infcx, &mut fulfillment_cx, @@ -454,16 +452,14 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Create mapping from trait to skolemized. let trait_to_skol_substs = - trait_to_impl_substs - .subst(tcx, impl_to_skol_substs).clone() - .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(), - impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec()); + impl_to_skol_substs.rebase_onto(tcx, impl_c.container.id(), + trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); debug!("compare_const_impl: trait_to_skol_substs={:?}", trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); - let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs); + let trait_ty = trait_c.ty.subst(tcx, trait_to_skol_substs); let mut origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 1e2446788adc9..7d79fc4fbf878 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use rustc::infer; use middle::region; -use rustc::ty::subst::{self, Subst}; +use rustc::ty::subst::{self, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; use util::nodemap::FnvHashSet; @@ -41,16 +41,14 @@ use syntax_pos::{self, Span}; /// cannot do `struct S; impl Drop for S { ... }`). /// pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> { - let ty::TypeScheme { generics: ref dtor_generics, - ty: dtor_self_type } = ccx.tcx.lookup_item_type(drop_impl_did); + let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty; let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyEnum(adt_def, self_to_impl_substs) | ty::TyStruct(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, drop_impl_did, - dtor_generics, - &dtor_self_type, + dtor_self_type, adt_def.did)?; ensure_drop_predicates_are_implied_by_item_defn(ccx, @@ -73,8 +71,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, drop_impl_did: DefId, - drop_impl_generics: &ty::Generics<'tcx>, - drop_impl_ty: &ty::Ty<'tcx>, + drop_impl_ty: Ty<'tcx>, self_type_did: DefId) -> Result<(), ()> { let tcx = ccx.tcx; @@ -93,8 +90,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP); let fresh_impl_substs = - infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics); - let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs); + infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); + let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), named_type, fresh_impl_self_ty) { @@ -131,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( drop_impl_did: DefId, dtor_predicates: &ty::GenericPredicates<'tcx>, self_type_did: DefId, - self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> { + self_to_impl_substs: &Substs<'tcx>) -> Result<(), ()> { // Here is an example, analogous to that from // `compare_impl_method`. diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 4334f043772e3..bfedb4fa6e1a0 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -36,11 +36,11 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let def_id = tcx.map.local_def_id(it.id); let i_ty = tcx.lookup_item_type(def_id); - let mut substs = Substs::empty(); - substs.types = i_ty.generics.types.map(|def| tcx.mk_param_from_def(def)); + let substs = Substs::for_item(tcx, def_id, + |_, _| ty::ReErased, + |def, _| tcx.mk_param_from_def(def)); - let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs), - tcx.mk_bare_fn(ty::BareFnTy { + let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: abi, sig: ty::Binder(FnSig { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 250bf9265d1a4..c071fce98965f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -12,7 +12,7 @@ use super::probe; use check::{FnCtxt, callee}; use hir::def_id::DefId; -use rustc::ty::subst::{self}; +use rustc::ty::subst::{self, Substs}; use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; @@ -42,10 +42,6 @@ struct InstantiatedMethodSig<'tcx> { /// argument is the receiver. method_sig: ty::FnSig<'tcx>, - /// Substitutions for all types/early-bound-regions declared on - /// the method. - all_substs: subst::Substs<'tcx>, - /// Generic bounds on the method's parameters which must be added /// as pending obligations. method_predicates: ty::InstantiatedPredicates<'tcx>, @@ -105,9 +101,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Create the final signature for the method, replacing late-bound regions. let InstantiatedMethodSig { - method_sig, all_substs, method_predicates + method_sig, method_predicates } = self.instantiate_method_sig(&pick, all_substs); - let all_substs = self.tcx.mk_substs(all_substs); let method_self_ty = method_sig.inputs[0]; // Unify the (adjusted) self type with what the method expects. @@ -198,7 +193,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn fresh_receiver_substs(&mut self, self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) - -> &'tcx subst::Substs<'tcx> + -> &'tcx Substs<'tcx> { match pick.kind { probe::InherentImplPick => { @@ -256,16 +251,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { probe::TraitPick => { let trait_def_id = pick.item.container().id(); - let trait_def = self.tcx.lookup_trait_def(trait_def_id); // Make a trait reference `$0 : Trait<$1...$n>` // consisting entirely of type variables. Later on in // the process we will unify the transformed-self-type // of the method with the actual type in order to // unify some of these variables. - self.fresh_substs_for_trait(self.span, - &trait_def.generics, - self.next_ty_var()) + self.fresh_substs_for_item(self.span, trait_def_id) } probe::WhereClausePick(ref poly_trait_ref) => { @@ -308,8 +300,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_substs(&mut self, pick: &probe::Pick<'tcx>, mut supplied_method_types: Vec>, - substs: &subst::Substs<'tcx>) - -> subst::Substs<'tcx> + substs: &Substs<'tcx>) + -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh @@ -335,7 +327,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - subst::Substs::from_generics(&method.generics, |def, _| { + Substs::for_item(self.tcx, method.def_id, |def, _| { if def.space != subst::FnSpace { substs.region_for_def(def) } else { @@ -376,7 +368,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, - all_substs: subst::Substs<'tcx>) + all_substs: &'tcx Substs<'tcx>) -> InstantiatedMethodSig<'tcx> { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", @@ -387,7 +379,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. let method_predicates = pick.item.as_opt_method().unwrap() - .predicates.instantiate(self.tcx, &all_substs); + .predicates.instantiate(self.tcx, all_substs); let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); @@ -405,20 +397,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); - let method_sig = self.instantiate_type_scheme(self.span, &all_substs, &method_sig); + let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); debug!("type scheme substituted, method_sig={:?}", method_sig); InstantiatedMethodSig { method_sig: method_sig, - all_substs: all_substs, method_predicates: method_predicates, } } fn add_obligations(&mut self, fty: Ty<'tcx>, - all_substs: &subst::Substs<'tcx>, + all_substs: &Substs<'tcx>, method_predicates: &ty::InstantiatedPredicates<'tcx>) { debug!("add_obligations: fty={:?} all_substs={:?} method_predicates={:?}", fty, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index ff34f37bde0dd..e5107af6ca04b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -13,7 +13,7 @@ use check::FnCtxt; use hir::def::Def; use hir::def_id::DefId; -use rustc::ty::subst; +use rustc::ty::subst::{self, Substs}; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; @@ -189,7 +189,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(trait_def.generics.regions.is_empty()); // Construct a trait-reference `self_ty : Trait` - let substs = subst::Substs::from_generics(&trait_def.generics, |def, _| { + let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { if def.space == subst::SelfSpace { @@ -201,7 +201,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); - let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs)); + let trait_ref = ty::TraitRef::new(trait_def_id, substs); // Construct an obligation let poly_trait_ref = trait_ref.to_poly_trait_ref(); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f6ac3235cf33e..448ea243655a8 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,8 +16,7 @@ use super::suggest; use check::{FnCtxt}; use hir::def_id::DefId; use hir::def::Def; -use rustc::ty::subst; -use rustc::ty::subst::Subst; +use rustc::ty::subst::{self, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::infer::{InferOk, TypeOrigin}; @@ -80,9 +79,9 @@ struct Candidate<'tcx> { #[derive(Debug)] enum CandidateKind<'tcx> { - InherentImplCandidate(subst::Substs<'tcx>, + InherentImplCandidate(&'tcx Substs<'tcx>, /* Normalize obligations */ Vec>), - ExtensionImplCandidate(/* Impl */ DefId, subst::Substs<'tcx>, + ExtensionImplCandidate(/* Impl */ DefId, &'tcx Substs<'tcx>, /* Normalize obligations */ Vec>), ObjectCandidate, TraitCandidate, @@ -421,10 +420,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = impl_ty.subst(self.tcx, &impl_substs); + let impl_ty = impl_ty.subst(self.tcx, impl_substs); // Determine the receiver type that the method itself expects. - let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs); + let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs); // We can't use normalize_associated_types_in as it will pollute the // fcx's fulfillment context after this probe is over. @@ -519,14 +518,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_ref, trait_ref.substs, m); - assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(), - trait_ref.substs.types.get_slice(subst::TypeSpace).len()); - assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(), - trait_ref.substs.regions.get_slice(subst::TypeSpace).len()); - assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(), - trait_ref.substs.types.get_slice(subst::SelfSpace).len()); - assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(), - trait_ref.substs.regions.get_slice(subst::SelfSpace).len()); + assert_eq!(m.generics.types.len(subst::TypeSpace), + trait_ref.substs.types.len(subst::TypeSpace)); + assert_eq!(m.generics.regions.len(subst::TypeSpace), + trait_ref.substs.regions.len(subst::TypeSpace)); + assert_eq!(m.generics.types.len(subst::SelfSpace), + trait_ref.substs.types.len(subst::SelfSpace)); + assert_eq!(m.generics.regions.len(subst::SelfSpace), + trait_ref.substs.regions.len(subst::SelfSpace)); } // Because this trait derives from a where-clause, it @@ -665,7 +664,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id) .unwrap() // we know this is a trait impl - .subst(self.tcx, &impl_substs); + .subst(self.tcx, impl_substs); debug!("impl_trait_ref={:?}", impl_trait_ref); @@ -753,14 +752,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // for the purposes of our method lookup, we only take // receiver type into account, so we can just substitute // fresh types here to use during substitution and subtyping. - let trait_def = self.tcx.lookup_trait_def(trait_def_id); - let substs = self.fresh_substs_for_trait(self.span, - &trait_def.generics, - step.self_ty); + let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { + self.region_var_for_def(self.span, def) + }, |def, substs| { + if def.space == subst::SelfSpace { + assert_eq!(def.index, 0); + step.self_ty + } else { + assert_eq!(def.space, subst::TypeSpace); + self.type_var_for_def(self.span, def, substs) + } + }); let xform_self_ty = self.xform_self_ty(&item, step.self_ty, - &substs); + substs); self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), @@ -1192,7 +1198,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn xform_self_ty(&self, item: &ty::ImplOrTraitItem<'tcx>, impl_ty: Ty<'tcx>, - substs: &subst::Substs<'tcx>) + substs: &Substs<'tcx>) -> Ty<'tcx> { match item.as_opt_method() { @@ -1205,7 +1211,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn xform_method_self_ty(&self, method: &Rc>, impl_ty: Ty<'tcx>, - substs: &subst::Substs<'tcx>) + substs: &Substs<'tcx>) -> Ty<'tcx> { debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", @@ -1236,7 +1242,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { method.generics.regions.is_empty_in(subst::FnSpace) { xform_self_ty.subst(self.tcx, substs) } else { - let substs = subst::Substs::from_generics(&method.generics, |def, _| { + let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { if def.space != subst::FnSpace { substs.region_for_def(def) } else { @@ -1251,14 +1257,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.type_var_for_def(self.span, def, cur_substs) } }); - xform_self_ty.subst(self.tcx, &substs) + xform_self_ty.subst(self.tcx, substs) } } /// Get the type of an impl and generate substitutions with placeholders. fn impl_ty_and_substs(&self, impl_def_id: DefId) - -> (Ty<'tcx>, subst::Substs<'tcx>) + -> (Ty<'tcx>, &'tcx Substs<'tcx>) { let impl_pty = self.tcx.lookup_item_type(impl_def_id); @@ -1270,8 +1276,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { impl_pty.generics.regions.map( |_| ty::ReErased); // see erase_late_bound_regions() for an expl of why 'erased - let substs = subst::Substs::new(type_vars, region_placeholders); - (impl_pty.ty, substs) + (impl_pty.ty, Substs::new(self.tcx, type_vars, region_placeholders)) } /// Replace late-bound-regions bound by `value` with `'static` using diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index dc6fa334b74fc..573dae46456ba 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -54,10 +54,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| { let fn_once_substs = - Substs::new_trait(vec![self.next_ty_var()], vec![], ty); - let trait_ref = - ty::TraitRef::new(fn_once, - tcx.mk_substs(fn_once_substs)); + Substs::new_trait(tcx, vec![self.next_ty_var()], vec![], ty); + let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = Obligation::misc(span, self.body_id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c41bb1930d458..700fb2ecf42dd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,7 +90,6 @@ use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; use rustc::ty::subst::{self, Subst, Substs}; use rustc::traits::{self, Reveal}; -use rustc::ty::{GenericPredicates, TypeScheme}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility}; @@ -745,26 +744,20 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let impl_def_id = ccx.tcx.map.local_def_id(it.id); match ccx.tcx.impl_trait_ref(impl_def_id) { Some(impl_trait_ref) => { - let trait_def_id = impl_trait_ref.def_id; - check_impl_items_against_trait(ccx, it.span, impl_def_id, &impl_trait_ref, impl_items); - check_on_unimplemented( - ccx, - &ccx.tcx.lookup_trait_def(trait_def_id).generics, - it, - ccx.tcx.item_name(trait_def_id)); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(ccx, trait_def_id, it); } None => { } } } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); - let generics = &ccx.tcx.lookup_trait_def(def_id).generics; - check_on_unimplemented(ccx, generics, it, it.name); + check_on_unimplemented(ccx, def_id, it); } hir::ItemStruct(..) => { check_struct(ccx, it.id, it.span); @@ -872,9 +865,9 @@ fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ty::Generics, - item: &hir::Item, - name: ast::Name) { + def_id: DefId, + item: &hir::Item) { + let generics = ccx.tcx.lookup_generics(def_id); if let Some(ref attr) = item.attrs.iter().find(|a| { a.check_name("rustc_on_unimplemented") }) { @@ -894,6 +887,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }) { Some(_) => (), None => { + let name = ccx.tcx.item_name(def_id); span_err!(ccx.tcx.sess, attr.span, E0230, "there is no type parameter \ {} on trait {}", @@ -1301,6 +1295,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { &self.ast_ty_to_ty_cache } + fn get_generics(&self, _: Span, id: DefId) + -> Result<&'tcx ty::Generics<'tcx>, ErrorReported> + { + Ok(self.tcx().lookup_generics(id)) + } + fn get_item_type_scheme(&self, _: Span, id: DefId) -> Result, ErrorReported> { @@ -1364,7 +1364,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn ty_infer_for_def(&self, ty_param_def: &ty::TypeParameterDef<'tcx>, - substs: &subst::Substs<'tcx>, + substs: &Substs<'tcx>, span: Span) -> Ty<'tcx> { self.type_var_for_def(span, ty_param_def, substs) } @@ -1690,25 +1690,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { node_id: ast::NodeId) -> Ty<'tcx> { debug!("instantiate_type_path(did={:?}, path={:?})", did, path); - let mut type_scheme = self.tcx.lookup_item_type(did); - if type_scheme.ty.is_fn() { + let mut ty = self.tcx.lookup_item_type(did).ty; + if ty.is_fn() { // Tuple variants have fn type even in type namespace, extract true variant type from it - let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap(); - type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics } + ty = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap(); } let type_predicates = self.tcx.lookup_predicates(did); let substs = AstConv::ast_path_substs_for_ty(self, self, path.span, PathParamMode::Optional, - &type_scheme.generics, + did, path.segments.last().unwrap()); - debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.ty, substs); + debug!("instantiate_type_path: ty={:?} substs={:?}", ty, substs); let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); let cause = traits::ObligationCause::new(path.span, self.body_id, traits::ItemObligation(did)); self.add_obligations_for_parameters(cause, &bounds); - let ty_substituted = self.instantiate_type_scheme(path.span, substs, &type_scheme.ty); + let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty); self.write_ty(node_id, ty_substituted); self.write_substs(node_id, ty::ItemSubsts { substs: substs @@ -2775,7 +2774,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ity = self.tcx.lookup_item_type(did); debug!("impl_self_ty: ity={:?}", ity); - let substs = self.fresh_substs_for_generics(span, &ity.generics); + let substs = self.fresh_substs_for_item(span, did); let substd_ty = self.instantiate_type_scheme(span, &substs, &ity.ty); TypeAndSubsts { substs: substs, ty: substd_ty } @@ -3443,10 +3442,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, expr.id, expr.span); if def != Def::Err { - let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, - def); - self.instantiate_value_path(segments, scheme, &predicates, - opt_ty, def, expr.span, id); + self.instantiate_value_path(segments, opt_ty, def, expr.span, id); } else { self.set_tainted_by_errors(); self.write_error(id); @@ -4036,54 +4032,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { *self.ps.borrow_mut() = prev; } - // Returns the type parameter count and the type for the given definition. - fn type_scheme_and_predicates_for_def(&self, - sp: Span, - defn: Def) - -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { - match defn { - Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => { - let typ = self.local_ty(sp, nid); - (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, - ty::GenericPredicates::empty()) - } - Def::Fn(id) | Def::Method(id) | - Def::Static(id, _) | Def::Variant(_, id) | - Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => { - (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id)) - } - Def::Trait(_) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::PrimTy(_) | - Def::TyParam(..) | - Def::Mod(..) | - Def::ForeignMod(..) | - Def::Label(..) | - Def::SelfTy(..) | - Def::Err => { - span_bug!(sp, "expected value, found {:?}", defn); - } - } - } - // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_value_path(&self, segments: &[hir::PathSegment], - type_scheme: TypeScheme<'tcx>, - type_predicates: &ty::GenericPredicates<'tcx>, opt_self_ty: Option>, def: Def, span: Span, node_id: ast::NodeId) -> Ty<'tcx> { - debug!("instantiate_value_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})", + debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})", segments, def, - node_id, - type_scheme); + node_id); // We need to extract the type parameters supplied by the user in // the path `path`. Due to the current setup, this is a bit of a @@ -4210,11 +4171,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::ForeignMod(..) | Def::Local(..) | Def::Label(..) | - Def::Upvar(..) => {} - - Def::Err => { - self.set_tainted_by_errors(); - } + Def::Upvar(..) | + Def::Err => {} } // In `>::method`, `A` and `B` are mandatory, but @@ -4232,6 +4190,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_segment.is_some() as usize; self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]); + match def { + Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => { + let ty = self.local_ty(span, nid); + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(node_id, ty); + self.write_substs(node_id, ty::ItemSubsts { + substs: Substs::empty(self.tcx) + }); + return ty; + } + _ => {} + } + let scheme = self.tcx.lookup_item_type(def.def_id()); + let type_predicates = self.tcx.lookup_predicates(def.def_id()); + // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user // did not provide any types, then we want to substitute inference @@ -4240,16 +4213,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // a problem. self.check_path_parameter_count(subst::TypeSpace, span, - &type_scheme.generics, + scheme.generics, !require_type_space, &mut type_segment); self.check_path_parameter_count(subst::FnSpace, span, - &type_scheme.generics, + scheme.generics, true, &mut fn_segment); - let substs = Substs::from_generics(&type_scheme.generics, |def, _| { + let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| { let i = def.index as usize; let segment = match def.space { subst::SelfSpace => None, @@ -4307,9 +4280,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. - let substs = self.tcx.mk_substs(substs); assert!(!substs.has_escaping_regions()); - assert!(!type_scheme.has_escaping_regions()); + assert!(!scheme.ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. @@ -4320,7 +4292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty); + let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty); if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5f8861f309948..6a475864f3b7d 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -18,7 +18,6 @@ use hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; -use rustc::ty::subst::ParamSpace; use rustc::infer::{InferCtxt, FixupError}; use rustc::util::nodemap::DefIdMap; use write_substs_to_tcx; @@ -68,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); - wbcx.visit_anon_types(); + wbcx.visit_anon_types(item_id); wbcx.visit_deferred_obligations(item_id); } } @@ -104,22 +103,20 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } let free_substs = fcx.parameter_environment.free_substs; - for &space in &ParamSpace::all() { - for (i, r) in free_substs.regions.get_slice(space).iter().enumerate() { - match *r { - ty::ReFree(ty::FreeRegion { - bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. - }) => { - let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion { - space: space, - index: i as u32, - name: name, - }); - wbcx.free_to_bound_regions.insert(def_id, bound_region); - } - _ => { - bug!("{:?} is not a free region for an early-bound lifetime", r); - } + for (space, i, r) in free_substs.regions.iter_enumerated() { + match *r { + ty::ReFree(ty::FreeRegion { + bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. + }) => { + let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion { + space: space, + index: i as u32, + name: name, + }); + wbcx.free_to_bound_regions.insert(def_id, bound_region); + } + _ => { + bug!("{:?} is not a free region for an early-bound lifetime", r); } } } @@ -300,11 +297,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_anon_types(&self) { + fn visit_anon_types(&self, item_id: ast::NodeId) { if self.fcx.writeback_errors.get() { return } + let item_def_id = self.fcx.tcx.map.local_def_id(item_id); + let gcx = self.tcx().global_tcx(); for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { let reason = ResolvingAnonTy(def_id); @@ -345,9 +344,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } }); - gcx.tcache.borrow_mut().insert(def_id, ty::TypeScheme { + gcx.register_item_type(def_id, ty::TypeScheme { ty: outside_ty, - generics: ty::Generics::empty() + generics: gcx.lookup_generics(item_def_id) }); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a2a162a7f5f74..77723ea973341 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -65,7 +65,7 @@ use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; -use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace}; +use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; @@ -120,6 +120,7 @@ struct ItemCtxt<'a,'tcx:'a> { #[derive(Copy, Clone, PartialEq, Eq)] pub enum AstConvRequest { + GetGenerics(DefId), GetItemTypeScheme(DefId), GetTraitDef(DefId), EnsureSuperPredicates(DefId), @@ -187,6 +188,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { err.span_label(span, &format!("cyclic reference")); match cycle[0] { + AstConvRequest::GetGenerics(def_id) | AstConvRequest::GetItemTypeScheme(def_id) | AstConvRequest::GetTraitDef(def_id) => { err.note( @@ -209,6 +211,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { for request in &cycle[1..] { match *request { + AstConvRequest::GetGenerics(def_id) | AstConvRequest::GetItemTypeScheme(def_id) | AstConvRequest::GetTraitDef(def_id) => { err.note( @@ -231,6 +234,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } match cycle[0] { + AstConvRequest::GetGenerics(def_id) | AstConvRequest::GetItemTypeScheme(def_id) | AstConvRequest::GetTraitDef(def_id) => { err.note( @@ -303,6 +307,14 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { &self.ccx.ast_ty_to_ty_cache } + fn get_generics(&self, span: Span, id: DefId) + -> Result<&'tcx ty::Generics<'tcx>, ErrorReported> + { + self.ccx.cycle_check(span, AstConvRequest::GetGenerics(id), || { + Ok(generics_of_def_id(self.ccx, id)) + }) + } + fn get_item_type_scheme(&self, span: Span, id: DefId) -> Result, ErrorReported> { @@ -544,7 +556,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, name: ast::Name, @@ -553,25 +564,22 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, sig: &hir::MethodSig, defaultness: hir::Defaultness, untransformed_rcvr_ty: Ty<'tcx>, - rcvr_ty_generics: &ty::Generics<'tcx>, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { - let ty_generics = ty_generics_for_fn(ccx, &sig.generics, rcvr_ty_generics); + let def_id = ccx.tcx.map.local_def_id(id); + let ty_generics = generics_of_def_id(ccx, def_id); let ty_generic_predicates = ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates); let (fty, explicit_self_category) = { let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(&ty_generics)), + ImplContainer(_) => Some(AnonTypeScope::new(def_id)), TraitContainer(_) => None }; AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), sig, untransformed_rcvr_ty, anon_scope) }; - let def_id = ccx.tcx.map.local_def_id(id); - let substs = mk_item_substs(ccx.tcx, &ty_generics); - let ty_method = ty::Method::new(name, ty_generics, ty_generic_predicates, @@ -582,16 +590,14 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id, container); + let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + ccx.tcx.map.span(id), def_id); let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty); debug!("method {} (id {}) has type {:?}", name, id, fty); - ccx.tcx.register_item_type(def_id, TypeScheme { - generics: ty_method.generics.clone(), - ty: fty - }); - ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone()); - + ccx.tcx.tcache.borrow_mut().insert(def_id, fty); write_ty_to_tcx(ccx, id, fty); + ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone()); debug!("writing method type: def_id={:?} mty={:?}", def_id, ty_method); @@ -601,7 +607,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - struct_generics: &ty::Generics<'tcx>, + struct_generics: &'tcx ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, field: &hir::StructField, ty_f: ty::FieldDefMaster<'tcx>) @@ -613,7 +619,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, /* add the field to the tcache */ ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(field.id), ty::TypeScheme { - generics: struct_generics.clone(), + generics: struct_generics, ty: tt }); ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(field.id), @@ -709,8 +715,9 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } hir::ItemEnum(ref enum_definition, _) => { - let (scheme, predicates) = convert_typed_item(ccx, it); - write_ty_to_tcx(ccx, it.id, scheme.ty); + let def_id = ccx.tcx.map.local_def_id(it.id); + let scheme = type_scheme_of_def_id(ccx, def_id); + let predicates = predicates_of_item(ccx, it); convert_enum_variant_types(ccx, tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)), scheme, @@ -737,7 +744,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Create generics from the generics specified in the impl head. debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); - let ty_generics = ty_generics_for_impl(ccx, generics); + let ty_generics = generics_of_def_id(ccx, def_id); let mut ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics); debug!("convert: impl_bounds={:?}", ty_predicates); @@ -746,7 +753,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { write_ty_to_tcx(ccx, it.id, selfty); tcx.register_item_type(def_id, - TypeScheme { generics: ty_generics.clone(), + TypeScheme { generics: ty_generics, ty: selfty }); let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), @@ -791,7 +798,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { .to_ty(&ExplicitRscope, &ty); tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id), TypeScheme { - generics: ty_generics.clone(), + generics: ty_generics, ty: ty, }); // Trait-associated constants are always public. @@ -829,7 +836,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { convert_method(ccx, ImplContainer(def_id), impl_item.name, impl_item.id, method_vis, - sig, impl_item.defaultness, selfty, &ty_generics, + sig, impl_item.defaultness, selfty, &ty_predicates); } } @@ -856,7 +863,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { .to_ty(&ExplicitRscope, ty); tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id), TypeScheme { - generics: trait_def.generics.clone(), + generics: trait_def.generics, ty: ty, }); convert_associated_const(ccx, @@ -898,7 +905,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { sig, hir::Defaultness::Default, tcx.mk_self_type(), - &trait_def.generics, &trait_predicates); } @@ -917,11 +923,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { trait_item_def_ids); }, hir::ItemStruct(ref struct_def, _) => { - let (scheme, predicates) = convert_typed_item(ccx, it); - write_ty_to_tcx(ccx, it.id, scheme.ty); + let def_id = ccx.tcx.map.local_def_id(it.id); + let scheme = type_scheme_of_def_id(ccx, def_id); + let predicates = predicates_of_item(ccx, it); - let it_def_id = ccx.tcx.map.local_def_id(it.id); - let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant(); + let variant = tcx.lookup_adt_def_master(def_id).struct_variant(); for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { convert_field(ccx, &scheme.generics, &predicates, f, ty_f) @@ -933,15 +939,14 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { }, hir::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); - let (scheme, _) = convert_typed_item(ccx, it); - write_ty_to_tcx(ccx, it.id, scheme.ty); + let def_id = ccx.tcx.map.local_def_id(it.id); + type_scheme_of_def_id(ccx, def_id); + predicates_of_item(ccx, it); }, _ => { - // This call populates the type cache with the converted type - // of the item in passing. All we have to do here is to write - // it into the node type table. - let (scheme, _) = convert_typed_item(ccx, it); - write_ty_to_tcx(ccx, it.id, scheme.ty); + let def_id = ccx.tcx.map.local_def_id(it.id); + type_scheme_of_def_id(ccx, def_id); + predicates_of_item(ccx, it); }, } } @@ -952,6 +957,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let tcx = ccx.tcx; + let def_id = tcx.map.local_def_id(ctor_id); + tcx.generics.borrow_mut().insert(def_id, scheme.generics); let ctor_ty = match variant.kind { VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { @@ -960,8 +967,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .iter() .map(|field| field.unsubst_ty()) .collect(); - let def_id = tcx.map.local_def_id(ctor_id); - let substs = mk_item_substs(tcx, &scheme.generics); + let substs = mk_item_substs(&ccx.icx(&predicates), + ccx.tcx.map.span(ctor_id), def_id); tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: abi::Abi::Rust, @@ -974,12 +981,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; write_ty_to_tcx(ccx, ctor_id, ctor_ty); + tcx.tcache.borrow_mut().insert(def_id, ctor_ty); tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates); - tcx.register_item_type(tcx.map.local_def_id(ctor_id), - TypeScheme { - generics: scheme.generics, - ty: ctor_ty - }); } fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -1237,7 +1240,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } let (unsafety, generics, items) = match it.node { - hir::ItemTrait(unsafety, ref generics, _, ref items) => (unsafety, generics, items), + hir::ItemTrait(unsafety, ref generics, _, ref items) => { + (unsafety, generics, items) + } _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"), }; @@ -1253,9 +1258,8 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, err.emit(); } - let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics)); - - let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics); + let ty_generics = generics_of_def_id(ccx, def_id); + let substs = mk_item_substs(&ccx.icx(generics), it.span, def_id); let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| { match trait_item.node { @@ -1264,51 +1268,14 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }).collect(); - let trait_ref = ty::TraitRef { - def_id: def_id, - substs: substs, - }; - + let trait_ref = ty::TraitRef::new(def_id, substs); let trait_def = ty::TraitDef::new(unsafety, paren_sugar, ty_generics, trait_ref, associated_type_names); - return tcx.intern_trait_def(trait_def); - - fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &hir::Generics) - -> Substs<'tcx> - { - let tcx = ccx.tcx; - - // Creates a no-op substitution for the trait's type parameters. - let regions = - generics.lifetimes - .iter() - .enumerate() - .map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion { - space: TypeSpace, - index: i as u32, - name: def.lifetime.name - })) - .collect(); - - // Start with the generics in the type parameters... - let types: Vec<_> = - generics.ty_params - .iter() - .enumerate() - .map(|(i, def)| tcx.mk_param(TypeSpace, - i as u32, def.name)) - .collect(); - - // ...and also create the `Self` parameter. - let self_ty = tcx.mk_self_type(); - - Substs::new_trait(types, regions, self_ty) - } + tcx.intern_trait_def(trait_def) } fn trait_defines_associated_type_named(ccx: &CrateCtxt, @@ -1410,105 +1377,243 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) } } -fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - def_id: DefId) - -> ty::TypeScheme<'tcx> -{ - if let Some(node_id) = ccx.tcx.map.as_local_node_id(def_id) { - match ccx.tcx.map.find(node_id) { - Some(hir_map::NodeItem(item)) => { - type_scheme_of_item(ccx, &item) +fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + def_id: DefId) + -> &'tcx ty::Generics<'tcx> { + let tcx = ccx.tcx; + let node_id = if let Some(id) = tcx.map.as_local_node_id(def_id) { + id + } else { + return tcx.lookup_generics(def_id); + }; + tcx.generics.memoize(def_id, || { + use rustc::hir::map::*; + use rustc::hir::*; + + let mut opt_self = None; + let mut base_def_id = None; + let mut allow_defaults = false; + + let no_generics = hir::Generics::empty(); + let (space, ast_generics) = match tcx.map.get(node_id) { + NodeImplItem(&ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) | + NodeTraitItem(&TraitItem { node: MethodTraitItem(ref sig, _), .. }) => { + let parent_id = tcx.map.get_parent(node_id); + base_def_id = Some(tcx.map.local_def_id(parent_id)); + (FnSpace, &sig.generics) } - Some(hir_map::NodeForeignItem(foreign_item)) => { - let abi = ccx.tcx.map.get_foreign_abi(node_id); - type_scheme_of_foreign_item(ccx, &foreign_item, abi) + + NodeImplItem(_) | + NodeTraitItem(_) => { + let parent_id = tcx.map.get_parent(node_id); + base_def_id = Some(tcx.map.local_def_id(parent_id)); + (FnSpace, &no_generics) } - x => { - bug!("unexpected sort of node in get_item_type_scheme(): {:?}", - x); + + NodeItem(item) => { + match item.node { + ItemFn(_, _, _, _, ref generics, _) => (FnSpace, generics), + ItemImpl(_, _, ref generics, _, _, _) => (TypeSpace, generics), + ItemTy(_, ref generics) | + ItemEnum(_, ref generics) | + ItemStruct(_, ref generics) => { + allow_defaults = true; + (TypeSpace, generics) + } + ItemTrait(_, ref generics, _, _) => { + // Add in the self type parameter. + // + // Something of a hack: use the node id for the trait, also as + // the node id for the Self type parameter. + let param_id = item.id; + + let parent = ccx.tcx.map.get_parent(param_id); + + let def = ty::TypeParameterDef { + space: SelfSpace, + index: 0, + name: keywords::SelfType.name(), + def_id: tcx.map.local_def_id(param_id), + default_def_id: tcx.map.local_def_id(parent), + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + }; + tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); + opt_self = Some(def); + + allow_defaults = true; + (TypeSpace, generics) + } + _ => (TypeSpace, &no_generics) + } + } + + NodeForeignItem(item) => { + match item.node { + ForeignItemStatic(..) => (TypeSpace, &no_generics), + ForeignItemFn(_, ref generics) => (FnSpace, generics) + } } + + _ => (TypeSpace, &no_generics) + }; + + let empty_generics = ty::Generics::empty(); + let base_generics = base_def_id.map_or(&empty_generics, |def_id| { + generics_of_def_id(ccx, def_id) + }); + + let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); + let regions = early_lifetimes.iter().enumerate().map(|(i, l)| { + ty::RegionParameterDef { + name: l.lifetime.name, + space: space, + index: i as u32, + def_id: tcx.map.local_def_id(l.lifetime.id), + bounds: l.bounds.iter().map(|l| { + ast_region_to_region(tcx, l) + }).collect() + } + }).collect(); + + // Now create the real type parameters. + let types = ast_generics.ty_params.iter().enumerate().map(|(i, _)| { + get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32, allow_defaults) + }).collect(); + + let has_self = base_generics.has_self || opt_self.is_some(); + let (regions, types) = match space { + SelfSpace => bug!(), + TypeSpace => { + assert_eq!(base_generics.regions.as_full_slice().len(), 0); + assert_eq!(base_generics.types.as_full_slice().len(), 0); + (VecPerParamSpace::new(vec![], regions, vec![]), + VecPerParamSpace::new(opt_self.into_iter().collect(), types, vec![])) + } + FnSpace => { + assert_eq!(base_generics.regions.len(FnSpace), 0); + assert_eq!(base_generics.types.len(FnSpace), 0); + (VecPerParamSpace::new(base_generics.regions.get_slice(SelfSpace).to_vec(), + base_generics.regions.get_slice(TypeSpace).to_vec(), + regions), + VecPerParamSpace::new(base_generics.types.get_slice(SelfSpace).to_vec(), + base_generics.types.get_slice(TypeSpace).to_vec(), + types)) + } + }; + + // Debugging aid. + if tcx.has_attr(def_id, "rustc_object_lifetime_default") { + let object_lifetime_default_reprs: String = + types.as_full_slice().iter().map(|t| { + match t.object_lifetime_default { + ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), + d => format!("{:?}", d), + } + }).collect::>().join(","); + tcx.sess.span_err(tcx.map.span(node_id), &object_lifetime_default_reprs); } - } else { - ccx.tcx.lookup_item_type(def_id) - } + + tcx.alloc_generics(ty::Generics { + regions: regions, + types: types, + has_self: has_self + }) + }) } -fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - item: &hir::Item) - -> ty::TypeScheme<'tcx> -{ - let item_def_id = ccx.tcx.map.local_def_id(item.id); - ccx.tcx.tcache.memoize(item_def_id, || { - // NB. Since the `memoized` function enters a new task, and we - // are giving this task access to the item `item`, we must - // register a read. - assert!(!ccx.tcx.map.is_inlined_def_id(item_def_id)); - ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); - compute_type_scheme_of_item(ccx, item) +fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + def_id: DefId) + -> Ty<'tcx> { + let node_id = if let Some(id) = ccx.tcx.map.as_local_node_id(def_id) { + id + } else { + return ccx.tcx.lookup_item_type(def_id).ty; + }; + ccx.tcx.tcache.memoize(def_id, || { + use rustc::hir::map::*; + use rustc::hir::*; + + let ty = match ccx.tcx.map.get(node_id) { + NodeItem(item) => { + match item.node { + ItemStatic(ref t, _, _) | ItemConst(ref t, _) => { + ccx.icx(&()).to_ty(&ExplicitRscope, &t) + } + ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { + let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, + Some(AnonTypeScope::new(def_id))); + let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); + ccx.tcx.mk_fn_def(def_id, substs, tofd) + } + ItemTy(ref t, ref generics) => { + ccx.icx(generics).to_ty(&ExplicitRscope, &t) + } + ItemEnum(ref ei, ref generics) => { + let def = convert_enum_def(ccx, item, ei); + let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); + ccx.tcx.mk_enum(def, substs) + } + ItemStruct(ref si, ref generics) => { + let def = convert_struct_def(ccx, item, si); + let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); + ccx.tcx.mk_struct(def, substs) + } + ItemDefaultImpl(..) | + ItemTrait(..) | + ItemImpl(..) | + ItemMod(..) | + ItemForeignMod(..) | + ItemExternCrate(..) | + ItemUse(..) => { + span_bug!( + item.span, + "compute_type_of_item: unexpected item type: {:?}", + item.node); + } + } + } + NodeForeignItem(foreign_item) => { + let abi = ccx.tcx.map.get_foreign_abi(node_id); + + match foreign_item.node { + ForeignItemFn(ref fn_decl, ref generics) => { + compute_type_of_foreign_fn_decl( + ccx, ccx.tcx.map.local_def_id(foreign_item.id), + fn_decl, generics, abi) + } + ForeignItemStatic(ref t, _) => { + ccx.icx(&()).to_ty(&ExplicitRscope, t) + } + } + } + x => { + bug!("unexpected sort of node in type_of_def_id(): {:?}", x); + } + }; + + write_ty_to_tcx(ccx, node_id, ty); + ty }) } -fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - it: &hir::Item) - -> ty::TypeScheme<'tcx> -{ - let tcx = ccx.tcx; - match it.node { - hir::ItemStatic(ref t, _, _) | hir::ItemConst(ref t, _) => { - let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &t); - ty::TypeScheme { ty: ty, generics: ty::Generics::empty() } - } - hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { - let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); - let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, - Some(AnonTypeScope::new(&ty_generics))); - let def_id = ccx.tcx.map.local_def_id(it.id); - let substs = mk_item_substs(tcx, &ty_generics); - let ty = tcx.mk_fn_def(def_id, substs, tofd); - ty::TypeScheme { ty: ty, generics: ty_generics } - } - hir::ItemTy(ref t, ref generics) => { - let ty_generics = ty_generics_for_type(ccx, generics); - let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &t); - ty::TypeScheme { ty: ty, generics: ty_generics } - } - hir::ItemEnum(ref ei, ref generics) => { - let def = convert_enum_def(ccx, it, ei); - let ty_generics = ty_generics_for_type(ccx, generics); - let substs = mk_item_substs(tcx, &ty_generics); - let t = tcx.mk_enum(def, substs); - ty::TypeScheme { ty: t, generics: ty_generics } - } - hir::ItemStruct(ref si, ref generics) => { - let def = convert_struct_def(ccx, it, si); - let ty_generics = ty_generics_for_type(ccx, generics); - let substs = mk_item_substs(tcx, &ty_generics); - let t = tcx.mk_struct(def, substs); - ty::TypeScheme { ty: t, generics: ty_generics } - } - hir::ItemDefaultImpl(..) | - hir::ItemTrait(..) | - hir::ItemImpl(..) | - hir::ItemMod(..) | - hir::ItemForeignMod(..) | - hir::ItemExternCrate(..) | - hir::ItemUse(..) => { - span_bug!( - it.span, - "compute_type_scheme_of_item: unexpected item type: {:?}", - it.node); +fn type_scheme_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, + def_id: DefId) + -> ty::TypeScheme<'tcx> { + if def_id.is_local() { + ty::TypeScheme { + generics: generics_of_def_id(ccx, def_id), + ty: type_of_def_id(ccx, def_id) } + } else { + ccx.tcx.lookup_item_type(def_id) } } -fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) - -> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>) -{ - let tcx = ccx.tcx; - - let tag = type_scheme_of_item(ccx, it); - let scheme = TypeScheme { generics: tag.generics, ty: tag.ty }; + -> ty::GenericPredicates<'tcx> { + let def_id = ccx.tcx.map.local_def_id(it.id); let predicates = match it.node { hir::ItemStatic(..) | hir::ItemConst(..) => { ty::GenericPredicates::empty() @@ -1516,12 +1621,8 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, hir::ItemFn(_, _, _, _, ref ast_generics, _) => { ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty()) } - hir::ItemTy(_, ref generics) => { - ty_generic_predicates_for_type_or_impl(ccx, generics) - } - hir::ItemEnum(_, ref generics) => { - ty_generic_predicates_for_type_or_impl(ccx, generics) - } + hir::ItemTy(_, ref generics) | + hir::ItemEnum(_, ref generics) | hir::ItemStruct(_, ref generics) => { ty_generic_predicates_for_type_or_impl(ccx, generics) } @@ -1534,68 +1635,16 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, hir::ItemForeignMod(..) => { span_bug!( it.span, - "compute_type_scheme_of_item: unexpected item type: {:?}", + "predicates_of_item: unexpected item type: {:?}", it.node); } }; - let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - predicates.clone()); + let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, + predicates.clone()); assert!(prev_predicates.is_none()); - // Debugging aid. - if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") { - let object_lifetime_default_reprs: String = - scheme.generics.types.as_full_slice().iter() - .map(|t| match t.object_lifetime_default { - ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), - d => format!("{:?}", d), - }) - .collect::>() - .join(","); - - tcx.sess.span_err(it.span, &object_lifetime_default_reprs); - } - - return (scheme, predicates); -} - -fn type_scheme_of_foreign_item<'a, 'tcx>( - ccx: &CrateCtxt<'a, 'tcx>, - item: &hir::ForeignItem, - abi: abi::Abi) - -> ty::TypeScheme<'tcx> -{ - let item_def_id = ccx.tcx.map.local_def_id(item.id); - ccx.tcx.tcache.memoize(item_def_id, || { - // NB. Since the `memoized` function enters a new task, and we - // are giving this task access to the item `item`, we must - // register a read. - assert!(!ccx.tcx.map.is_inlined_def_id(item_def_id)); - ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); - compute_type_scheme_of_foreign_item(ccx, item, abi) - }) -} - -fn compute_type_scheme_of_foreign_item<'a, 'tcx>( - ccx: &CrateCtxt<'a, 'tcx>, - it: &hir::ForeignItem, - abi: abi::Abi) - -> ty::TypeScheme<'tcx> -{ - match it.node { - hir::ForeignItemFn(ref fn_decl, ref generics) => { - compute_type_scheme_of_foreign_fn_decl( - ccx, ccx.tcx.map.local_def_id(it.id), - fn_decl, generics, abi) - } - hir::ForeignItemStatic(ref t, _) => { - ty::TypeScheme { - generics: ty::Generics::empty(), - ty: AstConv::ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, t) - } - } - } + predicates } fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -1605,11 +1654,8 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // map, and I regard each time that I use it as a personal and // moral failing, but at the moment it seems like the only // convenient way to extract the ABI. - ndm - let tcx = ccx.tcx; - let abi = tcx.map.get_foreign_abi(it.id); - - let scheme = type_scheme_of_foreign_item(ccx, it, abi); - write_ty_to_tcx(ccx, it.id, scheme.ty); + let def_id = ccx.tcx.map.local_def_id(it.id); + type_scheme_of_def_id(ccx, def_id); let predicates = match it.node { hir::ForeignItemFn(_, ref generics) => { @@ -1620,21 +1666,10 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; - let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - predicates); + let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); assert!(prev_predicates.is_none()); } -fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &hir::Generics) - -> ty::Generics<'tcx> { - ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty(), true) -} - -fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &hir::Generics) - -> ty::Generics<'tcx> { - ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty(), false) -} - fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, generics: &hir::Generics) -> ty::GenericPredicates<'tcx> @@ -1642,50 +1677,6 @@ fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty()) } -fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - trait_id: ast::NodeId, - substs: &'tcx Substs<'tcx>, - ast_generics: &hir::Generics) - -> ty::Generics<'tcx> -{ - debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})", - ccx.tcx.map.local_def_id(trait_id), substs); - - let mut generics = ty_generics_for_type(ccx, ast_generics); - - // Add in the self type parameter. - // - // Something of a hack: use the node id for the trait, also as - // the node id for the Self type parameter. - let param_id = trait_id; - - let parent = ccx.tcx.map.get_parent(param_id); - - let def = ty::TypeParameterDef { - space: SelfSpace, - index: 0, - name: keywords::SelfType.name(), - def_id: ccx.tcx.map.local_def_id(param_id), - default_def_id: ccx.tcx.map.local_def_id(parent), - default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, - }; - - ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); - - generics.types.push(SelfSpace, def); - - return generics; -} - -fn ty_generics_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &hir::Generics, - base_generics: &ty::Generics<'tcx>) - -> ty::Generics<'tcx> -{ - ty_generics(ccx, FnSpace, generics, base_generics, false) -} - fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, generics: &hir::Generics, base_predicates: &ty::GenericPredicates<'tcx>) @@ -1859,42 +1850,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, result } -fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - space: ParamSpace, - ast_generics: &hir::Generics, - base_generics: &ty::Generics<'tcx>, - allow_defaults: bool) - -> ty::Generics<'tcx> -{ - let tcx = ccx.tcx; - let mut result = base_generics.clone(); - - let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); - for (i, l) in early_lifetimes.iter().enumerate() { - let bounds = l.bounds.iter() - .map(|l| ast_region_to_region(tcx, l)) - .collect(); - let def = ty::RegionParameterDef { name: l.lifetime.name, - space: space, - index: i as u32, - def_id: ccx.tcx.map.local_def_id(l.lifetime.id), - bounds: bounds }; - result.regions.push(space, def); - } - - assert!(result.types.is_empty_in(space)); - - // Now create the real type parameters. - for i in 0..ast_generics.ty_params.len() { - let def = - get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32, allow_defaults); - debug!("ty_generics: def for type param: {:?}, {:?}", def, space); - result.types.push(space, def); - } - - result -} - fn convert_default_type_parameter<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, path: &P, space: ParamSpace, @@ -1969,6 +1924,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); + debug!("get_or_create_type_parameter_def: def for type param: {:?}, {:?}", + def, space); + def } @@ -2122,16 +2080,14 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, } } -fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( +fn compute_type_of_foreign_fn_decl<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, - id: DefId, + def_id: DefId, decl: &hir::FnDecl, ast_generics: &hir::Generics, abi: abi::Abi) - -> ty::TypeScheme<'tcx> + -> Ty<'tcx> { - let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty()); - let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() @@ -2167,34 +2123,32 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( } } - let substs = mk_item_substs(ccx.tcx, &ty_generics); - let t_fn = ccx.tcx.mk_fn_def(id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { + let id = ccx.tcx.map.as_local_node_id(def_id).unwrap(); + let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.map.span(id), def_id); + ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { abi: abi, unsafety: hir::Unsafety::Unsafe, sig: ty::Binder(ty::FnSig {inputs: input_tys, output: output, variadic: decl.variadic}), - })); - - ty::TypeScheme { - generics: ty_generics, - ty: t_fn - } + })) } -pub fn mk_item_substs<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - ty_generics: &ty::Generics) - -> &'tcx Substs<'tcx> -{ - let types = - ty_generics.types.map( - |def| tcx.mk_param_from_def(def)); - - let regions = - ty_generics.regions.map( - |def| def.to_early_bound_region()); +pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, + span: Span, + def_id: DefId) + -> &'tcx Substs<'tcx> { + let tcx = astconv.tcx(); + // FIXME(eddyb) Do this request from Substs::for_item in librustc. + if let Err(ErrorReported) = astconv.get_generics(span, def_id) { + // No convenient way to recover from a cycle here. Just bail. Sorry! + tcx.sess.abort_if_errors(); + bug!("ErrorReported returned, but no errors reports?") + } - tcx.mk_substs(Substs::new(types, regions)) + Substs::for_item(tcx, def_id, + |def, _| def.to_early_bound_region(), + |def, _| tcx.mk_param_from_def(def)) } /// Checks that all the type parameters on an impl diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 4ce6f8210c3c5..8a8232535c775 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -231,7 +231,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, _ => () } let main_def_id = tcx.map.local_def_id(main_id); - let substs = tcx.mk_substs(Substs::empty()); + let substs = Substs::empty(tcx); let se_ty = tcx.mk_fn_def(main_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, @@ -284,7 +284,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, } let start_def_id = ccx.tcx.map.local_def_id(start_id); - let substs = tcx.mk_substs(Substs::empty()); + let substs = Substs::empty(tcx); let se_ty = tcx.mk_fn_def(start_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 58d1ec9d02a95..9aca779dd89c4 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -use rustc::ty::{self, TyCtxt}; +use rustc::hir::def_id::DefId; +use rustc::ty; use rustc::ty::subst::Substs; +use astconv::AstConv; + use std::cell::Cell; use syntax_pos::Span; @@ -71,33 +73,34 @@ pub trait RegionScope { } #[derive(Copy, Clone)] -pub struct AnonTypeScope<'a> { - generics: &'a ty::Generics<'a> +pub struct AnonTypeScope { + enclosing_item: DefId } -impl<'a, 'b, 'gcx, 'tcx> AnonTypeScope<'a> { - pub fn new(generics: &'a ty::Generics<'a>) -> AnonTypeScope<'a> { +impl<'gcx: 'tcx, 'tcx> AnonTypeScope { + pub fn new(enclosing_item: DefId) -> AnonTypeScope { AnonTypeScope { - generics: generics + enclosing_item: enclosing_item } } - pub fn fresh_substs(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { + pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span) + -> &'tcx Substs<'tcx> { use collect::mk_item_substs; - mk_item_substs(tcx, self.generics) + mk_item_substs(astconv, span, self.enclosing_item) } } /// A scope wrapper which optionally allows anonymized types. #[derive(Copy, Clone)] -pub struct MaybeWithAnonTypes<'a, R> { +pub struct MaybeWithAnonTypes { base_scope: R, - anon_scope: Option> + anon_scope: Option } -impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R> { - pub fn new(base_scope: R, anon_scope: Option>) -> Self { +impl MaybeWithAnonTypes { + pub fn new(base_scope: R, anon_scope: Option) -> Self { MaybeWithAnonTypes { base_scope: base_scope, anon_scope: anon_scope @@ -105,7 +108,7 @@ impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R> { } } -impl<'a, R: RegionScope> RegionScope for MaybeWithAnonTypes<'a, R> { +impl RegionScope for MaybeWithAnonTypes { fn object_lifetime_default(&self, span: Span) -> Option { self.base_scope.object_lifetime_default(span) } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 6e6f9ce65c50f..8c9b4beb79d84 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -16,8 +16,7 @@ use dep_graph::DepTrackingMapConfig; use hir::def_id::DefId; use middle::resolve_lifetime as rl; -use rustc::ty::subst; -use rustc::ty::subst::ParamSpace; +use rustc::ty::subst::{self, ParamSpace, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::ItemVariances; use rustc::hir::map as hir_map; @@ -370,8 +369,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, def.did, - item_type.generics.types.get_slice(subst::TypeSpace), - item_type.generics.regions.get_slice(subst::TypeSpace), + item_type.generics.types.as_full_slice(), + item_type.generics.regions.as_full_slice(), substs, variance); } @@ -449,7 +448,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { def_id: DefId, type_param_defs: &[ty::TypeParameterDef<'tcx>], region_param_defs: &[ty::RegionParameterDef], - substs: &subst::Substs<'tcx>, + substs: &Substs<'tcx>, variance: VarianceTermPtr<'a>) { debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})", def_id, diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 8bb49410a5bdc..22edf219dff75 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -16,6 +16,7 @@ //! inferred is then written into the `variance_map` in the tcx. use rustc::ty; +use rustc::ty::subst; use std::rc::Rc; use super::constraints::*; @@ -108,7 +109,9 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { let num_inferred = self.terms_cx.num_inferred(); while index < num_inferred { let item_id = inferred_infos[index].item_id; - let mut item_variances = ty::ItemVariances::empty(); + + let (mut rs, mut rt, mut rf) = (vec![], vec![], vec![]); + let (mut ts, mut tt, mut tf) = (vec![], vec![], vec![]); while index < num_inferred && inferred_infos[index].item_id == item_id { let info = &inferred_infos[index]; @@ -116,13 +119,34 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { debug!("Index {} Info {} / {:?} / {:?} Variance {:?}", index, info.index, info.kind, info.space, variance); match info.kind { - TypeParam => { item_variances.types.push(info.space, variance); } - RegionParam => { item_variances.regions.push(info.space, variance); } + TypeParam => { + let types = match info.space { + subst::SelfSpace => &mut ts, + subst::TypeSpace => &mut tt, + subst::FnSpace => &mut tf + }; + assert_eq!(types.len(), info.index); + types.push(variance); + } + RegionParam => { + let regions = match info.space { + subst::SelfSpace => &mut rs, + subst::TypeSpace => &mut rt, + subst::FnSpace => &mut rf + }; + assert_eq!(regions.len(), info.index); + regions.push(variance); + } } index += 1; } + let item_variances = ty::ItemVariances { + regions: subst::VecPerParamSpace::new(rs, rt, rf), + types: subst::VecPerParamSpace::new(ts, tt, tf) + }; + debug!("item_id={} item_variances={:?}", item_id, item_variances); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cea12404298fc..b4be201440ccf 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -161,7 +161,7 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc let def = tcx.lookup_trait_def(did); let trait_items = tcx.trait_items(did).clean(cx); let predicates = tcx.lookup_predicates(did); - let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); + let generics = (def.generics, &predicates, subst::TypeSpace).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); clean::Trait { @@ -189,7 +189,7 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx let predicates = tcx.lookup_predicates(did); clean::Function { decl: decl, - generics: (&t.generics, &predicates, subst::FnSpace).clean(cx), + generics: (t.generics, &predicates, subst::FnSpace).clean(cx), unsafety: style, constness: constness, abi: abi, @@ -209,7 +209,7 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, _ => doctree::Plain, }, - generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (t.generics, &predicates, subst::TypeSpace).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } @@ -222,7 +222,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, match t.ty.sty { ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => { return clean::EnumItem(clean::Enum { - generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (t.generics, &predicates, subst::TypeSpace).clean(cx), variants_stripped: false, variants: edef.variants.clean(cx), }) @@ -232,7 +232,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, clean::TypedefItem(clean::Typedef { type_: t.ty.clean(cx), - generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (t.generics, &predicates, subst::TypeSpace).clean(cx), }, false) } @@ -389,15 +389,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } ty::TypeTraitItem(ref assoc_ty) => { let did = assoc_ty.def_id; - let type_scheme = ty::TypeScheme { - ty: assoc_ty.ty.unwrap(), - generics: ty::Generics::empty() - }; // Not sure the choice of ParamSpace actually matters here, // because an associated type won't have generics on the LHS let typedef = clean::Typedef { - type_: type_scheme.ty.clean(cx), - generics: (&type_scheme.generics, + type_: assoc_ty.ty.unwrap().clean(cx), + generics: (&ty::Generics::empty(), &ty::GenericPredicates::empty(), subst::TypeSpace).clean(cx) }; @@ -438,7 +434,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, provided_trait_methods: provided, trait_: trait_, for_: for_, - generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (ty.generics, &predicates, subst::TypeSpace).clean(cx), items: trait_items, polarity: polarity.map(|p| { p.clean(cx) }), }), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ffe5b9aad2fb3..f8a3a0af69752 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; -use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace}; +use rustc::ty::subst::{self, ParamSpace, Substs, VecPerParamSpace}; use rustc::ty; use rustc::middle::stability; @@ -631,7 +631,7 @@ impl Clean for hir::TyParamBound { } fn external_path_params(cx: &DocContext, trait_did: Option, - bindings: Vec, substs: &subst::Substs) -> PathParameters { + bindings: Vec, substs: &Substs) -> PathParameters { let lifetimes = substs.regions.get_slice(subst::TypeSpace) .iter() .filter_map(|v| v.clean(cx)) @@ -676,7 +676,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C fn external_path(cx: &DocContext, name: &str, trait_did: Option, - bindings: Vec, substs: &subst::Substs) -> Path { + bindings: Vec, substs: &Substs) -> Path { Path { global: false, segments: vec![PathSegment { @@ -692,20 +692,20 @@ impl Clean for ty::BuiltinBound { Some(tcx) => tcx, None => return RegionBound(Lifetime::statik()) }; - let empty = subst::Substs::empty(); + let empty = Substs::empty(tcx); let (did, path) = match *self { ty::BoundSend => (tcx.lang_items.send_trait().unwrap(), - external_path(cx, "Send", None, vec![], &empty)), + external_path(cx, "Send", None, vec![], empty)), ty::BoundSized => (tcx.lang_items.sized_trait().unwrap(), - external_path(cx, "Sized", None, vec![], &empty)), + external_path(cx, "Sized", None, vec![], empty)), ty::BoundCopy => (tcx.lang_items.copy_trait().unwrap(), - external_path(cx, "Copy", None, vec![], &empty)), + external_path(cx, "Copy", None, vec![], empty)), ty::BoundSync => (tcx.lang_items.sync_trait().unwrap(), - external_path(cx, "Sync", None, vec![], &empty)), + external_path(cx, "Sync", None, vec![], empty)), }; inline::record_extern_fqn(cx, did, TypeTrait); TraitBound(PolyTrait { @@ -765,7 +765,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { } } -impl<'tcx> Clean>> for subst::Substs<'tcx> { +impl<'tcx> Clean>> for Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { let mut v = Vec::new(); v.extend(self.regions.as_full_slice().iter().filter_map(|r| r.clean(cx)) @@ -891,7 +891,7 @@ impl<'a> Clean for ty::Predicate<'a> { impl<'a> Clean for ty::TraitPredicate<'a> { fn clean(&self, cx: &DocContext) -> WherePredicate { WherePredicate::BoundPredicate { - ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(), + ty: self.trait_ref.self_ty().clean(cx), bounds: vec![self.trait_ref.clean(cx)] } } @@ -1353,7 +1353,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { predicates: self.predicates.predicates[method_start..].to_vec() }; - let generics = (&self.generics, &method_predicates, + let generics = (self.generics, &method_predicates, subst::FnSpace).clean(cx); let mut decl = (self.def_id, &self.fty.sig).clean(cx); match self.explicit_self { @@ -2923,7 +2923,7 @@ impl<'tcx> Clean for ty::AssociatedType<'tcx> { // applied to this associated type in question. let def = cx.tcx().lookup_trait_def(did); let predicates = cx.tcx().lookup_predicates(did); - let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); + let generics = (def.generics, &predicates, subst::TypeSpace).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { WherePredicate::BoundPredicate { From c1cfd58cbdb84f834b8907dc5e1c7242c451225d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 15 Aug 2016 01:07:09 +0300 Subject: [PATCH 068/768] rustc: remove SelfSpace from ParamSpace. --- src/librustc/hir/def.rs | 5 +- src/librustc/middle/dead.rs | 2 +- src/librustc/traits/coherence.rs | 6 +- src/librustc/traits/error_reporting.rs | 4 +- src/librustc/traits/object_safety.rs | 9 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/error.rs | 3 +- src/librustc/ty/flags.rs | 4 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 14 +++- src/librustc/ty/subst.rs | 78 ++++++----------- src/librustc/util/ppaux.rs | 67 +++++++-------- .../borrowck/mir/elaborate_drops.rs | 6 +- src/librustc_metadata/astencode.rs | 2 +- src/librustc_metadata/tydecode.rs | 6 +- src/librustc_resolve/lib.rs | 32 ++----- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_trans/partitioning.rs | 2 +- src/librustc_typeck/astconv.rs | 52 ++++++++---- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 6 +- src/librustc_typeck/check/method/probe.rs | 8 +- src/librustc_typeck/check/mod.rs | 27 ++++-- src/librustc_typeck/check/wfcheck.rs | 45 +++------- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 83 +++++++------------ src/librustc_typeck/variance/constraints.rs | 8 +- src/librustc_typeck/variance/solve.rs | 10 +-- src/librustc_typeck/variance/terms.rs | 12 +-- src/librustdoc/clean/mod.rs | 38 +++++---- src/test/compile-fail/issue-26548.rs | 4 +- src/test/compile-fail/issue-26812.rs | 4 +- .../compile-fail/variance-associated-types.rs | 4 +- .../compile-fail/variance-object-types.rs | 2 +- .../compile-fail/variance-region-bounds.rs | 4 +- .../compile-fail/variance-regions-direct.rs | 14 ++-- .../compile-fail/variance-regions-indirect.rs | 10 +-- .../compile-fail/variance-trait-bounds.rs | 18 ++-- .../variance-trait-object-bound.rs | 2 +- .../compile-fail/variance-types-bounds.rs | 20 ++--- src/test/compile-fail/variance-types.rs | 12 +-- 41 files changed, 276 insertions(+), 357 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 218681efb7dc1..d15d51aed09a1 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -9,7 +9,6 @@ // except according to those terms. use hir::def_id::DefId; -use ty::subst::ParamSpace; use util::nodemap::NodeMap; use syntax::ast; use hir; @@ -31,7 +30,7 @@ pub enum Def { AssociatedTy(DefId /* trait */, DefId), Trait(DefId), PrimTy(hir::PrimTy), - TyParam(ParamSpace, u32, DefId, ast::Name), + TyParam(DefId), Upvar(DefId, // def id of closed over local ast::NodeId, // node id of closed over local usize, // index in the freevars list of the closure @@ -122,7 +121,7 @@ impl Def { match *self { Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) | Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) | - Def::TyParam(_, _, id, _) | Def::Struct(id) | Def::Trait(id) | + Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Local(id, _) | Def::Upvar(id, _, _, _) => { id diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 7412b5fc8048f..20e281816b8b0 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { - match substs.substs.types.get(subst::SelfSpace, 0).sty { + match substs.substs.types.get(subst::TypeSpace, 0).sty { TyEnum(tyid, _) | TyStruct(tyid, _) => { self.check_def_id(tyid.did) } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index f1701d60fd0c0..a5a415dd27c65 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -14,7 +14,6 @@ use super::{SelectionContext, Obligation, ObligationCause}; use middle::cstore::LOCAL_CRATE; use hir::def_id::DefId; -use ty::subst::TypeSpace; use ty::{self, Ty, TyCtxt}; use infer::{InferCtxt, TypeOrigin}; use syntax_pos::DUMMY_SP; @@ -160,12 +159,9 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt, // First, create an ordered iterator over all the type parameters to the trait, with the self // type appearing first. - let input_tys = Some(trait_ref.self_ty()); - let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace)); - // Find the first input type that either references a type parameter OR // some local type. - for input_ty in input_tys { + for input_ty in trait_ref.input_types() { if ty_is_local(tcx, input_ty, infer_is_local) { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index e67c0ba8053d7..77c1137c6c3be 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -232,8 +232,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) { self_match_impls.push(def_id); - if trait_ref.substs.types.get_slice(TypeSpace).iter() - .zip(impl_trait_ref.substs.types.get_slice(TypeSpace)) + if trait_ref.substs.types.get_slice(TypeSpace)[1..].iter() + .zip(&impl_trait_ref.substs.types.get_slice(TypeSpace)[1..]) .all(|(u,v)| self.fuzzy_match_tys(u, v)) { fuzzy_match_impls.push(def_id); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index ecfa7930d0294..11cf759859c62 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -20,7 +20,7 @@ use super::elaborate_predicates; use hir::def_id::DefId; -use ty::subst::{self, SelfSpace, TypeSpace}; +use ty::subst; use traits; use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use std::rc::Rc; @@ -146,10 +146,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match predicate { ty::Predicate::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.0.trait_ref.substs.types.get_slice(TypeSpace) - .iter() - .cloned() - .any(|t| t.has_self_ty()) + data.0.trait_ref.input_types()[1..].iter().any(|t| t.has_self_ty()) } ty::Predicate::Projection(..) | ty::Predicate::WellFormed(..) | @@ -325,7 +322,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty.maybe_walk(|ty| { match ty.sty { ty::TyParam(ref param_ty) => { - if param_ty.space == SelfSpace { + if param_ty.is_self() { error = true; } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 9356b408a51cb..c2daa81ca7dab 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1353,7 +1353,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(subst::SelfSpace, 0, keywords::SelfType.name()) + self.mk_param(subst::TypeSpace, 0, keywords::SelfType.name()) } pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 933746ebc2ad1..17f9b6c25995c 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -9,7 +9,6 @@ // except according to those terms. use hir::def_id::DefId; -use ty::subst; use infer::type_variable; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; @@ -258,7 +257,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), ty::TyProjection(_) => "associated type".to_string(), ty::TyParam(ref p) => { - if p.space == subst::SelfSpace { + if p.is_self() { "Self".to_string() } else { "type parameter".to_string() diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 312b09cd27dfc..900e1841fb592 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::subst::{self, Substs}; +use ty::subst::Substs; use ty::{self, Ty, TypeFlags, TypeFoldable}; pub struct FlagComputation { @@ -77,7 +77,7 @@ impl FlagComputation { &ty::TyParam(ref p) => { self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - if p.space == subst::SelfSpace { + if p.is_self() { self.add_flags(TypeFlags::HAS_SELF); } else { self.add_flags(TypeFlags::HAS_PARAMS); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36784e4006461..96537904d36e8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1225,7 +1225,7 @@ impl<'tcx> TraitRef<'tcx> { } pub fn self_ty(&self) -> Ty<'tcx> { - *self.substs.types.get(subst::SelfSpace, 0) + *self.substs.types.get(subst::TypeSpace, 0) } pub fn input_types(&self) -> &[Ty<'tcx>] { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index f31b844f04fe6..8786e2d16d22a 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -305,7 +305,7 @@ pub struct TraitObject<'tcx> { /// /// This would be represented by a trait-reference where the def-id is the /// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the -/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`. +/// `TypeSpace` and `U` as parameter 1 in the `TypeSpace`. /// /// Trait references also appear in object types like `Foo`, but in /// that case the `Self` parameter is absent from the substitutions. @@ -512,7 +512,7 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn for_self() -> ParamTy { - ParamTy::new(subst::SelfSpace, 0, keywords::SelfType.name()) + ParamTy::new(subst::TypeSpace, 0, keywords::SelfType.name()) } pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { @@ -524,7 +524,13 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn is_self(&self) -> bool { - self.space == subst::SelfSpace && self.idx == 0 + if self.name == keywords::SelfType.name() { + assert_eq!(self.space, subst::TypeSpace); + assert_eq!(self.idx, 0); + true + } else { + false + } } } @@ -954,7 +960,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_self(&self) -> bool { match self.sty { - TyParam(ref p) => p.space == subst::SelfSpace, + TyParam(ref p) => p.is_self(), _ => false } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 00537f9d6c5dc..2f95baa562589 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -47,8 +47,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { r: Vec) -> &'tcx Substs<'tcx> { - Substs::new(tcx, VecPerParamSpace::new(vec![], vec![], t), - VecPerParamSpace::new(vec![], vec![], r)) + Substs::new(tcx, VecPerParamSpace::new(vec![], t), + VecPerParamSpace::new(vec![], r)) } pub fn new_type(tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -56,18 +56,19 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { r: Vec) -> &'tcx Substs<'tcx> { - Substs::new(tcx, VecPerParamSpace::new(vec![], t, vec![]), - VecPerParamSpace::new(vec![], r, vec![])) + Substs::new(tcx, VecPerParamSpace::new(t, vec![]), + VecPerParamSpace::new(r, vec![])) } pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>, - t: Vec>, + mut t: Vec>, r: Vec, s: Ty<'tcx>) -> &'tcx Substs<'tcx> { - Substs::new(tcx, VecPerParamSpace::new(vec![s], t, vec![]), - VecPerParamSpace::new(vec![], r, vec![])) + t.insert(0, s); + Substs::new(tcx, VecPerParamSpace::new(t, vec![]), + VecPerParamSpace::new(r, vec![])) } pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { @@ -90,12 +91,10 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let defs = tcx.lookup_generics(def_id); let mut substs = Substs { types: VecPerParamSpace { - self_limit: 0, type_limit: 0, content: Vec::with_capacity(defs.types.content.len()) }, regions: VecPerParamSpace { - self_limit: 0, type_limit: 0, content: Vec::with_capacity(defs.regions.content.len()) } @@ -104,7 +103,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { for &space in &ParamSpace::all() { for def in defs.regions.get_slice(space) { assert_eq!(def.space, space); - assert!(space != SelfSpace); let region = mk_region(def, &substs); substs.regions.content.push(region); @@ -120,11 +118,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let ty = mk_type(def, &substs); substs.types.content.push(ty); - if space == SelfSpace { - substs.types.self_limit += 1; - } - - if space <= TypeSpace { + if space == TypeSpace { substs.types.type_limit += 1; } } @@ -155,7 +149,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { let defs = tcx.lookup_generics(source_ancestor); - assert_eq!(self.types.len(SelfSpace), defs.types.len(SelfSpace)); assert_eq!(self.types.len(TypeSpace), defs.types.len(TypeSpace)); assert_eq!(target_substs.types.len(FnSpace), 0); assert_eq!(defs.types.len(FnSpace), 0); @@ -195,29 +188,26 @@ impl<'tcx> Decodable for &'tcx Substs<'tcx> { #[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum ParamSpace { - SelfSpace, // Self parameter on a trait TypeSpace, // Type parameters attached to a type definition, trait, or impl FnSpace, // Type parameters attached to a method or fn } impl ParamSpace { - pub fn all() -> [ParamSpace; 3] { - [SelfSpace, TypeSpace, FnSpace] + pub fn all() -> [ParamSpace; 2] { + [TypeSpace, FnSpace] } pub fn to_uint(self) -> usize { match self { - SelfSpace => 0, - TypeSpace => 1, - FnSpace => 2, + TypeSpace => 0, + FnSpace => 1, } } pub fn from_uint(u: usize) -> ParamSpace { match u { - 0 => SelfSpace, - 1 => TypeSpace, - 2 => FnSpace, + 0 => TypeSpace, + 1 => FnSpace, _ => bug!("Invalid ParamSpace: {}", u) } } @@ -235,18 +225,15 @@ pub struct VecPerParamSpace { // Here is how the representation corresponds to the abstraction // i.e. the "abstraction function" AF: // - // AF(self) = (self.content[..self.self_limit], - // self.content[self.self_limit..self.type_limit], + // AF(self) = (self.content[..self.type_limit], // self.content[self.type_limit..]) - self_limit: usize, type_limit: usize, content: Vec, } impl fmt::Debug for VecPerParamSpace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{:?};{:?};{:?}]", - self.get_slice(SelfSpace), + write!(f, "[{:?};{:?}]", self.get_slice(TypeSpace), self.get_slice(FnSpace)) } @@ -255,43 +242,34 @@ impl fmt::Debug for VecPerParamSpace { impl VecPerParamSpace { fn limits(&self, space: ParamSpace) -> (usize, usize) { match space { - SelfSpace => (0, self.self_limit), - TypeSpace => (self.self_limit, self.type_limit), + TypeSpace => (0, self.type_limit), FnSpace => (self.type_limit, self.content.len()), } } pub fn empty() -> VecPerParamSpace { VecPerParamSpace { - self_limit: 0, type_limit: 0, content: Vec::new() } } - /// `s` is the self space. /// `t` is the type space. /// `f` is the fn space. - pub fn new(s: Vec, t: Vec, f: Vec) -> VecPerParamSpace { - let self_limit = s.len(); - let type_limit = self_limit + t.len(); + pub fn new(t: Vec, f: Vec) -> VecPerParamSpace { + let type_limit = t.len(); - let mut content = s; - content.extend(t); + let mut content = t; content.extend(f); VecPerParamSpace { - self_limit: self_limit, type_limit: type_limit, content: content, } } - fn new_internal(content: Vec, self_limit: usize, type_limit: usize) - -> VecPerParamSpace - { + fn new_internal(content: Vec, type_limit: usize) -> VecPerParamSpace { VecPerParamSpace { - self_limit: self_limit, type_limit: type_limit, content: content, } @@ -336,18 +314,14 @@ impl VecPerParamSpace { pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { let result = self.as_full_slice().iter().map(pred).collect(); - VecPerParamSpace::new_internal(result, - self.self_limit, - self.type_limit) + VecPerParamSpace::new_internal(result, self.type_limit) } pub fn map_enumerated(&self, pred: P) -> VecPerParamSpace where P: FnMut((ParamSpace, usize, &T)) -> U, { let result = self.iter_enumerated().map(pred).collect(); - VecPerParamSpace::new_internal(result, - self.self_limit, - self.type_limit) + VecPerParamSpace::new_internal(result, self.type_limit) } } @@ -639,8 +613,6 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { -> ty::ExistentialTraitRef<'tcx> { let Substs { mut types, regions } = trait_ref.substs.clone(); - assert_eq!(types.self_limit, 1); - types.self_limit = 0; types.type_limit -= 1; types.content.remove(0); @@ -665,8 +637,6 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { self.map_bound(|trait_ref| { let Substs { mut types, regions } = trait_ref.substs.clone(); - assert_eq!(types.self_limit, 0); - types.self_limit = 1; types.type_limit += 1; types.content.insert(0, self_ty); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index cdbd307052364..800ad865208aa 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -62,35 +62,36 @@ pub enum Ns { Value } -fn number_of_supplied_defaults<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - substs: &subst::Substs, - space: subst::ParamSpace, - generics: &ty::Generics<'tcx>) - -> usize -{ - let ty_params = generics.types.get_slice(space); - let tps = substs.types.get_slice(space); - if ty_params.last().map_or(false, |def| def.default.is_some()) { - let substs = tcx.lift(&substs); - ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| { - substs.and_then(|substs| def.default.subst(tcx, substs)) - == Some(actual) - }).count() - } else { - 0 - } -} - pub fn parameterized(f: &mut fmt::Formatter, substs: &subst::Substs, did: DefId, ns: Ns, projections: &[ty::ProjectionPredicate]) -> fmt::Result { - let (fn_trait_kind, verbose, item_name, is_in_trait) = ty::tls::with(|tcx| { - let is_in_trait = ns == Ns::Value && tcx.trait_of_item(did).is_some(); - if is_in_trait { - write!(f, "<{} as ", substs.types.get(subst::SelfSpace, 0))?; + let mut verbose = false; + let mut num_supplied_defaults = 0; + let mut has_self = false; + let (fn_trait_kind, item_name) = ty::tls::with(|tcx| { + verbose = tcx.sess.verbose(); + let generics = tcx.lookup_generics(did); + if !verbose { + let ty_params = generics.types.get_slice(subst::TypeSpace); + if ty_params.last().map_or(false, |def| def.default.is_some()) { + if let Some(substs) = tcx.lift(&substs) { + let tps = substs.types.get_slice(subst::TypeSpace); + for (def, actual) in ty_params.iter().zip(tps).rev() { + if def.default.subst(tcx, substs) != Some(actual) { + break; + } + num_supplied_defaults += 1; + } + } + } + } + + has_self = generics.has_self; + if ns == Ns::Value && has_self { + write!(f, "<{} as ", substs.types.get(subst::TypeSpace, 0))?; } let (did, item_name) = if ns == Ns::Value { @@ -107,15 +108,12 @@ pub fn parameterized(f: &mut fmt::Formatter, (did, None) }; write!(f, "{}", tcx.item_path_str(did))?; - Ok((tcx.lang_items.fn_trait_kind(did), - tcx.sess.verbose(), - item_name, - is_in_trait)) + Ok((tcx.lang_items.fn_trait_kind(did), item_name)) })?; if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { let projection_ty = projections[0].ty; - if let TyTuple(ref args) = substs.types.get(subst::TypeSpace, 0).sty { + if let TyTuple(ref args) = substs.types.get(subst::TypeSpace, 1).sty { return fn_sig(f, args, false, projection_ty); } } @@ -160,18 +158,9 @@ pub fn parameterized(f: &mut fmt::Formatter, print_regions(f, "<", substs.regions.get_slice(subst::TypeSpace))?; - let num_supplied_defaults = if verbose { - 0 - } else { - ty::tls::with(|tcx| { - let generics = tcx.lookup_generics(did); - number_of_supplied_defaults(tcx, substs, subst::TypeSpace, generics) - }) - }; - let tps = substs.types.get_slice(subst::TypeSpace); - for &ty in &tps[..tps.len() - num_supplied_defaults] { + for &ty in &tps[has_self as usize..tps.len() - num_supplied_defaults] { start_or_continue(f, "<", ", ")?; write!(f, "{}", ty)?; } @@ -189,7 +178,7 @@ pub fn parameterized(f: &mut fmt::Formatter, if ns == Ns::Value { empty.set(true); - if is_in_trait { + if has_self { write!(f, ">")?; } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index df91ec2b98d5d..9f300b5b29ba8 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -16,7 +16,7 @@ use super::{drop_flag_effects_for_location, on_all_children_bits}; use super::{DropFlagState, MoveDataParamEnv}; use super::patch::MirPatch; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::{Subst, Substs, VecPerParamSpace}; +use rustc::ty::subst::{Subst, Substs}; use rustc::mir::repr::*; use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; @@ -859,9 +859,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil())); let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new(tcx, - VecPerParamSpace::new(vec![], vec![], vec![ty]), - VecPerParamSpace::new(vec![], vec![], vec![])); + let substs = Substs::new_fn(tcx, vec![ty], vec![]); let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); self.patch.new_block(BasicBlockData { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 1b00eee76f69b..1ef48e6d6565f 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -413,7 +413,7 @@ impl tr for Def { Def::AssociatedTy(trait_did, did) => Def::AssociatedTy(trait_did.tr(dcx), did.tr(dcx)), Def::PrimTy(p) => Def::PrimTy(p), - Def::TyParam(s, index, def_id, n) => Def::TyParam(s, index, def_id.tr(dcx), n), + Def::TyParam(did) => Def::TyParam(did.tr(dcx)), Def::Upvar(_, nid1, index, nid2) => { let nid1 = dcx.tr_id(nid1); let nid2 = dcx.tr_id(nid2); diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 3f0fa9073aa36..82d050a1de9d7 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -131,15 +131,15 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { fn parse_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T, { - let (mut a, mut b, mut c) = (vec![], vec![], vec![]); - for r in &mut [&mut a, &mut b, &mut c] { + let (mut a, mut b) = (vec![], vec![]); + for r in &mut [&mut a, &mut b] { assert_eq!(self.next(), '['); while self.peek() != ']' { r.push(f(self)); } assert_eq!(self.next(), ']'); } - VecPerParamSpace::new(a, b, c) + VecPerParamSpace::new(a, b) } pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 962509be324de..65e14eee4bc2b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -49,7 +49,6 @@ use rustc::lint; use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::ty; -use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace}; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; @@ -557,7 +556,7 @@ impl<'a> Visitor for Resolver<'a> { fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { let type_parameters = match foreign_item.node { ForeignItemKind::Fn(_, ref generics) => { - HasTypeParameters(generics, FnSpace, ItemRibKind) + HasTypeParameters(generics, ItemRibKind) } ForeignItemKind::Static(..) => NoTypeParameters, }; @@ -625,10 +624,6 @@ enum TypeParameters<'a, 'b> { HasTypeParameters(// Type parameters. &'b Generics, - // Identifies the things that these parameters - // were declared on (type, fn, etc) - ParamSpace, - // The kind of the rib used for type parameters. RibKind<'a>), } @@ -1613,12 +1608,9 @@ impl<'a> Resolver<'a> { match item.node { ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) | - ItemKind::Struct(_, ref generics) => { - self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, ItemRibKind), - |this| visit::walk_item(this, item)); - } + ItemKind::Struct(_, ref generics) | ItemKind::Fn(_, _, _, _, ref generics, _) => { - self.with_type_parameter_rib(HasTypeParameters(generics, FnSpace, ItemRibKind), + self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| visit::walk_item(this, item)); } @@ -1634,10 +1626,7 @@ impl<'a> Resolver<'a> { ItemKind::Trait(_, ref generics, ref bounds, ref trait_items) => { // Create a new rib for the trait-wide type parameters. - self.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - ItemRibKind), - |this| { + self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| { let local_def_id = this.definitions.local_def_id(item.id); this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| { this.visit_generics(generics); @@ -1660,7 +1649,6 @@ impl<'a> Resolver<'a> { TraitItemKind::Method(ref sig, _) => { let type_parameters = HasTypeParameters(&sig.generics, - FnSpace, MethodRibKind(!sig.decl.has_self())); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_trait_item(this, trait_item) @@ -1729,10 +1717,10 @@ impl<'a> Resolver<'a> { where F: FnOnce(&mut Resolver) { match type_parameters { - HasTypeParameters(generics, space, rib_kind) => { + HasTypeParameters(generics, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); let mut seen_bindings = HashSet::new(); - for (index, type_parameter) in generics.ty_params.iter().enumerate() { + for type_parameter in &generics.ty_params { let name = type_parameter.ident.name; debug!("with_type_parameter_rib: {}", type_parameter.id); @@ -1745,7 +1733,7 @@ impl<'a> Resolver<'a> { // plain insert (no renaming) let def_id = self.definitions.local_def_id(type_parameter.id); - let def = Def::TyParam(space, index as u32, def_id, name); + let def = Def::TyParam(def_id); function_type_rib.bindings.insert(ast::Ident::with_empty_ctxt(name), def); self.record_def(type_parameter.id, PathResolution::new(def)); } @@ -1917,10 +1905,7 @@ impl<'a> Resolver<'a> { item_id: NodeId, impl_items: &[ImplItem]) { // If applicable, create a rib for the type parameters. - self.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - ItemRibKind), - |this| { + self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| { // Resolve the type parameters. this.visit_generics(generics); @@ -1953,7 +1938,6 @@ impl<'a> Resolver<'a> { // specific type parameters. let type_parameters = HasTypeParameters(&sig.generics, - FnSpace, MethodRibKind(!sig.decl.has_self())); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_impl_item(this, impl_item); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 6c9cf1a5625b2..db535e22f194d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -490,7 +490,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::Enum(def_id) | Def::TyAlias(def_id) | Def::Trait(def_id) | - Def::TyParam(_, _, def_id, _) => { + Def::TyParam(def_id) => { Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), ref_id: Some(def_id), diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index f24ab0f65578c..1e90f273301ff 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -488,7 +488,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // DefId, we use the location of the impl after all. if tcx.trait_of_item(instance.def).is_some() { - let self_ty = *instance.substs.types.get(subst::SelfSpace, 0); + let self_ty = *instance.substs.types.get(subst::TypeSpace, 0); // This is an implementation of a trait method. return characteristic_def_id_of_type(self_ty).or(Some(instance.def)); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5655c7c8e7291..109cfd2abf6e5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use hir::def_id::DefId; use hir::print as pprust; use middle::resolve_lifetime as rl; use rustc::lint; -use rustc::ty::subst::{TypeSpace, SelfSpace, Subst, Substs}; +use rustc::ty::subst::{TypeSpace, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -455,6 +455,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Check the number of type parameters supplied by the user. if let Some(num_provided) = num_types_provided { let ty_param_defs = decl_generics.types.get_slice(TypeSpace); + let ty_param_defs = &ty_param_defs[self_ty.is_some() as usize..]; check_type_argument_count(tcx, span, num_provided, ty_param_defs); } @@ -476,13 +477,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assert_eq!(def.space, TypeSpace); regions[def.index as usize] }, |def, substs| { - assert!(def.space == SelfSpace || def.space == TypeSpace); + assert!(def.space == TypeSpace); let i = def.index as usize; - if def.space == SelfSpace { - // Self, which must have been provided. - assert_eq!(i, 0); - self_ty.expect("Self type parameter missing") - } else if num_types_provided.map_or(false, |n| i < n) { + + // Handle Self first, so we can adjust the index to match the AST. + if let (0, Some(ty)) = (i, self_ty) { + return ty; + } + + let i = i - self_ty.is_some() as usize; + if num_types_provided.map_or(false, |n| i < n) { // A provided type parameter. match *parameters { hir::AngleBracketedParameters(ref data) => { @@ -1325,8 +1329,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Err(ErrorReported) => return (tcx.types.err, Def::Err), } } - (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => { + (&ty::TyParam(_), Def::TyParam(param_did)) => { let param_node_id = tcx.map.as_local_node_id(param_did).unwrap(); + let param_name = tcx.type_parameter_def(param_node_id).name; match self.find_bound_for_assoc_item(param_node_id, param_name, assoc_name, @@ -1336,10 +1341,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } _ => { - self.report_ambiguous_associated_type(span, - &ty.to_string(), - "Trait", - &assoc_name.as_str()); + // Don't print TyErr to the user. + if !ty.references_error() { + self.report_ambiguous_associated_type(span, + &ty.to_string(), + "Trait", + &assoc_name.as_str()); + } return (tcx.types.err, Def::Err); } }; @@ -1477,9 +1485,25 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { did, base_segments.last().unwrap()) } - Def::TyParam(space, index, _, name) => { + Def::TyParam(did) => { tcx.prohibit_type_params(base_segments); - tcx.mk_param(space, index, name) + + let node_id = tcx.map.as_local_node_id(did).unwrap(); + let param = tcx.ty_param_defs.borrow().get(&node_id) + .map(ty::ParamTy::for_def); + if let Some(p) = param { + p.to_ty(tcx) + } else { + // Only while computing defaults of earlier type + // parameters can a type parameter be missing its def. + struct_span_err!(tcx.sess, span, E0128, + "type parameters with a default cannot use \ + forward declared identifiers") + .span_label(span, &format!("defaulted type parameters \ + cannot be forward declared")) + .emit(); + tcx.types.err + } } Def::SelfTy(_, Some(impl_id)) => { // Self in impl (we know the concrete type). diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8a007293e64ff..087549a2f1c4c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -204,7 +204,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } - let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); + let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1); let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e5107af6ca04b..a9e08461fd28e 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let trait_def = self.tcx.lookup_trait_def(trait_def_id); if let Some(ref input_types) = opt_input_types { - assert_eq!(trait_def.generics.types.len(subst::TypeSpace), input_types.len()); + assert_eq!(trait_def.generics.types.len(subst::TypeSpace) - 1, input_types.len()); } assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0); assert!(trait_def.generics.regions.is_empty()); @@ -192,10 +192,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { - if def.space == subst::SelfSpace { + if def.index == 0 { self_ty } else if let Some(ref input_types) = opt_input_types { - input_types[def.index as usize] + input_types[def.index as usize - 1] } else { self.type_var_for_def(span, def, substs) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 448ea243655a8..044de179917b4 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -522,10 +522,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_ref.substs.types.len(subst::TypeSpace)); assert_eq!(m.generics.regions.len(subst::TypeSpace), trait_ref.substs.regions.len(subst::TypeSpace)); - assert_eq!(m.generics.types.len(subst::SelfSpace), - trait_ref.substs.types.len(subst::SelfSpace)); - assert_eq!(m.generics.regions.len(subst::SelfSpace), - trait_ref.substs.regions.len(subst::SelfSpace)); } // Because this trait derives from a where-clause, it @@ -755,11 +751,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { self.region_var_for_def(self.span, def) }, |def, substs| { - if def.space == subst::SelfSpace { - assert_eq!(def.index, 0); + if def.index == 0 { step.self_ty } else { - assert_eq!(def.space, subst::TypeSpace); self.type_var_for_def(self.span, def, substs) } }); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 700fb2ecf42dd..ae3378f41f936 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4225,7 +4225,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| { let i = def.index as usize; let segment = match def.space { - subst::SelfSpace => None, subst::TypeSpace => type_segment, subst::FnSpace => fn_segment }; @@ -4241,9 +4240,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.region_var_for_def(span, def) } }, |def, substs| { - let i = def.index as usize; + let mut i = def.index as usize; let segment = match def.space { - subst::SelfSpace => None, subst::TypeSpace => type_segment, subst::FnSpace => fn_segment }; @@ -4252,18 +4250,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(&hir::ParenthesizedParameters(_)) => bug!(), None => &[] }; + + // Handle Self first, so we can adjust the index to match the AST. + if scheme.generics.has_self && def.space == subst::TypeSpace { + if i == 0 { + return opt_self_ty.unwrap_or_else(|| { + self.type_var_for_def(span, def, substs) + }); + } + i -= 1; + } + let can_omit = def.space != subst::TypeSpace || !require_type_space; let default = if can_omit && types.len() == 0 { def.default } else { None }; - - if def.space == subst::SelfSpace && opt_self_ty.is_some() { - // Self, which has been provided. - assert_eq!(i, 0); - opt_self_ty.unwrap() - } else if let Some(ast_ty) = types.get(i) { + if let Some(ast_ty) = types.get(i) { // A provided type parameter. self.to_ty(ast_ty) } else if let Some(default) = default { @@ -4371,6 +4375,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Check provided type parameters. let type_defs = generics.types.get_slice(space); + let type_defs = if space == subst::TypeSpace { + &type_defs[generics.has_self as usize..] + } else { + type_defs + }; let required_len = type_defs.iter() .take_while(|d| d.default.is_none()) .count(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 678c102a4de3b..f2076895f0873 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -14,13 +14,12 @@ use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; -use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; +use rustc::ty::subst; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use std::collections::HashSet; use syntax::ast; -use syntax::parse::token::keywords; use syntax_pos::Span; use errors::DiagnosticBuilder; @@ -461,7 +460,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { variances.types .iter_enumerated() .filter(|&(_, _, &variance)| variance != ty::Bivariant) - .map(|(space, index, _)| self.param_ty(ast_generics, space, index)) + .map(|(_, index, _)| self.param_ty(ast_generics, index)) .map(|p| Parameter::Type(p)) .collect(); @@ -470,52 +469,34 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { &mut constrained_parameters); for (space, index, _) in variances.types.iter_enumerated() { - let param_ty = self.param_ty(ast_generics, space, index); + assert_eq!(space, subst::TypeSpace); + + let param_ty = self.param_ty(ast_generics, index); if constrained_parameters.contains(&Parameter::Type(param_ty)) { continue; } - let span = self.ty_param_span(ast_generics, item, space, index); + let span = ast_generics.ty_params[index].span; self.report_bivariance(span, param_ty.name); } for (space, index, &variance) in variances.regions.iter_enumerated() { + assert_eq!(space, subst::TypeSpace); + if variance != ty::Bivariant { continue; } - assert_eq!(space, TypeSpace); let span = ast_generics.lifetimes[index].lifetime.span; let name = ast_generics.lifetimes[index].lifetime.name; self.report_bivariance(span, name); } } - fn param_ty(&self, - ast_generics: &hir::Generics, - space: ParamSpace, - index: usize) - -> ty::ParamTy - { - let name = match space { - TypeSpace => ast_generics.ty_params[index].name, - SelfSpace => keywords::SelfType.name(), - FnSpace => bug!("Fn space occupied?"), - }; - - ty::ParamTy { space: space, idx: index as u32, name: name } - } - - fn ty_param_span(&self, - ast_generics: &hir::Generics, - item: &hir::Item, - space: ParamSpace, - index: usize) - -> Span - { - match space { - TypeSpace => ast_generics.ty_params[index].span, - SelfSpace => item.span, - FnSpace => span_bug!(item.span, "Fn space occupied?"), + fn param_ty(&self, ast_generics: &hir::Generics, index: usize) -> ty::ParamTy { + ty::ParamTy { + space: subst::TypeSpace, + idx: index as u32, + name: ast_generics.ty_params[index].name } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 485e744bf916e..17a84e98e61e2 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let source = tcx.lookup_item_type(impl_did).ty; let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); - let target = *trait_ref.substs.types.get(subst::TypeSpace, 0); + let target = *trait_ref.substs.types.get(subst::TypeSpace, 1); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 77723ea973341..8eef384f2cf9f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -65,7 +65,7 @@ use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; -use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; +use rustc::ty::subst::{Substs, FnSpace, ParamSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; @@ -85,7 +85,6 @@ use std::rc::Rc; use syntax::{abi, ast, attr}; use syntax::parse::token::keywords; -use syntax::ptr::P; use syntax_pos::Span; use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; @@ -546,7 +545,7 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let path_res = tcx.expect_resolution(ast_ty.id); match path_res.base_def { Def::SelfTy(Some(def_id), None) | - Def::TyParam(_, _, def_id, _) if path_res.depth == 0 => { + Def::TyParam(def_id) if path_res.depth == 0 => { def_id == tcx.map.local_def_id(param_id) } _ => false @@ -1333,7 +1332,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) // add in the explicit where-clauses let mut trait_predicates = - ty_generic_predicates(ccx, TypeSpace, generics, &base_predicates); + ty_generic_predicates(ccx, TypeSpace, generics, &base_predicates, true); let assoc_predicates = predicates_for_associated_types(ccx, generics, @@ -1430,7 +1429,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let parent = ccx.tcx.map.get_parent(param_id); let def = ty::TypeParameterDef { - space: SelfSpace, + space: TypeSpace, index: 0, name: keywords::SelfType.name(), def_id: tcx.map.local_def_id(param_id), @@ -1477,27 +1476,25 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }).collect(); // Now create the real type parameters. - let types = ast_generics.ty_params.iter().enumerate().map(|(i, _)| { - get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32, allow_defaults) + let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { + let i = opt_self.is_some() as u32 + i as u32; + get_or_create_type_parameter_def(ccx, ast_generics, space, i, p, allow_defaults) }).collect(); let has_self = base_generics.has_self || opt_self.is_some(); let (regions, types) = match space { - SelfSpace => bug!(), TypeSpace => { assert_eq!(base_generics.regions.as_full_slice().len(), 0); assert_eq!(base_generics.types.as_full_slice().len(), 0); - (VecPerParamSpace::new(vec![], regions, vec![]), - VecPerParamSpace::new(opt_self.into_iter().collect(), types, vec![])) + (VecPerParamSpace::new(regions, vec![]), + VecPerParamSpace::new(opt_self.into_iter().chain(types).collect(), vec![])) } FnSpace => { assert_eq!(base_generics.regions.len(FnSpace), 0); assert_eq!(base_generics.types.len(FnSpace), 0); - (VecPerParamSpace::new(base_generics.regions.get_slice(SelfSpace).to_vec(), - base_generics.regions.get_slice(TypeSpace).to_vec(), + (VecPerParamSpace::new(base_generics.regions.get_slice(TypeSpace).to_vec(), regions), - VecPerParamSpace::new(base_generics.types.get_slice(SelfSpace).to_vec(), - base_generics.types.get_slice(TypeSpace).to_vec(), + VecPerParamSpace::new(base_generics.types.get_slice(TypeSpace).to_vec(), types)) } }; @@ -1674,7 +1671,7 @@ fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, generics: &hir::Generics) -> ty::GenericPredicates<'tcx> { - ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty()) + ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty(), false) } fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, @@ -1682,7 +1679,7 @@ fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, base_predicates: &ty::GenericPredicates<'tcx>) -> ty::GenericPredicates<'tcx> { - ty_generic_predicates(ccx, FnSpace, generics, base_predicates) + ty_generic_predicates(ccx, FnSpace, generics, base_predicates, false) } // Add the Sized bound, unless the type parameter is marked as `?Sized`. @@ -1752,7 +1749,8 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>( fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: ParamSpace, ast_generics: &hir::Generics, - base_predicates: &ty::GenericPredicates<'tcx>) + base_predicates: &ty::GenericPredicates<'tcx>, + has_self: bool) -> ty::GenericPredicates<'tcx> { let tcx = ccx.tcx; @@ -1761,7 +1759,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). for (index, param) in ast_generics.ty_params.iter().enumerate() { - let index = index as u32; + let index = has_self as u32 + index as u32; let param_ty = ty::ParamTy::new(space, index, param.name).to_ty(ccx.tcx); let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), param_ty, @@ -1850,50 +1848,22 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, result } -fn convert_default_type_parameter<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - path: &P, - space: ParamSpace, - index: u32) - -> Ty<'tcx> -{ - let ty = AstConv::ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &path); - - for leaf_ty in ty.walk() { - if let ty::TyParam(p) = leaf_ty.sty { - if p.space == space && p.idx >= index { - struct_span_err!(ccx.tcx.sess, path.span, E0128, - "type parameters with a default cannot use \ - forward declared identifiers") - .span_label(path.span, &format!("defaulted type parameters \ - cannot be forward declared")) - .emit(); - - return ccx.tcx.types.err - } - } - } - - ty -} - fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ast_generics: &hir::Generics, space: ParamSpace, index: u32, + param: &hir::TyParam, allow_defaults: bool) -> ty::TypeParameterDef<'tcx> { - let param = &ast_generics.ty_params[index as usize]; - let tcx = ccx.tcx; match tcx.ty_param_defs.borrow().get(¶m.id) { Some(d) => { return d.clone(); } None => { } } - let default = param.default.as_ref().map( - |def| convert_default_type_parameter(ccx, def, space, index) - ); + let default = + param.default.as_ref().map(|def| ccx.icx(&()).to_ty(&ExplicitRscope, def)); let object_lifetime_default = compute_object_lifetime_default(ccx, param.id, @@ -1922,6 +1892,10 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, object_lifetime_default: object_lifetime_default, }; + if def.name == keywords::SelfType.name() { + span_bug!(param.span, "`Self` should not be the name of a regular parameter"); + } + tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); debug!("get_or_create_type_parameter_def: def for type param: {:?}, {:?}", @@ -2153,7 +2127,7 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, /// Checks that all the type parameters on an impl fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - ast_generics: &hir::Generics, + generics: &hir::Generics, impl_predicates: &mut ty::GenericPredicates<'tcx>, impl_def_id: DefId) { @@ -2173,12 +2147,11 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_trait_ref, &mut input_parameters); - for (index, ty_param) in ast_generics.ty_params.iter().enumerate() { - let param_ty = ty::ParamTy { space: TypeSpace, - idx: index as u32, - name: ty_param.name }; + let ty_generics = generics_of_def_id(ccx, impl_def_id); + for (ty_param, param) in ty_generics.types.as_full_slice().iter().zip(&generics.ty_params) { + let param_ty = ty::ParamTy::for_def(ty_param); if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { - report_unused_parameter(ccx, ty_param.span, "type", ¶m_ty.to_string()); + report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); } } } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 8c9b4beb79d84..2b88689ff1295 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -361,9 +361,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // All type parameters on enums and structs should be // in the TypeSpace. - assert!(item_type.generics.types.is_empty_in(subst::SelfSpace)); assert!(item_type.generics.types.is_empty_in(subst::FnSpace)); - assert!(item_type.generics.regions.is_empty_in(subst::SelfSpace)); assert!(item_type.generics.regions.is_empty_in(subst::FnSpace)); self.add_constraints_from_substs( @@ -394,14 +392,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyTrait(ref data) => { - let poly_trait_ref = - data.principal.with_self_ty(self.tcx(), self.tcx().types.err); - // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); self.add_constraints_from_region(generics, data.region_bound, contra); - // Ignore the SelfSpace, it is erased. + let poly_trait_ref = + data.principal.with_self_ty(self.tcx(), self.tcx().types.err); self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance); for projection in &data.projection_bounds { diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 22edf219dff75..9048d892b09d2 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -110,8 +110,8 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { while index < num_inferred { let item_id = inferred_infos[index].item_id; - let (mut rs, mut rt, mut rf) = (vec![], vec![], vec![]); - let (mut ts, mut tt, mut tf) = (vec![], vec![], vec![]); + let (mut rt, mut rf) = (vec![], vec![]); + let (mut tt, mut tf) = (vec![], vec![]); while index < num_inferred && inferred_infos[index].item_id == item_id { let info = &inferred_infos[index]; @@ -121,7 +121,6 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { match info.kind { TypeParam => { let types = match info.space { - subst::SelfSpace => &mut ts, subst::TypeSpace => &mut tt, subst::FnSpace => &mut tf }; @@ -130,7 +129,6 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } RegionParam => { let regions = match info.space { - subst::SelfSpace => &mut rs, subst::TypeSpace => &mut rt, subst::FnSpace => &mut rf }; @@ -143,8 +141,8 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } let item_variances = ty::ItemVariances { - regions: subst::VecPerParamSpace::new(rs, rt, rf), - types: subst::VecPerParamSpace::new(ts, tt, tf) + regions: subst::VecPerParamSpace::new(rt, rf), + types: subst::VecPerParamSpace::new(tt, tf) }; debug!("item_id={} item_variances={:?}", diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 72f8d9cb23ba8..9dc38bb195c14 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -21,7 +21,7 @@ use arena::TypedArena; use dep_graph::DepTrackingMapConfig; -use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace}; +use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace}; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::ItemVariances; use std::fmt; @@ -164,16 +164,16 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { let inferreds_on_entry = self.num_inferred(); - if has_self { - self.add_inferred(item_id, TypeParam, SelfSpace, 0, item_id); - } - for (i, p) in generics.lifetimes.iter().enumerate() { let id = p.lifetime.id; self.add_inferred(item_id, RegionParam, TypeSpace, i, id); } + if has_self { + self.add_inferred(item_id, TypeParam, TypeSpace, 0, item_id); + } for (i, p) in generics.ty_params.iter().enumerate() { + let i = has_self as usize + i; self.add_inferred(item_id, TypeParam, TypeSpace, i, p.id); } @@ -233,7 +233,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { -> ty::Variance { match space { - SelfSpace | FnSpace => { + FnSpace => { ty::Bivariant } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f8a3a0af69752..6fae7ddc24a89 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; -use rustc::ty::subst::{self, ParamSpace, Substs, VecPerParamSpace}; +use rustc::ty::subst::{self, Substs, VecPerParamSpace}; use rustc::ty; use rustc::middle::stability; @@ -630,13 +630,14 @@ impl Clean for hir::TyParamBound { } } -fn external_path_params(cx: &DocContext, trait_did: Option, +fn external_path_params(cx: &DocContext, trait_did: Option, has_self: bool, bindings: Vec, substs: &Substs) -> PathParameters { let lifetimes = substs.regions.get_slice(subst::TypeSpace) .iter() .filter_map(|v| v.clean(cx)) .collect(); - let types = substs.types.get_slice(subst::TypeSpace).to_vec(); + let types = substs.types.get_slice(subst::TypeSpace); + let types = types[has_self as usize..].to_vec(); match (trait_did, cx.tcx_opt()) { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C @@ -675,13 +676,13 @@ fn external_path_params(cx: &DocContext, trait_did: Option, // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C -fn external_path(cx: &DocContext, name: &str, trait_did: Option, +fn external_path(cx: &DocContext, name: &str, trait_did: Option, has_self: bool, bindings: Vec, substs: &Substs) -> Path { Path { global: false, segments: vec![PathSegment { name: name.to_string(), - params: external_path_params(cx, trait_did, bindings, substs) + params: external_path_params(cx, trait_did, has_self, bindings, substs) }], } } @@ -696,16 +697,16 @@ impl Clean for ty::BuiltinBound { let (did, path) = match *self { ty::BoundSend => (tcx.lang_items.send_trait().unwrap(), - external_path(cx, "Send", None, vec![], empty)), + external_path(cx, "Send", None, false, vec![], empty)), ty::BoundSized => (tcx.lang_items.sized_trait().unwrap(), - external_path(cx, "Sized", None, vec![], empty)), + external_path(cx, "Sized", None, false, vec![], empty)), ty::BoundCopy => (tcx.lang_items.copy_trait().unwrap(), - external_path(cx, "Copy", None, vec![], empty)), + external_path(cx, "Copy", None, false, vec![], empty)), ty::BoundSync => (tcx.lang_items.sync_trait().unwrap(), - external_path(cx, "Sync", None, vec![], empty)), + external_path(cx, "Sync", None, false, vec![], empty)), }; inline::record_extern_fqn(cx, did, TypeTrait); TraitBound(PolyTrait { @@ -728,14 +729,14 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { }; inline::record_extern_fqn(cx, self.def_id, TypeTrait); let path = external_path(cx, &tcx.item_name(self.def_id).as_str(), - Some(self.def_id), vec![], self.substs); + Some(self.def_id), true, vec![], self.substs); debug!("ty::TraitRef\n substs.types(TypeSpace): {:?}\n", - self.substs.types.get_slice(ParamSpace::TypeSpace)); + &self.input_types()[1..]); // collect any late bound regions let mut late_bounds = vec![]; - for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) { + for &ty_s in &self.input_types()[1..] { if let ty::TyTuple(ts) = ty_s.sty { for &ty_s in ts { if let ty::TyRef(ref reg, _) = ty_s.sty { @@ -982,8 +983,13 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. - let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| { - tp.clean(cx) + let stripped_typarams = gens.types.get_slice(space).iter().filter_map(|tp| { + if tp.name == keywords::SelfType.name() { + assert_eq!(tp.index, 0); + None + } else { + Some(tp.clean(cx)) + } }).collect::>(); let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| { let mut srp = rp.clone(); @@ -1820,7 +1826,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, &cx.tcx().item_name(did).as_str(), - None, vec![], substs); + None, false, vec![], substs); ResolvedPath { path: path, typarams: None, @@ -1847,7 +1853,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } let path = external_path(cx, &cx.tcx().item_name(did).as_str(), - Some(did), bindings, obj.principal.0.substs); + Some(did), false, bindings, obj.principal.0.substs); ResolvedPath { path: path, typarams: Some(typarams), diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index b6d5e5458ff08..2591d7bcbaef4 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: overflow representing the type `S` +// error-pattern: overflow representing the type -#![feature(rustc_attrs)] trait Mirror { type It: ?Sized; } impl Mirror for T { type It = Self; } struct S(Option<::It>); -#[rustc_no_mir] // FIXME #27840 MIR tries to represent `std::option::Option` first. fn main() { let _s = S(None); } diff --git a/src/test/compile-fail/issue-26812.rs b/src/test/compile-fail/issue-26812.rs index 060a66846d36f..1dd008810788b 100644 --- a/src/test/compile-fail/issue-26812.rs +++ b/src/test/compile-fail/issue-26812.rs @@ -10,5 +10,7 @@ #![feature(default_type_parameter_fallback)] -fn avg(_: T) {} //~ ERROR associated type `Item` not found for `T` +fn avg(_: T) {} +//~^ ERROR type parameters with a default cannot use forward declared identifiers + fn main() {} diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index a3456b0628b35..9aa4d29c4ecf7 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -20,12 +20,12 @@ trait Trait<'a> { } #[rustc_variance] -struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[];[+];[]], regions=[[];[-];[]]) +struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[+];[]], regions=[[-];[]]) field: (T, &'a ()) } #[rustc_variance] -struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[];[o];[]], regions=[[];[o];[]]) +struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[o];[]], regions=[[o];[]]) field: >::Type } diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index ffd829c38d3d3..3c8b27f965a61 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -18,7 +18,7 @@ use std::cell::Cell; // For better or worse, associated types are invariant, and hence we // get an invariant result for `'a`. #[rustc_variance] -struct Foo<'a> { //~ ERROR regions=[[];[o];[]] +struct Foo<'a> { //~ ERROR regions=[[o];[]] x: Box &'a i32 + 'static> } diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs index 6dd791f2558a7..ae5a8674f446c 100644 --- a/src/test/compile-fail/variance-region-bounds.rs +++ b/src/test/compile-fail/variance-region-bounds.rs @@ -13,11 +13,11 @@ #![feature(rustc_attrs)] #[rustc_variance] -trait Foo: 'static { //~ ERROR types=[[o];[];[]] +trait Foo: 'static { //~ ERROR types=[[o];[]] } #[rustc_variance] -trait Bar { //~ ERROR types=[[o];[o];[]] +trait Bar { //~ ERROR types=[[o, o];[]] fn do_it(&self) where T: 'static; } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 0c712d3fa0377..93d3d2773149e 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -16,7 +16,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[];[-, -, -];[]] +struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[]] x: &'a isize, y: &'b [isize], c: &'c str @@ -25,7 +25,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[];[-, -, -];[]] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[];[+, +, +];[]] +struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[]] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), c: extern "Rust" fn(&'c str), @@ -34,7 +34,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[];[+, +, +];[]] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR regions=[[];[-, o];[]] +struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[]] x: &'a mut &'b isize, } @@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[];[-, o];[]] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b:'a> { //~ ERROR regions=[[];[+, o];[]] +struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[]] x: extern "Rust" fn(&'a mut &'b isize), } @@ -52,14 +52,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[[];[+, o];[]] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b:'a> { //~ ERROR regions=[[];[-, o];[]] +struct Test6<'a, 'b:'a> { //~ ERROR regions=[[-, o];[]] x: &'a mut extern "Rust" fn(&'b isize), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR regions=[[];[*];[]] +struct Test7<'a> { //~ ERROR regions=[[*];[]] //~^ ERROR parameter `'a` is never used x: isize } @@ -67,7 +67,7 @@ struct Test7<'a> { //~ ERROR regions=[[];[*];[]] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[];[+, -, o];[]] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[]] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index 9bdb05e188dcf..eeb981b707e31 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -15,7 +15,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[];[+, -, o, *];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[]] //~^ ERROR parameter `'d` is never used Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), @@ -23,25 +23,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[];[+, -, o, *];[]] } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[];[*, o, -, +];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[]] //~^ ERROR parameter `'w` is never used f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[];[o, o, *];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[]] //~^ ERROR parameter `'c` is never used f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[];[o, -, *];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[]] //~^ ERROR parameter `'c` is never used f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[];[+, -, o];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[]] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 528be50c0b850..860dd6deefd5b 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -15,48 +15,48 @@ // influence variance. #[rustc_variance] -trait Getter { //~ ERROR types=[[o];[o];[]] +trait Getter { //~ ERROR types=[[o, o];[]] fn get(&self) -> T; } #[rustc_variance] -trait Setter { //~ ERROR types=[[o];[o];[]] +trait Setter { //~ ERROR types=[[o, o];[]] fn get(&self, T); } #[rustc_variance] -struct TestStruct> { //~ ERROR types=[[];[+, +];[]] +struct TestStruct> { //~ ERROR types=[[+, +];[]] t: T, u: U } #[rustc_variance] -enum TestEnum> {//~ ERROR types=[[];[*, +];[]] +enum TestEnum> {//~ ERROR types=[[*, +];[]] //~^ ERROR parameter `U` is never used Foo(T) } #[rustc_variance] -trait TestTrait> { //~ ERROR types=[[o];[o, o];[]] +trait TestTrait> { //~ ERROR types=[[o, o, o];[]] fn getter(&self, u: U) -> T; } #[rustc_variance] -trait TestTrait2 : Getter { //~ ERROR types=[[o];[o];[]] +trait TestTrait2 : Getter { //~ ERROR types=[[o, o];[]] } #[rustc_variance] -trait TestTrait3 { //~ ERROR types=[[o];[o];[]] +trait TestTrait3 { //~ ERROR types=[[o, o];[]] fn getter>(&self); } #[rustc_variance] -struct TestContraStruct> { //~ ERROR types=[[];[*, +];[]] +struct TestContraStruct> { //~ ERROR types=[[*, +];[]] //~^ ERROR parameter `U` is never used t: T } #[rustc_variance] -struct TestBox+Setter> { //~ ERROR types=[[];[*, +];[]] +struct TestBox+Setter> { //~ ERROR types=[[*, +];[]] //~^ ERROR parameter `U` is never used t: T } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index b58540204986a..b37007a6d34e4 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -21,7 +21,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[[];[-];[]] +struct TOption<'a> { //~ ERROR regions=[[-];[]] v: Option>, } diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index d110c402d3b77..8eb96814fa8f0 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -14,46 +14,46 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct TestImm { //~ ERROR types=[[];[+, +];[]] +struct TestImm { //~ ERROR types=[[+, +];[]] x: A, y: B, } #[rustc_variance] -struct TestMut { //~ ERROR types=[[];[+, o];[]] +struct TestMut { //~ ERROR types=[[+, o];[]] x: A, y: &'static mut B, } #[rustc_variance] -struct TestIndirect { //~ ERROR types=[[];[+, o];[]] +struct TestIndirect { //~ ERROR types=[[+, o];[]] m: TestMut } #[rustc_variance] -struct TestIndirect2 { //~ ERROR types=[[];[o, o];[]] +struct TestIndirect2 { //~ ERROR types=[[o, o];[]] n: TestMut, m: TestMut } #[rustc_variance] -trait Getter { //~ ERROR types=[[o];[o];[]] +trait Getter { //~ ERROR types=[[o, o];[]] fn get(&self) -> A; } #[rustc_variance] -trait Setter { //~ ERROR types=[[o];[o];[]] +trait Setter { //~ ERROR types=[[o, o];[]] fn set(&mut self, a: A); } #[rustc_variance] -trait GetterSetter { //~ ERROR types=[[o];[o];[]] +trait GetterSetter { //~ ERROR types=[[o, o];[]] fn get(&self) -> A; fn set(&mut self, a: A); } #[rustc_variance] -trait GetterInTypeBound { //~ ERROR types=[[o];[o];[]] +trait GetterInTypeBound { //~ ERROR types=[[o, o];[]] // Here, the use of `A` in the method bound *does* affect // variance. Think of it as if the method requested a dictionary // for `T:Getter`. Since this dictionary is an input, it is @@ -63,12 +63,12 @@ trait GetterInTypeBound { //~ ERROR types=[[o];[o];[]] } #[rustc_variance] -trait SetterInTypeBound { //~ ERROR types=[[o];[o];[]] +trait SetterInTypeBound { //~ ERROR types=[[o, o];[]] fn do_it>(&self); } #[rustc_variance] -struct TestObject { //~ ERROR types=[[];[o, o];[]] +struct TestObject { //~ ERROR types=[[o, o];[]] n: Box+Send>, m: Box+Send>, } diff --git a/src/test/compile-fail/variance-types.rs b/src/test/compile-fail/variance-types.rs index 8c1a544334c2a..791b56caea02b 100644 --- a/src/test/compile-fail/variance-types.rs +++ b/src/test/compile-fail/variance-types.rs @@ -17,32 +17,32 @@ use std::cell::Cell; // not considered bivariant. #[rustc_variance] -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[[];[o, o];[]], regions=[[];[-];[]] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[[o, o];[]], regions=[[-];[]] t: &'a mut (A,B) } #[rustc_variance] -struct InvariantCell { //~ ERROR types=[[];[o];[]] +struct InvariantCell { //~ ERROR types=[[o];[]] t: Cell } #[rustc_variance] -struct InvariantIndirect { //~ ERROR types=[[];[o];[]] +struct InvariantIndirect { //~ ERROR types=[[o];[]] t: InvariantCell } #[rustc_variance] -struct Covariant { //~ ERROR types=[[];[+];[]] +struct Covariant { //~ ERROR types=[[+];[]] t: A, u: fn() -> A } #[rustc_variance] -struct Contravariant { //~ ERROR types=[[];[-];[]] +struct Contravariant { //~ ERROR types=[[-];[]] t: fn(A) } #[rustc_variance] -enum Enum { //~ ERROR types=[[];[+, -, o];[]] +enum Enum { //~ ERROR types=[[+, -, o];[]] Foo(Covariant), Bar(Contravariant), Zed(Covariant,Contravariant) From 3e74e5bffe14ead921646d41bab436f8e6a69d33 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 10 Aug 2016 20:39:09 +0300 Subject: [PATCH 069/768] rustc: split Generics of a method from its parent Generics. --- src/librustc/infer/error_reporting.rs | 3 +- src/librustc/traits/error_reporting.rs | 12 +- src/librustc/traits/object_safety.rs | 3 +- src/librustc/ty/mod.rs | 29 +---- src/librustc/ty/structural_impls.rs | 14 --- src/librustc/ty/subst.rs | 71 +++++++----- src/librustc/util/ppaux.rs | 10 +- src/librustc_metadata/encoder.rs | 6 +- src/librustc_metadata/tydecode.rs | 24 +++- src/librustc_metadata/tyencode.rs | 19 +++- src/librustc_trans/base.rs | 4 +- src/librustc_trans/collector.rs | 15 ++- src/librustc_trans/debuginfo/mod.rs | 17 ++- src/librustc_typeck/astconv.rs | 5 +- src/librustc_typeck/check/compare_method.rs | 10 +- src/librustc_typeck/check/intrinsic.rs | 4 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 8 +- src/librustc_typeck/check/method/probe.rs | 21 ++-- src/librustc_typeck/check/mod.rs | 116 +++++++++++--------- src/librustc_typeck/check/wfcheck.rs | 6 +- src/librustc_typeck/collect.rs | 94 ++++++++-------- src/librustc_typeck/variance/constraints.rs | 26 ++--- src/librustdoc/clean/inline.rs | 21 ++-- src/librustdoc/clean/mod.rs | 14 +-- 25 files changed, 290 insertions(+), 264 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 21fccd2c6132d..9a6375719c1bc 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -82,7 +82,6 @@ use hir::def::Def; use hir::def_id::DefId; use infer::{self, TypeOrigin}; use middle::region; -use ty::subst; use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; @@ -1369,7 +1368,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { let generics = self.tcx.lookup_generics(did); let expected = - generics.regions.len(subst::TypeSpace) as u32; + generics.regions.len() as u32; let lifetimes = path.segments.last().unwrap().parameters.lifetimes(); let mut insert = Vec::new(); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 77c1137c6c3be..77d7d5115efbc 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -271,14 +271,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let def = self.tcx.lookup_trait_def(trait_ref.def_id); let trait_str = def.trait_ref.to_string(); if let Some(ref istring) = item.value_str() { - let mut generic_map = def.generics.types.iter_enumerated() - .map(|(param, i, gen)| { - (gen.name.as_str().to_string(), - trait_ref.substs.types.get(param, i) - .to_string()) - }).collect::>(); - generic_map.insert("Self".to_string(), - trait_ref.self_ty().to_string()); + let generic_map = def.generics.types.iter().map(|param| { + (param.name.as_str().to_string(), + trait_ref.substs.type_for_def(param).to_string()) + }).collect::>(); let parser = Parser::new(&istring); let mut errored = false; let err: String = parser.filter_map(|p| { diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 11cf759859c62..25d2df8fdedb3 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -20,7 +20,6 @@ use super::elaborate_predicates; use hir::def_id::DefId; -use ty::subst; use traits; use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use std::rc::Rc; @@ -266,7 +265,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !method.generics.types.is_empty_in(subst::FnSpace) { + if !method.generics.types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 96537904d36e8..689f2ad02c94c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -757,33 +757,14 @@ impl RegionParameterDef { /// with an item or method. Analogous to hir::Generics. #[derive(Clone, Debug)] pub struct Generics<'tcx> { - pub types: VecPerParamSpace>, - pub regions: VecPerParamSpace, + pub parent: Option, + pub parent_regions: u32, + pub parent_types: u32, + pub regions: Vec, + pub types: Vec>, pub has_self: bool, } -impl<'tcx> Generics<'tcx> { - pub fn empty() -> Generics<'tcx> { - Generics { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), - has_self: false, - } - } - - pub fn is_empty(&self) -> bool { - self.types.is_empty() && self.regions.is_empty() - } - - pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { - !self.types.is_empty_in(space) - } - - pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { - !self.regions.is_empty_in(space) - } -} - /// Bounds on generics. #[derive(Clone)] pub struct GenericPredicates<'tcx> { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9021b0587a013..248d5d9062d59 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -832,20 +832,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef { } } -impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::Generics { - types: self.types.fold_with(folder), - regions: self.regions.fold_with(folder), - has_self: self.has_self - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.types.visit_with(visitor) || self.regions.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::GenericPredicates { diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 2f95baa562589..594d15ad5f734 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -89,42 +89,55 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { let defs = tcx.lookup_generics(def_id); + let num_regions = defs.parent_regions as usize + defs.regions.len(); + let num_types = defs.parent_types as usize + defs.types.len(); let mut substs = Substs { - types: VecPerParamSpace { + regions: VecPerParamSpace { type_limit: 0, - content: Vec::with_capacity(defs.types.content.len()) + content: Vec::with_capacity(num_regions) }, - regions: VecPerParamSpace { + types: VecPerParamSpace { type_limit: 0, - content: Vec::with_capacity(defs.regions.content.len()) + content: Vec::with_capacity(num_types) } }; - for &space in &ParamSpace::all() { - for def in defs.regions.get_slice(space) { - assert_eq!(def.space, space); - - let region = mk_region(def, &substs); - substs.regions.content.push(region); + substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type); - if space == TypeSpace { - substs.regions.type_limit += 1; - } - } + Substs::new(tcx, substs.types, substs.regions) + } - for def in defs.types.get_slice(space) { - assert_eq!(def.space, space); + fn fill_item(&mut self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + defs: &ty::Generics<'tcx>, + mk_region: &mut FR, + mk_type: &mut FT) + where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { + if let Some(def_id) = defs.parent { + let parent_defs = tcx.lookup_generics(def_id); + self.fill_item(tcx, parent_defs, mk_region, mk_type); + } - let ty = mk_type(def, &substs); - substs.types.content.push(ty); + for def in &defs.regions { + let region = mk_region(def, self); + self.regions.content.push(region); - if space == TypeSpace { - substs.types.type_limit += 1; - } + if def.space == TypeSpace { + self.regions.type_limit += 1; + assert_eq!(self.regions.content.len(), self.regions.type_limit); } } - Substs::new(tcx, substs.types, substs.regions) + for def in &defs.types { + let ty = mk_type(def, self); + self.types.content.push(ty); + + if def.space == TypeSpace { + self.types.type_limit += 1; + assert_eq!(self.types.content.len(), self.types.type_limit); + } + } } pub fn is_noop(&self) -> bool { @@ -149,16 +162,14 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { let defs = tcx.lookup_generics(source_ancestor); - assert_eq!(self.types.len(TypeSpace), defs.types.len(TypeSpace)); + assert_eq!(self.types.len(TypeSpace), defs.types.len()); assert_eq!(target_substs.types.len(FnSpace), 0); - assert_eq!(defs.types.len(FnSpace), 0); - assert_eq!(self.regions.len(TypeSpace), defs.regions.len(TypeSpace)); + assert_eq!(self.regions.len(TypeSpace), defs.regions.len()); assert_eq!(target_substs.regions.len(FnSpace), 0); - assert_eq!(defs.regions.len(FnSpace), 0); let Substs { mut types, mut regions } = target_substs.clone(); - types.content.extend(&self.types.as_full_slice()[defs.types.content.len()..]); - regions.content.extend(&self.regions.as_full_slice()[defs.regions.content.len()..]); + types.content.extend(&self.types.as_full_slice()[defs.types.len()..]); + regions.content.extend(&self.regions.as_full_slice()[defs.regions.len()..]); Substs::new(tcx, types, regions) } } @@ -597,8 +608,8 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { -> ty::TraitRef<'tcx> { let Substs { mut types, mut regions } = substs.clone(); let defs = tcx.lookup_generics(trait_id); - types.content.truncate(defs.types.type_limit); - regions.content.truncate(defs.regions.type_limit); + types.content.truncate(defs.types.len()); + regions.content.truncate(defs.regions.len()); ty::TraitRef { def_id: trait_id, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 800ad865208aa..a62ee37613e50 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -73,13 +73,15 @@ pub fn parameterized(f: &mut fmt::Formatter, let mut has_self = false; let (fn_trait_kind, item_name) = ty::tls::with(|tcx| { verbose = tcx.sess.verbose(); - let generics = tcx.lookup_generics(did); + let mut generics = tcx.lookup_generics(did); + if let Some(def_id) = generics.parent { + generics = tcx.lookup_generics(def_id); + } if !verbose { - let ty_params = generics.types.get_slice(subst::TypeSpace); - if ty_params.last().map_or(false, |def| def.default.is_some()) { + if generics.types.last().map_or(false, |def| def.default.is_some()) { if let Some(substs) = tcx.lift(&substs) { let tps = substs.types.get_slice(subst::TypeSpace); - for (def, actual) in ty_params.iter().zip(tps).rev() { + for (def, actual) in generics.types.iter().zip(tps).rev() { if def.default.subst(tcx, substs) != Some(actual) { break; } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1e74b3c1ef48f..0cde9b48d6f88 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -620,9 +620,9 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, if let Some(impl_item) = impl_item_opt { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { encode_attributes(rbml_w, &impl_item.attrs); - let scheme = ecx.tcx.lookup_item_type(m.def_id); - let any_types = !scheme.generics.types.is_empty(); - let needs_inline = any_types || is_default_impl || + let generics = ecx.tcx.lookup_generics(m.def_id); + let types = generics.parent_types as usize + generics.types.len(); + let needs_inline = types > 0 || is_default_impl || attr::requests_inline(&impl_item.attrs); if needs_inline || sig.constness == hir::Constness::Const { encode_inlined_item(ecx, diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 82d050a1de9d7..e8e3679a60ca2 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -149,9 +149,29 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> { - let regions = self.parse_vec_per_param_space(|this| this.parse_region_param_def()); - let types = self.parse_vec_per_param_space(|this| this.parse_type_param_def()); + let parent = self.parse_opt(|this| this.parse_def()); + let parent_regions = self.parse_u32(); + assert_eq!(self.next(), '|'); + let parent_types = self.parse_u32(); + + let mut regions = vec![]; + assert_eq!(self.next(), '['); + while self.peek() != ']' { + regions.push(self.parse_region_param_def()); + } + assert_eq!(self.next(), ']'); + + let mut types = vec![]; + assert_eq!(self.next(), '['); + while self.peek() != ']' { + types.push(self.parse_type_param_def()); + } + assert_eq!(self.next(), ']'); + self.tcx.alloc_generics(ty::Generics { + parent: parent, + parent_regions: parent_regions, + parent_types: parent_types, regions: regions, types: types, has_self: self.next() == 'S' diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 130d15485829a..27907596ca788 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -274,10 +274,21 @@ pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, generics: &ty::Generics<'tcx>) { - enc_vec_per_param_space(w, cx, &generics.regions, - |w, cx, r| enc_region_param_def(w, cx, r)); - enc_vec_per_param_space(w, cx, &generics.types, - |w, cx, ty| enc_type_param_def(w, cx, ty)); + enc_opt(w, generics.parent, |w, def_id| { + write!(w, "{}|", (cx.ds)(cx.tcx, def_id)); + }); + write!(w, "{}|{}[", + generics.parent_regions, + generics.parent_types); + + for r in &generics.regions { + enc_region_param_def(w, cx, r) + } + write!(w, "]["); + for t in &generics.types { + enc_type_param_def(w, cx, t); + } + write!(w, "]"); if generics.has_self { write!(w, "S"); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ee5d1d11fa0a6..f190fbeb6feb9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2470,8 +2470,8 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { hir_map::NodeImplItem(&hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.map.local_def_id(id); - let scheme = tcx.lookup_item_type(def_id); - scheme.generics.types.is_empty() + let generics = tcx.lookup_generics(def_id); + generics.parent_types == 0 && generics.types.is_empty() } _ => false diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 82c86928783bc..76910304eebb0 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -195,7 +195,7 @@ use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem}; use rustc::traits; -use rustc::ty::subst::{self, Substs, Subst}; +use rustc::ty::subst::{Substs, Subst}; use rustc::ty::{self, TypeFoldable, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::repr as mir; @@ -1219,17 +1219,16 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id_to_string(tcx, impl_def_id)); if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { - let default_impls = tcx.provided_trait_methods(trait_ref.def_id); let callee_substs = tcx.erase_regions(&trait_ref.substs); let overridden_methods: FnvHashSet<_> = items.iter() .map(|item| item.name) .collect(); - for default_impl in default_impls { - if overridden_methods.contains(&default_impl.name) { + for method in tcx.provided_trait_methods(trait_ref.def_id) { + if overridden_methods.contains(&method.name) { continue; } - if default_impl.generics.has_type_params(subst::FnSpace) { + if !method.generics.types.is_empty() { continue; } @@ -1242,7 +1241,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callee_substs, impl_def_id, impl_substs, - default_impl.name); + method.name); assert!(mth.is_provided); @@ -1251,10 +1250,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, continue; } - if can_have_local_instance(tcx, default_impl.def_id) { + if can_have_local_instance(tcx, method.def_id) { let empty_substs = tcx.erase_regions(&mth.substs); let item = create_fn_trans_item(tcx, - default_impl.def_id, + method.def_id, callee_substs, empty_substs); output.push(item); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 963cc09e1ab95..684628e9a40fb 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -381,10 +381,11 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { - generics.types.as_full_slice().iter().enumerate().map(|(i, param)| { - let actual_type = cx.tcx().normalize_associated_type(&actual_types[i]); + let names = get_type_parameter_names(cx, generics); + actual_types.iter().zip(names).map(|(ty, name)| { + let actual_type = cx.tcx().normalize_associated_type(ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(param.name.as_str().as_bytes()).unwrap(); + let name = CString::new(name.as_str().as_bytes()).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), @@ -403,6 +404,16 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return create_DIArray(DIB(cx), &template_params[..]); } + fn get_type_parameter_names<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, + generics: &ty::Generics<'tcx>) + -> Vec { + let mut names = generics.parent.map_or(vec![], |def_id| { + get_type_parameter_names(cx, cx.tcx().lookup_generics(def_id)) + }); + names.extend(generics.types.iter().map(|param| param.name)); + names + } + fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>, instance: Instance<'tcx>) -> (DIScope, Span) { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 109cfd2abf6e5..a452b55a7d33d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -429,7 +429,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { bug!("ErrorReported returned, but no errors reports?") } }; - let expected_num_region_params = decl_generics.regions.len(TypeSpace); + let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); let regions = if expected_num_region_params == supplied_num_region_params { lifetimes.iter().map(|l| ast_region_to_region(tcx, l)).collect() @@ -454,8 +454,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Check the number of type parameters supplied by the user. if let Some(num_provided) = num_types_provided { - let ty_param_defs = decl_generics.types.get_slice(TypeSpace); - let ty_param_defs = &ty_param_defs[self_ty.is_some() as usize..]; + let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..]; check_type_argument_count(tcx, span, num_provided, ty_param_defs); } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 3cb528eba63e0..5bfe58e78f112 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -13,7 +13,7 @@ use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, Reveal}; use rustc::ty::error::ExpectedFound; -use rustc::ty::subst::{self, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::hir::map::Node; use rustc::hir::{ImplItemKind, TraitItem_}; @@ -95,8 +95,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } - let num_impl_m_type_params = impl_m.generics.types.len(subst::FnSpace); - let num_trait_m_type_params = trait_m.generics.types.len(subst::FnSpace); + let num_impl_m_type_params = impl_m.generics.types.len(); + let num_trait_m_type_params = trait_m.generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { span_err!(tcx.sess, impl_m_span, E0049, "method `{}` has {} type parameter{} \ @@ -389,8 +389,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> bool { - let trait_params = trait_generics.regions.get_slice(subst::FnSpace); - let impl_params = impl_generics.regions.get_slice(subst::FnSpace); + let trait_params = &trait_generics.regions[..]; + let impl_params = &impl_generics.regions[..]; debug!("check_region_bounds_on_impl_method: \ trait_generics={:?} \ diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index bfedb4fa6e1a0..b2af51c12e6bb 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -49,7 +49,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, variadic: false, }), })); - let i_n_tps = i_ty.generics.types.len(subst::FnSpace); + let i_n_tps = i_ty.generics.types.len(); if i_n_tps != n_tps { struct_span_err!(tcx.sess, it.span, E0094, "intrinsic has wrong number of type \ @@ -321,7 +321,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, let tcx = ccx.tcx; let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); - let i_n_tps = i_ty.generics.types.len(subst::FnSpace); + let i_n_tps = i_ty.generics.types.len(); let name = it.name.as_str(); let (n_tps, inputs, output) = match &*name { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c071fce98965f..8aa4ad56aea88 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -308,7 +308,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // variables. let num_supplied_types = supplied_method_types.len(); let method = pick.item.as_opt_method().unwrap(); - let num_method_types = method.generics.types.len(subst::FnSpace); + let num_method_types = method.generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { if num_method_types == 0 { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index a9e08461fd28e..b057ad3150b51 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -183,15 +183,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let trait_def = self.tcx.lookup_trait_def(trait_def_id); if let Some(ref input_types) = opt_input_types { - assert_eq!(trait_def.generics.types.len(subst::TypeSpace) - 1, input_types.len()); + assert_eq!(trait_def.generics.types.len() - 1, input_types.len()); } - assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0); assert!(trait_def.generics.regions.is_empty()); // Construct a trait-reference `self_ty : Trait` let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { + assert_eq!(def.space, subst::TypeSpace); if def.index == 0 { self_ty } else if let Some(ref input_types) = opt_input_types { @@ -221,8 +221,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let method_item = self.trait_item(trait_def_id, m_name).unwrap(); let method_ty = method_item.as_opt_method().unwrap(); - assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); - assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); + assert_eq!(method_ty.generics.types.len(), 0); + assert_eq!(method_ty.generics.regions.len(), 0); debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", method_item, method_ty); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 044de179917b4..c52bb36911a2a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -518,9 +518,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_ref, trait_ref.substs, m); - assert_eq!(m.generics.types.len(subst::TypeSpace), + assert_eq!(m.generics.parent_types as usize, trait_ref.substs.types.len(subst::TypeSpace)); - assert_eq!(m.generics.regions.len(subst::TypeSpace), + assert_eq!(m.generics.parent_regions as usize, trait_ref.substs.regions.len(subst::TypeSpace)); } @@ -1232,8 +1232,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let xform_self_ty = method.fty.sig.input(0); let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty); - if method.generics.types.is_empty_in(subst::FnSpace) && - method.generics.regions.is_empty_in(subst::FnSpace) { + if method.generics.types.is_empty() && method.generics.regions.is_empty() { xform_self_ty.subst(self.tcx, substs) } else { let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { @@ -1260,17 +1259,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) { - let impl_pty = self.tcx.lookup_item_type(impl_def_id); + let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty; - let type_vars = - impl_pty.generics.types.map( - |_| self.next_ty_var()); + let substs = Substs::for_item(self.tcx, impl_def_id, + |_, _| ty::ReErased, + |_, _| self.next_ty_var()); - let region_placeholders = - impl_pty.generics.regions.map( - |_| ty::ReErased); // see erase_late_bound_regions() for an expl of why 'erased - - (impl_pty.ty, Substs::new(self.tcx, type_vars, region_placeholders)) + (impl_ty, substs) } /// Replace late-bound-regions bound by `value` with `'static` using diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae3378f41f936..d699bafed9a05 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -881,8 +881,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // `{Self}` is allowed Position::ArgumentNamed(s) if s == "Self" => (), // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => match types.as_full_slice() - .iter().find(|t| { + Position::ArgumentNamed(s) => match types.iter().find(|t| { t.name.as_str() == s }) { Some(_) => (), @@ -1693,7 +1692,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut ty = self.tcx.lookup_item_type(did).ty; if ty.is_fn() { // Tuple variants have fn type even in type namespace, extract true variant type from it - ty = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap(); + ty = self.tcx.no_late_bound_regions(&ty.fn_ret()).unwrap(); } let type_predicates = self.tcx.lookup_predicates(did); let substs = AstConv::ast_path_substs_for_ty(self, self, @@ -3222,13 +3221,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); return None; } - Def::Variant(..) | Def::Struct(..) => { - Some(self.tcx.expect_variant_def(def)) + Def::Variant(type_did, _) | Def::Struct(type_did) => { + Some((type_did, self.tcx.expect_variant_def(def))) } - Def::TyAlias(did) | Def::AssociatedTy(_, did) => { + Def::TyAlias(did) => { if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did) .map(|scheme| &scheme.ty.sty) { - Some(adt.struct_variant()) + Some((did, adt.struct_variant())) } else { None } @@ -3236,14 +3235,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => None }; - if let Some(variant) = variant { + if let Some((def_id, variant)) = variant { if variant.kind == ty::VariantKind::Tuple && !self.tcx.sess.features.borrow().relaxed_adts { emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic, "relaxed_adts", span, GateIssue::Language, "tuple structs and variants in struct patterns are unstable"); } - let ty = self.instantiate_type_path(def.def_id(), path, node_id); + let ty = self.instantiate_type_path(def_id, path, node_id); Some((variant, ty)) } else { struct_span_err!(self.tcx.sess, path.span, E0071, @@ -4122,25 +4121,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut fn_segment = None; match def { // Case 1 and 1b. Reference to a *type* or *enum variant*. - Def::SelfTy(..) | - Def::Struct(..) | - Def::Variant(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::Trait(..) | - Def::PrimTy(..) | - Def::TyParam(..) => { + Def::Struct(def_id) | + Def::Variant(_, def_id) | + Def::Enum(def_id) | + Def::TyAlias(def_id) | + Def::AssociatedTy(_, def_id) | + Def::Trait(def_id) => { // Everything but the final segment should have no // parameters at all. - type_segment = segments.last(); + let mut generics = self.tcx.lookup_generics(def_id); + if let Some(def_id) = generics.parent { + // Variant and struct constructors use the + // generics of their parent type definition. + generics = self.tcx.lookup_generics(def_id); + } + type_segment = Some((segments.last().unwrap(), generics)); } // Case 2. Reference to a top-level value. - Def::Fn(..) | - Def::Const(..) | - Def::Static(..) => { - fn_segment = segments.last(); + Def::Fn(def_id) | + Def::Const(def_id) | + Def::Static(def_id, _) => { + fn_segment = Some((segments.last().unwrap(), + self.tcx.lookup_generics(def_id))); } // Case 3. Reference to a method or associated const. @@ -4154,14 +4157,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::ImplContainer(_) => {} } + let generics = self.tcx.lookup_generics(def_id); if segments.len() >= 2 { - type_segment = Some(&segments[segments.len() - 2]); + let parent_generics = self.tcx.lookup_generics(generics.parent.unwrap()); + type_segment = Some((&segments[segments.len() - 2], parent_generics)); } else { // `::assoc` will end up here, and so can `T::assoc`. let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self"); ufcs_associated = Some((container, self_ty)); } - fn_segment = segments.last(); + fn_segment = Some((segments.last().unwrap(), generics)); } // Other cases. Various nonsense that really shouldn't show up @@ -4169,6 +4174,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // elsewhere. (I hope) Def::Mod(..) | Def::ForeignMod(..) | + Def::PrimTy(..) | + Def::SelfTy(..) | + Def::TyParam(..) | Def::Local(..) | Def::Label(..) | Def::Upvar(..) | @@ -4213,12 +4221,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // a problem. self.check_path_parameter_count(subst::TypeSpace, span, - scheme.generics, !require_type_space, &mut type_segment); self.check_path_parameter_count(subst::FnSpace, span, - scheme.generics, true, &mut fn_segment); @@ -4228,7 +4234,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { subst::TypeSpace => type_segment, subst::FnSpace => fn_segment }; - let lifetimes = match segment.map(|s| &s.parameters) { + let lifetimes = match segment.map(|(s, _)| &s.parameters) { Some(&hir::AngleBracketedParameters(ref data)) => &data.lifetimes[..], Some(&hir::ParenthesizedParameters(_)) => bug!(), None => &[] @@ -4242,25 +4248,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, |def, substs| { let mut i = def.index as usize; let segment = match def.space { - subst::TypeSpace => type_segment, + subst::TypeSpace => { + // Handle Self first, so we can adjust the index to match the AST. + match (type_segment, fn_segment) { + (Some((_, generics)), _) | (_, Some((_, generics))) => { + if generics.has_self { + if i == 0 { + return opt_self_ty.unwrap_or_else(|| { + self.type_var_for_def(span, def, substs) + }); + } + i -= 1; + } + } + _ => {} + } + type_segment + } subst::FnSpace => fn_segment }; - let types = match segment.map(|s| &s.parameters) { + let types = match segment.map(|(s, _)| &s.parameters) { Some(&hir::AngleBracketedParameters(ref data)) => &data.types[..], Some(&hir::ParenthesizedParameters(_)) => bug!(), None => &[] }; - // Handle Self first, so we can adjust the index to match the AST. - if scheme.generics.has_self && def.space == subst::TypeSpace { - if i == 0 { - return opt_self_ty.unwrap_or_else(|| { - self.type_var_for_def(span, def, substs) - }); - } - i -= 1; - } - let can_omit = def.space != subst::TypeSpace || !require_type_space; let default = if can_omit && types.len() == 0 { def.default @@ -4306,9 +4318,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // with the substituted impl type. let impl_scheme = self.tcx.lookup_item_type(impl_def_id); assert_eq!(substs.types.len(subst::TypeSpace), - impl_scheme.generics.types.len(subst::TypeSpace)); + impl_scheme.generics.types.len()); assert_eq!(substs.regions.len(subst::TypeSpace), - impl_scheme.generics.regions.len(subst::TypeSpace)); + impl_scheme.generics.regions.len()); let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { @@ -4339,10 +4351,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_path_parameter_count(&self, space: subst::ParamSpace, span: Span, - generics: &ty::Generics<'tcx>, can_omit: bool, - segment: &mut Option<&hir::PathSegment>) { - let (lifetimes, types, bindings) = match segment.map(|s| &s.parameters) { + segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) { + let (lifetimes, types, bindings) = match segment.map(|(s, _)| &s.parameters) { Some(&hir::AngleBracketedParameters(ref data)) => { (&data.lifetimes[..], &data.types[..], &data.bindings[..]) } @@ -4357,7 +4368,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Check provided lifetime parameters. - let lifetime_defs = generics.regions.get_slice(space); + let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions); if lifetimes.len() > lifetime_defs.len() { let span = lifetimes[lifetime_defs.len()].span; span_err!(self.tcx.sess, span, E0088, @@ -4374,12 +4385,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Check provided type parameters. - let type_defs = generics.types.get_slice(space); - let type_defs = if space == subst::TypeSpace { - &type_defs[generics.has_self as usize..] - } else { - type_defs - }; + let type_defs = segment.map_or(&[][..], |(_, generics)| { + if space == subst::TypeSpace { + &generics.types[generics.has_self as usize..] + } else { + &generics.types + } + }); let required_len = type_defs.iter() .take_while(|d| d.default.is_none()) .count(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index f2076895f0873..f793ce7acb7c7 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -523,10 +523,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) { - let impl_params = generics.types.get_slice(subst::TypeSpace).iter() - .map(|tp| tp.name).collect::>(); + let parent = tcx.lookup_generics(generics.parent.unwrap()); + let impl_params: HashSet<_> = parent.types.iter().map(|tp| tp.name).collect(); - for method_param in generics.types.get_slice(subst::FnSpace) { + for method_param in &generics.types { if impl_params.contains(&method_param.name) { error_194(tcx, span, method_param.name); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8eef384f2cf9f..9e8fe710cc1cd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -65,7 +65,7 @@ use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; -use rustc::ty::subst::{Substs, FnSpace, ParamSpace, TypeSpace, VecPerParamSpace}; +use rustc::ty::subst::{Substs, FnSpace, ParamSpace, TypeSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; @@ -793,9 +793,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node { + let const_def_id = ccx.tcx.map.local_def_id(impl_item.id); + let ty_generics = generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&ty_predicates) .to_ty(&ExplicitRscope, &ty); - tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id), + tcx.register_item_type(const_def_id, TypeScheme { generics: ty_generics, ty: ty, @@ -858,11 +860,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated constants. for trait_item in trait_items { if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node { + let const_def_id = ccx.tcx.map.local_def_id(trait_item.id); + let ty_generics = generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&trait_predicates) .to_ty(&ExplicitRscope, ty); - tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id), + tcx.register_item_type(const_def_id, TypeScheme { - generics: trait_def.generics, + generics: ty_generics, ty: ty, }); convert_associated_const(ccx, @@ -957,7 +961,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, predicates: ty::GenericPredicates<'tcx>) { let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(ctor_id); - tcx.generics.borrow_mut().insert(def_id, scheme.generics); + generics_of_def_id(ccx, def_id); let ctor_ty = match variant.kind { VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { @@ -1389,24 +1393,35 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, use rustc::hir::map::*; use rustc::hir::*; + let node = tcx.map.get(node_id); + let parent_def_id = match node { + NodeImplItem(_) | + NodeTraitItem(_) | + NodeVariant(_) | + NodeStructCtor(_) => { + let parent_id = tcx.map.get_parent(node_id); + Some(tcx.map.local_def_id(parent_id)) + } + _ => None + }; + let mut opt_self = None; - let mut base_def_id = None; let mut allow_defaults = false; let no_generics = hir::Generics::empty(); - let (space, ast_generics) = match tcx.map.get(node_id) { - NodeImplItem(&ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) | - NodeTraitItem(&TraitItem { node: MethodTraitItem(ref sig, _), .. }) => { - let parent_id = tcx.map.get_parent(node_id); - base_def_id = Some(tcx.map.local_def_id(parent_id)); - (FnSpace, &sig.generics) + let (space, ast_generics) = match node { + NodeTraitItem(item) => { + match item.node { + MethodTraitItem(ref sig, _) => (FnSpace, &sig.generics), + _ => (FnSpace, &no_generics) + } } - NodeImplItem(_) | - NodeTraitItem(_) => { - let parent_id = tcx.map.get_parent(node_id); - base_def_id = Some(tcx.map.local_def_id(parent_id)); - (FnSpace, &no_generics) + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => (FnSpace, &sig.generics), + _ => (FnSpace, &no_generics) + } } NodeItem(item) => { @@ -1457,9 +1472,16 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => (TypeSpace, &no_generics) }; - let empty_generics = ty::Generics::empty(); - let base_generics = base_def_id.map_or(&empty_generics, |def_id| { - generics_of_def_id(ccx, def_id) + let has_self = opt_self.is_some(); + let mut parent_has_self = false; + let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| { + let generics = generics_of_def_id(ccx, def_id); + assert_eq!(generics.parent, None); + assert_eq!(generics.parent_regions, 0); + assert_eq!(generics.parent_types, 0); + assert_eq!(has_self, false); + parent_has_self = generics.has_self; + (generics.regions.len(), generics.types.len()) }); let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); @@ -1477,32 +1499,15 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Now create the real type parameters. let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { - let i = opt_self.is_some() as u32 + i as u32; + let i = has_self as u32 + i as u32; get_or_create_type_parameter_def(ccx, ast_generics, space, i, p, allow_defaults) - }).collect(); - - let has_self = base_generics.has_self || opt_self.is_some(); - let (regions, types) = match space { - TypeSpace => { - assert_eq!(base_generics.regions.as_full_slice().len(), 0); - assert_eq!(base_generics.types.as_full_slice().len(), 0); - (VecPerParamSpace::new(regions, vec![]), - VecPerParamSpace::new(opt_self.into_iter().chain(types).collect(), vec![])) - } - FnSpace => { - assert_eq!(base_generics.regions.len(FnSpace), 0); - assert_eq!(base_generics.types.len(FnSpace), 0); - (VecPerParamSpace::new(base_generics.regions.get_slice(TypeSpace).to_vec(), - regions), - VecPerParamSpace::new(base_generics.types.get_slice(TypeSpace).to_vec(), - types)) - } - }; + }); + let types: Vec<_> = opt_self.into_iter().chain(types).collect(); // Debugging aid. if tcx.has_attr(def_id, "rustc_object_lifetime_default") { let object_lifetime_default_reprs: String = - types.as_full_slice().iter().map(|t| { + types.iter().map(|t| { match t.object_lifetime_default { ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), d => format!("{:?}", d), @@ -1512,9 +1517,12 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } tcx.alloc_generics(ty::Generics { + parent: parent_def_id, + parent_regions: parent_regions as u32, + parent_types: parent_types as u32, regions: regions, types: types, - has_self: has_self + has_self: has_self || parent_has_self }) }) } @@ -2148,7 +2156,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &mut input_parameters); let ty_generics = generics_of_def_id(ccx, impl_def_id); - for (ty_param, param) in ty_generics.types.as_full_slice().iter().zip(&generics.ty_params) { + for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) { let param_ty = ty::ParamTy::for_def(ty_param); if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 2b88689ff1295..95ddb59c0e28a 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -301,8 +301,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, trait_ref.def_id, - trait_def.generics.types.as_full_slice(), - trait_def.generics.regions.as_full_slice(), + &trait_def.generics.types, + &trait_def.generics.regions, trait_ref.substs, variance); } @@ -359,16 +359,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(ItemVariances::to_dep_node(&def.did)); - // All type parameters on enums and structs should be - // in the TypeSpace. - assert!(item_type.generics.types.is_empty_in(subst::FnSpace)); - assert!(item_type.generics.regions.is_empty_in(subst::FnSpace)); - self.add_constraints_from_substs( generics, def.did, - item_type.generics.types.as_full_slice(), - item_type.generics.regions.as_full_slice(), + &item_type.generics.types, + &item_type.generics.regions, substs, variance); } @@ -385,8 +380,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, trait_ref.def_id, - trait_def.generics.types.as_full_slice(), - trait_def.generics.regions.as_full_slice(), + &trait_def.generics.types, + &trait_def.generics.regions, trait_ref.substs, variance); } @@ -406,7 +401,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyParam(ref data) => { - let def_id = generics.types.get(data.space, data.idx as usize).def_id; + assert_eq!(data.space, subst::TypeSpace); + assert_eq!(generics.parent, None); + let def_id = generics.types[data.idx as usize].def_id; let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); match self.terms_cx.inferred_map.get(&node_id) { Some(&index) => { @@ -493,8 +490,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance: VarianceTermPtr<'a>) { match region { ty::ReEarlyBound(ref data) => { - let def_id = - generics.regions.get(data.space, data.index as usize).def_id; + assert_eq!(data.space, subst::TypeSpace); + assert_eq!(generics.parent, None); + let def_id = generics.regions[data.index as usize].def_id; let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); if self.is_to_be_inferred(node_id) { let index = self.inferred_index(node_id); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b4be201440ccf..427468069d04e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -21,7 +21,6 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; use rustc::ty::{self, TyCtxt}; -use rustc::ty::subst; use rustc_const_eval::lookup_const_by_id; @@ -161,7 +160,7 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc let def = tcx.lookup_trait_def(did); let trait_items = tcx.trait_items(did).clean(cx); let predicates = tcx.lookup_predicates(did); - let generics = (def.generics, &predicates, subst::TypeSpace).clean(cx); + let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); clean::Trait { @@ -189,7 +188,7 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx let predicates = tcx.lookup_predicates(did); clean::Function { decl: decl, - generics: (t.generics, &predicates, subst::FnSpace).clean(cx), + generics: (t.generics, &predicates).clean(cx), unsafety: style, constness: constness, abi: abi, @@ -209,7 +208,7 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, _ => doctree::Plain, }, - generics: (t.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (t.generics, &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } @@ -222,7 +221,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, match t.ty.sty { ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => { return clean::EnumItem(clean::Enum { - generics: (t.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (t.generics, &predicates).clean(cx), variants_stripped: false, variants: edef.variants.clean(cx), }) @@ -232,7 +231,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, clean::TypedefItem(clean::Typedef { type_: t.ty.clean(cx), - generics: (t.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (t.generics, &predicates).clean(cx), }, false) } @@ -393,9 +392,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, // because an associated type won't have generics on the LHS let typedef = clean::Typedef { type_: assoc_ty.ty.unwrap().clean(cx), - generics: (&ty::Generics::empty(), - &ty::GenericPredicates::empty(), - subst::TypeSpace).clean(cx) + generics: clean::Generics { + lifetimes: vec![], + type_params: vec![], + where_predicates: vec![] + } }; Some(clean::Item { name: Some(assoc_ty.name.clean(cx)), @@ -434,7 +435,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, provided_trait_methods: provided, trait_: trait_, for_: for_, - generics: (ty.generics, &predicates, subst::TypeSpace).clean(cx), + generics: (ty.generics, &predicates).clean(cx), items: trait_items, polarity: polarity.map(|p| { p.clean(cx) }), }), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6fae7ddc24a89..07821a730ccf6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -973,17 +973,16 @@ impl Clean for hir::Generics { } impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, - &'a ty::GenericPredicates<'tcx>, - subst::ParamSpace) { + &'a ty::GenericPredicates<'tcx>) { fn clean(&self, cx: &DocContext) -> Generics { use self::WherePredicate as WP; - let (gens, preds, space) = *self; + let (gens, preds) = *self; // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. - let stripped_typarams = gens.types.get_slice(space).iter().filter_map(|tp| { + let stripped_typarams = gens.types.iter().filter_map(|tp| { if tp.name == keywords::SelfType.name() { assert_eq!(tp.index, 0); None @@ -991,7 +990,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, Some(tp.clean(cx)) } }).collect::>(); - let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| { + let stripped_lifetimes = gens.regions.iter().map(|rp| { let mut srp = rp.clone(); srp.bounds = Vec::new(); srp.clean(cx) @@ -1359,8 +1358,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { predicates: self.predicates.predicates[method_start..].to_vec() }; - let generics = (self.generics, &method_predicates, - subst::FnSpace).clean(cx); + let generics = (self.generics, &method_predicates).clean(cx); let mut decl = (self.def_id, &self.fty.sig).clean(cx); match self.explicit_self { ty::ExplicitSelfCategory::ByValue => { @@ -2929,7 +2927,7 @@ impl<'tcx> Clean for ty::AssociatedType<'tcx> { // applied to this associated type in question. let def = cx.tcx().lookup_trait_def(did); let predicates = cx.tcx().lookup_predicates(did); - let generics = (def.generics, &predicates, subst::TypeSpace).clean(cx); + let generics = (def.generics, &predicates).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { WherePredicate::BoundPredicate { From 6f5e455c2de007a12ed632f84b986369ae43a504 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 11 Aug 2016 09:19:42 +0300 Subject: [PATCH 070/768] rustc: split GenericPredicates of a method from its parent predicates. --- src/librustc/traits/select.rs | 26 ++- src/librustc/ty/mod.rs | 25 ++- src/librustc/ty/structural_impls.rs | 12 -- src/librustc_metadata/decoder.rs | 1 + src/librustc_metadata/encoder.rs | 3 + src/librustc_typeck/astconv.rs | 1 + src/librustc_typeck/check/compare_method.rs | 30 ++-- src/librustc_typeck/check/dropck.rs | 1 + src/librustc_typeck/check/mod.rs | 12 +- src/librustc_typeck/check/regionck.rs | 1 + src/librustc_typeck/check/wfcheck.rs | 1 + src/librustc_typeck/collect.rs | 158 +++++++++--------- src/librustdoc/clean/mod.rs | 12 +- .../associated-const-type-parameter-arrays.rs | 3 +- 14 files changed, 136 insertions(+), 150 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9099d6cd740d1..bf6aad98db1a8 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2897,20 +2897,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx - .lookup_predicates(def_id) - .predicates.iter() - .flat_map(|predicate| { - let predicate = - normalize_with_depth(self, cause.clone(), recursion_depth, - &predicate.subst(tcx, substs)); - predicate.obligations.into_iter().chain( - Some(Obligation { - cause: cause.clone(), - recursion_depth: recursion_depth, - predicate: predicate.value - })) - }).collect(); + let predicates = tcx.lookup_predicates(def_id); + assert_eq!(predicates.parent, None); + let predicates = predicates.predicates.iter().flat_map(|predicate| { + let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, + &predicate.subst(tcx, substs)); + predicate.obligations.into_iter().chain( + Some(Obligation { + cause: cause.clone(), + recursion_depth: recursion_depth, + predicate: predicate.value + })) + }).collect(); self.infcx().plug_leaks(skol_map, snapshot, &predicates) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 689f2ad02c94c..b2b8286be2fba 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -768,27 +768,38 @@ pub struct Generics<'tcx> { /// Bounds on generics. #[derive(Clone)] pub struct GenericPredicates<'tcx> { + pub parent: Option, pub predicates: Vec>, } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { - pub fn empty() -> GenericPredicates<'tcx> { - GenericPredicates { - predicates: vec![] - } - } - pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { + let mut instantiated = InstantiatedPredicates::empty(); + self.instantiate_into(tcx, &mut instantiated, substs); + instantiated + } + pub fn instantiate_own(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) + -> InstantiatedPredicates<'tcx> { InstantiatedPredicates { - predicates: self.predicates.subst(tcx, substs), + predicates: self.predicates.subst(tcx, substs) + } + } + + fn instantiate_into(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + instantiated: &mut InstantiatedPredicates<'tcx>, + substs: &Substs<'tcx>) { + if let Some(def_id) = self.parent { + tcx.lookup_predicates(def_id).instantiate_into(tcx, instantiated, substs); } + instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) } pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, poly_trait_ref: &ty::PolyTraitRef<'tcx>) -> InstantiatedPredicates<'tcx> { + assert_eq!(self.parent, None); InstantiatedPredicates { predicates: self.predicates.iter().map(|pred| { pred.subst_supertrait(tcx, poly_trait_ref) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 248d5d9062d59..021ae820b87c5 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -832,18 +832,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef { } } -impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::GenericPredicates { - predicates: self.predicates.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.predicates.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e42825ef1e549..5488f114db32f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1591,6 +1591,7 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, let doc = reader::get_doc(base_doc, tag); ty::GenericPredicates { + parent: item_parent_item(cdata, doc), predicates: reader::tagged_docs(doc, tag_predicate).map(|predicate_doc| { doc_predicate(cdata, predicate_doc, tcx) }).collect() diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0cde9b48d6f88..320ba3c8d9dc8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -525,6 +525,9 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, tag: usize) { rbml_w.start_tag(tag); + if let Some(def_id) = predicates.parent { + rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); + } for predicate in &predicates.predicates { rbml_w.wr_tagged_u32(tag_predicate, index.add_xref(XRef::Predicate(predicate.clone()))); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a452b55a7d33d..aec8f8245da5e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1726,6 +1726,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let predicates = bounds.predicates(tcx, ty); let predicates = tcx.lift_to_global(&predicates).unwrap(); tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates { + parent: None, predicates: predicates }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 5bfe58e78f112..4cbb2d7f09f02 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -211,29 +211,18 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return; } - // Depend on trait/impl predicates always being before method's own predicates, - // to be able to split method predicates into "inherited" and method-specific. - let trait_predicates = tcx.lookup_predicates(trait_m.container_id()).predicates; - let impl_predicates = tcx.lookup_predicates(impl_m.container_id()).predicates; - let trait_method_start = trait_predicates.len(); - let impl_method_start = impl_predicates.len(); - assert_eq!(&trait_predicates[..], &trait_m.predicates.predicates[..trait_method_start]); - assert_eq!(&impl_predicates[..], &impl_m.predicates.predicates[..impl_method_start]); - tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| { let mut fulfillment_cx = traits::FulfillmentContext::new(); - // Normalize the associated types in the trait_bounds. - let trait_bounds = trait_m.predicates.instantiate(tcx, trait_to_skol_substs); - // Create obligations for each predicate declared by the impl // definition in the context of the trait's parameter // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_bounds = impl_m.predicates.instantiate(tcx, impl_to_skol_substs); + let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); - debug!("compare_impl_method: impl_bounds={:?}", impl_bounds); + debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); // This is the only tricky bit of the new way we check implementation methods // We need to build a set of predicates where only the FnSpace bounds @@ -242,14 +231,14 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // // We then register the obligations from the impl_m and check to see // if all constraints hold. - let hybrid_preds = impl_bounds.predicates[..impl_method_start].iter() - .chain(trait_bounds.predicates[trait_method_start..].iter()); + hybrid_preds.predicates.extend( + trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); // Construct trait parameter environment and then shift it into the skolemized viewpoint. // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); - let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.cloned().collect()); + let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates); let trait_param_env = traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone()); @@ -261,12 +250,13 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut selcx = traits::SelectionContext::new(&infcx); - let (impl_pred_fns, _) = + let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs); + let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var( impl_m_span, infer::HigherRankedType, - &ty::Binder(impl_bounds.predicates[impl_method_start..].to_vec())); - for predicate in impl_pred_fns { + &ty::Binder(impl_m_own_bounds.predicates)); + for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, .. } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 7d79fc4fbf878..d1da95f39df40 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -184,6 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // 'a:'b and T:'b into region inference constraints. It is simpler // just to look for all the predicates directly. + assert_eq!(dtor_predicates.parent, None); for predicate in &dtor_predicates.predicates { // (We do not need to worry about deep analysis of type // expressions etc because the Drop impls are already forced diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d699bafed9a05..8c4ec8453177e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1612,8 +1612,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bounds: &ty::GenericPredicates<'tcx>) -> ty::InstantiatedPredicates<'tcx> { + let result = bounds.instantiate(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &result.predicates); + debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", + bounds, + substs, + result); ty::InstantiatedPredicates { - predicates: self.instantiate_type_scheme(span, substs, &bounds.predicates) + predicates: result } } @@ -4210,8 +4216,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => {} } - let scheme = self.tcx.lookup_item_type(def.def_id()); - let type_predicates = self.tcx.lookup_predicates(def.def_id()); // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user @@ -4296,6 +4300,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. + let scheme = self.tcx.lookup_item_type(def.def_id()); + let type_predicates = self.tcx.lookup_predicates(def.def_id()); assert!(!substs.has_escaping_regions()); assert!(!scheme.ty.has_escaping_regions()); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 8e34b0b8c5559..f6ffbc60c2836 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1754,6 +1754,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // // we can thus deduce that `>::SomeType : 'a`. let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id); + assert_eq!(trait_predicates.parent, None); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(self.tcx, predicates) .filter_map(|predicate| { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index f793ce7acb7c7..ef5e1a26f4150 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -454,6 +454,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let item_def_id = self.tcx().map.local_def_id(item.id); let ty_predicates = self.tcx().lookup_predicates(item_def_id); + assert_eq!(ty_predicates.parent, None); let variances = self.tcx().item_variances(item_def_id); let mut constrained_parameters: HashSet<_> = diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 9e8fe710cc1cd..939f8ac50a6c6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -459,35 +459,38 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for () { impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { fn get_type_parameter_bounds(&self, astconv: &AstConv<'tcx, 'tcx>, - _span: Span, + span: Span, node_id: ast::NodeId) -> Vec> { let def = astconv.tcx().type_parameter_def(node_id); - self.predicates - .iter() - .filter(|predicate| { - match **predicate { - ty::Predicate::Trait(ref data) => { - data.skip_binder().self_ty().is_param(def.space, def.index) - } - ty::Predicate::TypeOutlives(ref data) => { - data.skip_binder().0.is_param(def.space, def.index) - } - ty::Predicate::Rfc1592(..) | - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::Projection(..) => { - false - } + let mut results = self.parent.map_or(vec![], |def_id| { + let parent = astconv.tcx().lookup_predicates(def_id); + parent.get_type_parameter_bounds(astconv, span, node_id) + }); + + results.extend(self.predicates.iter().filter(|predicate| { + match **predicate { + ty::Predicate::Trait(ref data) => { + data.skip_binder().self_ty().is_param(def.space, def.index) + } + ty::Predicate::TypeOutlives(ref data) => { + data.skip_binder().0.is_param(def.space, def.index) } - }) - .cloned() - .collect() + ty::Predicate::Rfc1592(..) | + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::Projection(..) => { + false + } + } + }).cloned()); + + results } } @@ -568,7 +571,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generics = generics_of_def_id(ccx, def_id); let ty_generic_predicates = - ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates); + ty_generic_predicates(ccx, FnSpace, &sig.generics, ty_generics.parent, vec![], false); let (fty, explicit_self_category) = { let anon_scope = match container { @@ -634,8 +637,12 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty: ty::Ty<'tcx>, has_value: bool) { + let predicates = ty::GenericPredicates { + parent: Some(container.id()), + predicates: vec![] + }; ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - ty::GenericPredicates::empty()); + predicates); write_ty_to_tcx(ccx, id, ty); @@ -744,7 +751,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); let ty_generics = generics_of_def_id(ccx, def_id); - let mut ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics); + let mut ty_predicates = + ty_generic_predicates(ccx, TypeSpace, generics, None, vec![], false); debug!("convert: impl_bounds={:?}", ty_predicates); @@ -1187,6 +1195,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, // generic types: let trait_def = trait_def_of_item(ccx, item); let self_predicate = ty::GenericPredicates { + parent: None, predicates: vec![trait_def.trait_ref.to_predicate()] }; let scope = &(generics, &self_predicate); @@ -1209,6 +1218,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, // Combine the two lists to form the complete set of superbounds: let superbounds = superbounds1.into_iter().chain(superbounds2).collect(); let superpredicates = ty::GenericPredicates { + parent: None, predicates: superbounds }; debug!("superpredicates for trait {:?} = {:?}", @@ -1327,16 +1337,16 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) // but to get the full set of predicates on a trait we need to add // in the supertrait bounds and anything declared on the // associated types. - let mut base_predicates = super_predicates; + let mut base_predicates = super_predicates.predicates; // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. let self_predicate = trait_def.trait_ref.to_poly_trait_ref().to_predicate(); - base_predicates.predicates.push(self_predicate); + base_predicates.push(self_predicate); // add in the explicit where-clauses let mut trait_predicates = - ty_generic_predicates(ccx, TypeSpace, generics, &base_predicates, true); + ty_generic_predicates(ccx, TypeSpace, generics, None, base_predicates, true); let assoc_predicates = predicates_for_associated_types(ccx, generics, @@ -1619,32 +1629,17 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> ty::GenericPredicates<'tcx> { let def_id = ccx.tcx.map.local_def_id(it.id); - let predicates = match it.node { - hir::ItemStatic(..) | hir::ItemConst(..) => { - ty::GenericPredicates::empty() - } - hir::ItemFn(_, _, _, _, ref ast_generics, _) => { - ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty()) - } + + let no_generics = hir::Generics::empty(); + let (space, generics) = match it.node { + hir::ItemFn(_, _, _, _, ref generics, _) => (FnSpace, generics), hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => { - ty_generic_predicates_for_type_or_impl(ccx, generics) - } - hir::ItemDefaultImpl(..) | - hir::ItemTrait(..) | - hir::ItemExternCrate(..) | - hir::ItemUse(..) | - hir::ItemImpl(..) | - hir::ItemMod(..) | - hir::ItemForeignMod(..) => { - span_bug!( - it.span, - "predicates_of_item: unexpected item type: {:?}", - it.node); - } + hir::ItemStruct(_, ref generics) => (TypeSpace, generics), + _ => (TypeSpace, &no_generics) }; + let predicates = ty_generic_predicates(ccx, space, generics, None, vec![], false); let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, predicates.clone()); assert!(prev_predicates.is_none()); @@ -1662,34 +1657,17 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let def_id = ccx.tcx.map.local_def_id(it.id); type_scheme_of_def_id(ccx, def_id); - let predicates = match it.node { - hir::ForeignItemFn(_, ref generics) => { - ty_generic_predicates_for_fn(ccx, generics, &ty::GenericPredicates::empty()) - } - hir::ForeignItemStatic(..) => { - ty::GenericPredicates::empty() - } + let no_generics = hir::Generics::empty(); + let (space, generics) = match it.node { + hir::ForeignItemFn(_, ref generics) => (FnSpace, generics), + hir::ForeignItemStatic(..) => (TypeSpace, &no_generics) }; + let predicates = ty_generic_predicates(ccx, space, generics, None, vec![], false); let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); assert!(prev_predicates.is_none()); } -fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &hir::Generics) - -> ty::GenericPredicates<'tcx> -{ - ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty(), false) -} - -fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &hir::Generics, - base_predicates: &ty::GenericPredicates<'tcx>) - -> ty::GenericPredicates<'tcx> -{ - ty_generic_predicates(ccx, FnSpace, generics, base_predicates, false) -} - // Add the Sized bound, unless the type parameter is marked as `?Sized`. fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, bounds: &mut ty::BuiltinBounds, @@ -1757,12 +1735,25 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>( fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: ParamSpace, ast_generics: &hir::Generics, - base_predicates: &ty::GenericPredicates<'tcx>, + parent: Option, + super_predicates: Vec>, has_self: bool) -> ty::GenericPredicates<'tcx> { let tcx = ccx.tcx; - let mut result = base_predicates.clone(); + let ref base_predicates = match parent { + Some(def_id) => { + assert_eq!(super_predicates, vec![]); + tcx.lookup_predicates(def_id) + } + None => { + ty::GenericPredicates { + parent: None, + predicates: super_predicates.clone() + } + } + }; + let mut predicates = super_predicates; // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). @@ -1775,7 +1766,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, SizedByDefault::Yes, None, param.span); - result.predicates.extend(bounds.predicates(ccx.tcx, param_ty)); + predicates.extend(bounds.predicates(ccx.tcx, param_ty)); } // Collect the region predicates that were declared inline as @@ -1793,7 +1784,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for bound in ¶m.bounds { let bound_region = ast_region_to_region(ccx.tcx, bound); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); - result.predicates.push(outlives.to_predicate()); + predicates.push(outlives.to_predicate()); } } @@ -1819,17 +1810,17 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ty, &mut projections); - result.predicates.push(trait_ref.to_predicate()); + predicates.push(trait_ref.to_predicate()); for projection in &projections { - result.predicates.push(projection.to_predicate()); + predicates.push(projection.to_predicate()); } } &hir::TyParamBound::RegionTyParamBound(ref lifetime) => { let region = ast_region_to_region(tcx, lifetime); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); - result.predicates.push(ty::Predicate::TypeOutlives(pred)) + predicates.push(ty::Predicate::TypeOutlives(pred)) } } } @@ -1840,7 +1831,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for bound in ®ion_pred.bounds { let r2 = ast_region_to_region(tcx, bound); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); - result.predicates.push(ty::Predicate::RegionOutlives(pred)) + predicates.push(ty::Predicate::RegionOutlives(pred)) } } @@ -1853,7 +1844,10 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - result + ty::GenericPredicates { + parent: parent, + predicates: predicates + } } fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 07821a730ccf6..90288b17dfcce 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1348,17 +1348,7 @@ impl Clean for hir::ImplItem { impl<'tcx> Clean for ty::Method<'tcx> { fn clean(&self, cx: &DocContext) -> Item { - // Depend on trait/impl predicates always being before method's own predicates, - // to be able to split method predicates into "inherited" and method-specific. - let outer_predicates = cx.tcx().lookup_predicates(self.container_id()).predicates; - let method_start = outer_predicates.len(); - assert_eq!(&outer_predicates[..], &self.predicates.predicates[..method_start]); - - let method_predicates = ty::GenericPredicates { - predicates: self.predicates.predicates[method_start..].to_vec() - }; - - let generics = (self.generics, &method_predicates).clean(cx); + let generics = (self.generics, &self.predicates).clean(cx); let mut decl = (self.def_id, &self.fty.sig).clean(cx); match self.explicit_self { ty::ExplicitSelfCategory::ByValue => { diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs index 3d3b795b2291a..ddf16a2278e5b 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs @@ -25,7 +25,8 @@ impl Foo for Def { } pub fn test() { - let _array: [u32; ::Y]; //~ error: the parameter type + let _array: [u32; ::Y]; + //~^ ERROR the trait bound `A: Foo` is not satisfied } fn main() { From 9453d9b8ada9f6b651b10b3ad8131732fc70c61e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 06:32:00 +0300 Subject: [PATCH 071/768] rustc: remove ParamSpace from Substs. --- src/librustc/middle/dead.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 60 ++-- src/librustc/traits/error_reporting.rs | 6 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/select.rs | 17 +- src/librustc/traits/specialize/mod.rs | 9 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/flags.rs | 4 +- src/librustc/ty/mod.rs | 32 +- src/librustc/ty/relate.rs | 49 +-- src/librustc/ty/structural_impls.rs | 14 +- src/librustc/ty/sty.rs | 36 +-- src/librustc/ty/subst.rs | 297 ++---------------- src/librustc/ty/util.rs | 5 +- src/librustc/ty/walk.rs | 8 +- src/librustc/ty/wf.rs | 1 - src/librustc/util/ppaux.rs | 80 ++--- .../borrowck/mir/elaborate_drops.rs | 2 +- src/librustc_driver/test.rs | 21 +- src/librustc_metadata/tydecode.rs | 53 +--- src/librustc_metadata/tyencode.rs | 51 ++- src/librustc_mir/build/scope.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/intrinsic.rs | 56 ++-- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/partitioning.rs | 3 +- src/librustc_trans/trans_item.rs | 6 +- src/librustc_trans/type_of.rs | 10 +- src/librustc_typeck/astconv.rs | 11 +- src/librustc_typeck/check/closure.rs | 3 +- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/intrinsic.rs | 6 +- src/librustc_typeck/check/method/confirm.rs | 12 +- src/librustc_typeck/check/method/mod.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 18 +- src/librustc_typeck/check/mod.rs | 88 +++--- src/librustc_typeck/check/regionck.rs | 10 +- src/librustc_typeck/check/wfcheck.rs | 18 +- src/librustc_typeck/check/writeback.rs | 3 +- src/librustc_typeck/coherence/mod.rs | 4 +- src/librustc_typeck/collect.rs | 96 +++--- src/librustc_typeck/variance/constraints.rs | 19 +- src/librustc_typeck/variance/solve.rs | 29 +- src/librustc_typeck/variance/terms.rs | 30 +- src/librustdoc/clean/inline.rs | 2 - src/librustdoc/clean/mod.rs | 24 +- .../compile-fail/variance-associated-types.rs | 4 +- .../compile-fail/variance-object-types.rs | 2 +- .../compile-fail/variance-region-bounds.rs | 4 +- .../compile-fail/variance-regions-direct.rs | 14 +- .../compile-fail/variance-regions-indirect.rs | 10 +- .../compile-fail/variance-trait-bounds.rs | 18 +- .../variance-trait-object-bound.rs | 2 +- .../compile-fail/variance-types-bounds.rs | 20 +- src/test/compile-fail/variance-types.rs | 12 +- src/test/mir-opt/storage_ranges.rs | 4 +- 60 files changed, 462 insertions(+), 857 deletions(-) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 20e281816b8b0..2a8594c59a837 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -18,7 +18,7 @@ use hir::{self, pat_util, PatKind}; use hir::intravisit::{self, Visitor}; use middle::privacy; -use ty::{self, subst, TyCtxt}; +use ty::{self, TyCtxt}; use hir::def::Def; use hir::def_id::{DefId}; use lint; @@ -95,7 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { - match substs.substs.types.get(subst::TypeSpace, 0).sty { + match substs.substs.types[0].sty { TyEnum(tyid, _) | TyStruct(tyid, _) => { self.check_def_id(tyid.did) } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 9ccca9e6a08f9..8369a6c39d54d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -24,9 +24,7 @@ use session::Session; use hir::def::{Def, DefMap}; use hir::def_id::DefId; use middle::region; -use ty::subst; use ty; -use std::fmt; use std::mem::replace; use syntax::ast; use syntax::parse::token::keywords; @@ -41,8 +39,7 @@ use hir::intravisit::{self, Visitor, FnKind}; #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum DefRegion { DefStaticRegion, - DefEarlyBoundRegion(/* space */ subst::ParamSpace, - /* index */ u32, + DefEarlyBoundRegion(/* index */ u32, /* lifetime decl */ ast::NodeId), DefLateBoundRegion(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId), @@ -90,10 +87,11 @@ struct LifetimeContext<'a, 'tcx: 'a> { labels_in_fn: Vec<(ast::Name, Span)>, } +#[derive(PartialEq, Debug)] enum ScopeChain<'a> { - /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound - /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. - EarlyScope(subst::ParamSpace, &'a [hir::LifetimeDef], Scope<'a>), + /// EarlyScope(['a, 'b, ...], s) extends s with early-bound + /// lifetimes. + EarlyScope(&'a [hir::LifetimeDef], Scope<'a>), /// LateScope(['a, 'b, ...], s) extends s with late-bound /// lifetimes introduced by the declaration binder_id. LateScope(&'a [hir::LifetimeDef], Scope<'a>), @@ -159,8 +157,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { hir::ItemImpl(_, _, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; - let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE); - this.with(early_scope, |old_scope, this| { + this.with(EarlyScope(lifetimes, &ROOT_SCOPE), |old_scope, this| { this.check_lifetime_defs(old_scope, lifetimes); intravisit::walk_item(this, item); }); @@ -181,11 +178,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { self.with(RootScope, |_, this| { match item.node { hir::ForeignItemFn(ref decl, ref generics) => { - this.visit_early_late(item.id, - subst::FnSpace, - decl, - generics, - |this| { + this.visit_early_late(item.id, decl, generics, |this| { intravisit::walk_foreign_item(this, item); }) } @@ -203,14 +196,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { b: &'v hir::Block, s: Span, fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, _, _, _, _, _) => { - self.visit_early_late(fn_id, subst::FnSpace, decl, generics, |this| { + self.visit_early_late(fn_id,decl, generics, |this| { this.add_scope_and_walk_fn(fk, decl, b, s, fn_id) }) } FnKind::Method(_, sig, _, _) => { self.visit_early_late( fn_id, - subst::FnSpace, decl, &sig.generics, |this| this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)); @@ -263,7 +255,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { if let hir::MethodTraitItem(ref sig, None) = trait_item.node { self.visit_early_late( - trait_item.id, subst::FnSpace, + trait_item.id, &sig.decl, &sig.generics, |this| intravisit::walk_trait_item(this, trait_item)) } else { @@ -469,7 +461,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { FnScope { s, .. } => { scope = s; } RootScope => { return; } - EarlyScope(_, lifetimes, s) | + EarlyScope(lifetimes, s) | LateScope(lifetimes, s) => { for lifetime_def in lifetimes { // FIXME (#24278): non-hygienic comparison @@ -557,7 +549,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late(&mut self, fn_id: ast::NodeId, - early_space: subst::ParamSpace, decl: &hir::FnDecl, generics: &hir::Generics, walk: F) where @@ -576,7 +567,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .partition(|l| self.map.late_bound.contains_key(&l.lifetime.id)); let this = self; - this.with(EarlyScope(early_space, &early, this.scope), move |old_scope, this| { + this.with(EarlyScope(&early, this.scope), move |old_scope, this| { this.with(LateScope(&late, this.scope), move |_, this| { this.check_lifetime_defs(old_scope, &generics.lifetimes); walk(this); @@ -606,11 +597,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break; } - EarlyScope(space, lifetimes, s) => { + EarlyScope(lifetimes, s) => { match search_lifetimes(lifetimes, lifetime_ref) { - Some((index, lifetime_def)) => { + Some((mut index, lifetime_def)) => { + // Adjust for nested early scopes, e.g. in methods. + let mut parent = s; + while let EarlyScope(lifetimes, s) = *parent { + index += lifetimes.len() as u32; + parent = s; + } + assert_eq!(*parent, RootScope); + let decl_id = lifetime_def.id; - let def = DefEarlyBoundRegion(space, index, decl_id); + let def = DefEarlyBoundRegion(index, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -672,7 +671,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break; } - EarlyScope(_, lifetimes, s) | + EarlyScope(lifetimes, s) | LateScope(lifetimes, s) => { search_result = search_lifetimes(lifetimes, lifetime_ref); if search_result.is_some() { @@ -768,7 +767,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - EarlyScope(_, lifetimes, s) | + EarlyScope(lifetimes, s) | LateScope(lifetimes, s) => { if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { signal_shadowing_problem( @@ -963,14 +962,3 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, } } } - -impl<'a> fmt::Debug for ScopeChain<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs), - LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs), - FnScope { fn_id, body_id, s: _ } => write!(fmt, "FnScope({:?}, {:?})", fn_id, body_id), - RootScope => write!(fmt, "RootScope"), - } - } -} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 77d7d5115efbc..33db0053cda13 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -31,7 +31,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; -use ty::subst::{Subst, TypeSpace}; +use ty::subst::Subst; use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; @@ -232,8 +232,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) { self_match_impls.push(def_id); - if trait_ref.substs.types.get_slice(TypeSpace)[1..].iter() - .zip(&impl_trait_ref.substs.types.get_slice(TypeSpace)[1..]) + if trait_ref.substs.types[1..].iter() + .zip(&impl_trait_ref.substs.types[1..]) .all(|(u,v)| self.fuzzy_match_tys(u, v)) { fuzzy_match_impls.push(def_id); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 3698027dca887..837e33b3e7fc2 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -142,7 +142,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { // Auto trait obligations on `impl Trait`. if tcx.trait_has_default_impl(predicate.def_id()) { let substs = predicate.skip_binder().trait_ref.substs; - if substs.types.as_full_slice().len() == 1 && substs.regions.is_empty() { + if substs.types.len() == 1 && substs.regions.is_empty() { if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty { return true; } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index bf6aad98db1a8..9ea738bd326eb 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -36,7 +36,7 @@ use super::util; use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin}; -use ty::subst::{Subst, Substs, TypeSpace}; +use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use traits; use ty::fast_reject; @@ -1936,7 +1936,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // for `PhantomData`, we pass `T` ty::TyStruct(def, substs) if def.is_phantom_data() => { - substs.types.as_full_slice().to_vec() + substs.types.to_vec() } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2585,11 +2585,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } else { return Err(Unimplemented); }; - let mut ty_params = BitVector::new(substs_a.types.len(TypeSpace)); + let mut ty_params = BitVector::new(substs_a.types.len()); let mut found = false; for ty in field.walk() { if let ty::TyParam(p) = ty.sty { - assert!(p.space == TypeSpace); ty_params.insert(p.idx as usize); found = true; } @@ -2602,13 +2601,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // TyError and ensure they do not affect any other fields. // This could be checked after type collection for any struct // with a potentially unsized trailing field. - let types = substs_a.types.map_enumerated(|(_, i, ty)| { + let types = substs_a.types.iter().enumerate().map(|(i, ty)| { if ty_params.contains(i) { tcx.types.err } else { ty } - }); + }).collect(); let substs = Substs::new(tcx, types, substs_a.regions.clone()); for &ty in fields.split_last().unwrap().1 { if ty.subst(tcx, substs).references_error() { @@ -2622,13 +2621,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Check that the source structure with the target's // type parameters is a subtype of the target. - let types = substs_a.types.map_enumerated(|(_, i, ty)| { + let types = substs_a.types.iter().enumerate().map(|(i, ty)| { if ty_params.contains(i) { - *substs_b.types.get(TypeSpace, i) + substs_b.types[i] } else { ty } - }); + }).collect(); let substs = Substs::new(tcx, types, substs_a.regions.clone()); let new_struct = tcx.mk_struct(def, substs); let origin = TypeOrigin::Misc(obligation.cause.span); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 42865ca927de3..9acfe2754820c 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -44,11 +44,10 @@ pub struct OverlapError { /// When we have selected one impl, but are actually using item definitions from /// a parent impl providing a default, we need a way to translate between the /// type parameters of the two impls. Here the `source_impl` is the one we've -/// selected, and `source_substs` is a substitution of its generics (and -/// possibly some relevant `FnSpace` variables as well). And `target_node` is -/// the impl/trait we're actually going to get the definition from. The resulting -/// substitution will map from `target_node`'s generics to `source_impl`'s -/// generics as instantiated by `source_subst`. +/// selected, and `source_substs` is a substitution of its generics. +/// And `target_node` is the impl/trait we're actually going to get the +/// definition from. The resulting substitution will map from `target_node`'s +/// generics to `source_impl`'s generics as instantiated by `source_subst`. /// /// For example, consider the following scenario: /// diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c2daa81ca7dab..3501dd4846087 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -23,7 +23,7 @@ use middle::free_region::FreeRegionMap; use middle::region::RegionMaps; use middle::resolve_lifetime; use middle::stability; -use ty::subst::{self, Substs}; +use ty::subst::Substs; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants}; @@ -1346,18 +1346,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_param(self, - space: subst::ParamSpace, index: u32, name: Name) -> Ty<'tcx> { - self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name })) + self.mk_ty(TyParam(ParamTy { idx: index, name: name })) } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(subst::TypeSpace, 0, keywords::SelfType.name()) + self.mk_param(0, keywords::SelfType.name()) } pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { - self.mk_param(def.space, def.index, def.name) + self.mk_param(def.index, def.name) } pub fn mk_anon(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 900e1841fb592..c6c37296e9e12 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -208,8 +208,8 @@ impl FlagComputation { } fn add_substs(&mut self, substs: &Substs) { - self.add_tys(substs.types.as_full_slice()); - for &r in substs.regions.as_full_slice() { + self.add_tys(&substs.types); + for &r in &substs.regions { self.add_region(r); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b2b8286be2fba..1f747ddfb2959 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -28,7 +28,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; use traits; use ty; -use ty::subst::{Subst, Substs, VecPerParamSpace}; +use ty::subst::{Subst, Substs}; use ty::walk::TypeWalker; use util::common::MemoizationMap; use util::nodemap::NodeSet; @@ -426,15 +426,15 @@ pub struct AssociatedType<'tcx> { #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] pub struct ItemVariances { - pub types: VecPerParamSpace, - pub regions: VecPerParamSpace, + pub types: Vec, + pub regions: Vec, } impl ItemVariances { pub fn empty() -> ItemVariances { ItemVariances { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), + types: vec![], + regions: vec![], } } } @@ -723,7 +723,6 @@ pub enum ObjectLifetimeDefault { pub struct TypeParameterDef<'tcx> { pub name: Name, pub def_id: DefId, - pub space: subst::ParamSpace, pub index: u32, pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, @@ -734,7 +733,6 @@ pub struct TypeParameterDef<'tcx> { pub struct RegionParameterDef { pub name: Name, pub def_id: DefId, - pub space: subst::ParamSpace, pub index: u32, pub bounds: Vec, } @@ -742,7 +740,6 @@ pub struct RegionParameterDef { impl RegionParameterDef { pub fn to_early_bound_region(&self) -> ty::Region { ty::ReEarlyBound(ty::EarlyBoundRegion { - space: self.space, index: self.index, name: self.name, }) @@ -812,7 +809,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` - /// would be the parameters in the `TypeSpace`. + /// would be the type parameters. Trait(PolyTraitPredicate<'tcx>), /// A predicate created by RFC1592 @@ -837,9 +834,9 @@ pub enum Predicate<'tcx> { /// trait must be object-safe ObjectSafe(DefId), - /// No direct syntax. May be thought of as `where T : FnFoo<...>` for some 'TypeSpace' - /// substitutions `...` and T being a closure type. Satisfied (or refuted) once we know the - /// closure's kind. + /// No direct syntax. May be thought of as `where T : FnFoo<...>` + /// for some substitutions `...` and T being a closure type. + /// Satisfied (or refuted) once we know the closure's kind. ClosureKind(DefId, ClosureKind), } @@ -975,7 +972,7 @@ impl<'tcx> TraitPredicate<'tcx> { } pub fn input_types(&self) -> &[Ty<'tcx>] { - self.trait_ref.substs.types.as_full_slice() + &self.trait_ref.substs.types } pub fn self_ty(&self) -> Ty<'tcx> { @@ -1117,7 +1114,7 @@ impl<'tcx> Predicate<'tcx> { pub fn walk_tys(&self) -> IntoIter> { let vec: Vec<_> = match *self { ty::Predicate::Trait(ref data) => { - data.0.trait_ref.substs.types.as_full_slice().to_vec() + data.0.trait_ref.input_types().to_vec() } ty::Predicate::Rfc1592(ref data) => { return data.walk_tys() @@ -1132,8 +1129,7 @@ impl<'tcx> Predicate<'tcx> { vec![] } ty::Predicate::Projection(ref data) => { - let trait_inputs = data.0.projection_ty.trait_ref.substs - .types.as_full_slice(); + let trait_inputs = data.0.projection_ty.trait_ref.input_types(); trait_inputs.iter() .cloned() .chain(Some(data.0.ty)) @@ -1217,7 +1213,7 @@ impl<'tcx> TraitRef<'tcx> { } pub fn self_ty(&self) -> Ty<'tcx> { - *self.substs.types.get(subst::TypeSpace, 0) + self.substs.types[0] } pub fn input_types(&self) -> &[Ty<'tcx>] { @@ -1225,7 +1221,7 @@ impl<'tcx> TraitRef<'tcx> { // now this is all the types that appear in the // trait-reference, but it should eventually exclude // associated types. - self.substs.types.as_full_slice() + &self.substs.types } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 388e8926403fd..abf863f953664 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -146,41 +146,18 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { let tcx = relation.tcx(); - let mut result = Ok(()); - - let types = a_subst.types.map_enumerated(|(space, i, a_ty)| { - if result.is_err() { return tcx.types.err; } - - let b_ty = b_subst.types.get(space, i); - let variance = variances.map_or(ty::Invariant, |v| { - *v.types.get(space, i) - }); - match relation.relate_with_variance(variance, a_ty, b_ty) { - Ok(ty) => ty, - Err(e) => { - result = Err(e); - tcx.types.err - } - } - }); - result?; - - let regions = a_subst.regions.map_enumerated(|(space, i, a_r)| { - if result.is_err() { return ty::ReStatic; } - - let b_r = b_subst.regions.get(space, i); - let variance = variances.map_or(ty::Invariant, |v| { - *v.regions.get(space, i) - }); - match relation.relate_with_variance(variance, a_r, b_r) { - Ok(r) => r, - Err(e) => { - result = Err(e); - ty::ReStatic - } - } - }); - result?; + + let types = a_subst.types.iter().enumerate().map(|(i, a_ty)| { + let b_ty = &b_subst.types[i]; + let variance = variances.map_or(ty::Invariant, |v| v.types[i]); + relation.relate_with_variance(variance, a_ty, b_ty) + }).collect()?; + + let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| { + let b_r = &b_subst.regions[i]; + let variance = variances.map_or(ty::Invariant, |v| v.regions[i]); + relation.relate_with_variance(variance, a_r, b_r) + }).collect()?; Ok(Substs::new(tcx, types, regions)) } @@ -433,7 +410,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, } (&ty::TyParam(ref a_p), &ty::TyParam(ref b_p)) - if a_p.idx == b_p.idx && a_p.space == b_p.space => + if a_p.idx == b_p.idx => { Ok(a) } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 021ae820b87c5..f7c4b9938c279 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,7 +9,7 @@ // except according to those terms. use infer::type_variable; -use ty::subst::{Substs, VecPerParamSpace}; +use ty::subst::Substs; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -450,16 +450,6 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for P<[T]> { } } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - self.map(|elem| elem.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.as_full_slice().iter().any(|elem| elem.visit_with(visitor)) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitObject { @@ -780,7 +770,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { ty::TypeParameterDef { name: self.name, def_id: self.def_id, - space: self.space, index: self.index, default: self.default.fold_with(folder), default_def_id: self.default_def_id, @@ -821,7 +810,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef { ty::RegionParameterDef { name: self.name, def_id: self.def_id, - space: self.space, index: self.index, bounds: self.bounds.fold_with(folder), } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 8786e2d16d22a..8aa81cc4743c9 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -13,7 +13,7 @@ use middle::cstore; use hir::def_id::DefId; use middle::region; -use ty::subst::{self, Substs}; +use ty::subst::Substs; use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TyS, TypeFoldable}; use util::common::ErrorReported; @@ -304,8 +304,8 @@ pub struct TraitObject<'tcx> { /// T : Foo /// /// This would be represented by a trait-reference where the def-id is the -/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the -/// `TypeSpace` and `U` as parameter 1 in the `TypeSpace`. +/// def-id for the trait `Foo` and the substs define `T` as parameter 0, +/// and `U` as parameter 1. /// /// Trait references also appear in object types like `Foo`, but in /// that case the `Self` parameter is absent from the substitutions. @@ -365,7 +365,7 @@ impl<'tcx> ExistentialTraitRef<'tcx> { // now this is all the types that appear in the // trait-reference, but it should eventually exclude // associated types. - self.substs.types.as_full_slice() + &self.substs.types } } @@ -498,34 +498,29 @@ impl<'tcx> PolyFnSig<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ParamTy { - pub space: subst::ParamSpace, pub idx: u32, pub name: Name, } impl<'a, 'gcx, 'tcx> ParamTy { - pub fn new(space: subst::ParamSpace, - index: u32, - name: Name) - -> ParamTy { - ParamTy { space: space, idx: index, name: name } + pub fn new(index: u32, name: Name) -> ParamTy { + ParamTy { idx: index, name: name } } pub fn for_self() -> ParamTy { - ParamTy::new(subst::TypeSpace, 0, keywords::SelfType.name()) + ParamTy::new(0, keywords::SelfType.name()) } pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { - ParamTy::new(def.space, def.index, def.name) + ParamTy::new(def.index, def.name) } pub fn to_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - tcx.mk_param(self.space, self.idx, self.name) + tcx.mk_param(self.idx, self.name) } pub fn is_self(&self) -> bool { if self.name == keywords::SelfType.name() { - assert_eq!(self.space, subst::TypeSpace); assert_eq!(self.idx, 0); true } else { @@ -682,7 +677,6 @@ pub enum Region { #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct EarlyBoundRegion { - pub space: subst::ParamSpace, pub index: u32, pub name: Name, } @@ -951,9 +945,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_bool(&self) -> bool { self.sty == TyBool } - pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool { + pub fn is_param(&self, index: u32) -> bool { match self.sty { - ty::TyParam(ref data) => data.space == space && data.idx == index, + ty::TyParam(ref data) => data.idx == index, _ => false, } } @@ -1219,19 +1213,19 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } TyTrait(ref obj) => { let mut v = vec![obj.region_bound]; - v.extend_from_slice(obj.principal.skip_binder().substs.regions.as_full_slice()); + v.extend_from_slice(&obj.principal.skip_binder().substs.regions); v } TyEnum(_, substs) | TyStruct(_, substs) | TyAnon(_, substs) => { - substs.regions.as_full_slice().to_vec() + substs.regions.to_vec() } TyClosure(_, ref substs) => { - substs.func_substs.regions.as_full_slice().to_vec() + substs.func_substs.regions.to_vec() } TyProjection(ref data) => { - data.trait_ref.substs.regions.as_full_slice().to_vec() + data.trait_ref.substs.regions.to_vec() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 594d15ad5f734..e1a19a7b7992e 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -10,56 +10,32 @@ // Type substitutions. -pub use self::ParamSpace::*; - use middle::cstore; use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use serialize::{Encodable, Encoder, Decodable, Decoder}; -use std::fmt; use syntax_pos::{Span, DUMMY_SP}; /////////////////////////////////////////////////////////////////////////// -/// A substitution mapping type/region parameters to new values. We -/// identify each in-scope parameter by an *index* and a *parameter -/// space* (which indices where the parameter is defined; see -/// `ParamSpace`). +/// A substitution mapping type/region parameters to new values. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Substs<'tcx> { - pub types: VecPerParamSpace>, - pub regions: VecPerParamSpace, + pub types: Vec>, + pub regions: Vec, } impl<'a, 'gcx, 'tcx> Substs<'tcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - t: VecPerParamSpace>, - r: VecPerParamSpace) + t: Vec>, + r: Vec) -> &'tcx Substs<'tcx> { tcx.mk_substs(Substs { types: t, regions: r }) } - pub fn new_fn(tcx: TyCtxt<'a, 'gcx, 'tcx>, - t: Vec>, - r: Vec) - -> &'tcx Substs<'tcx> - { - Substs::new(tcx, VecPerParamSpace::new(vec![], t), - VecPerParamSpace::new(vec![], r)) - } - - pub fn new_type(tcx: TyCtxt<'a, 'gcx, 'tcx>, - t: Vec>, - r: Vec) - -> &'tcx Substs<'tcx> - { - Substs::new(tcx, VecPerParamSpace::new(t, vec![]), - VecPerParamSpace::new(r, vec![])) - } - pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>, mut t: Vec>, r: Vec, @@ -67,13 +43,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { -> &'tcx Substs<'tcx> { t.insert(0, s); - Substs::new(tcx, VecPerParamSpace::new(t, vec![]), - VecPerParamSpace::new(r, vec![])) + Substs::new(tcx, t, r) } pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { - Substs::new(tcx, VecPerParamSpace::empty(), - VecPerParamSpace::empty()) + Substs::new(tcx, vec![], vec![]) } /// Creates a Substs for generic parameter definitions, @@ -92,14 +66,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let num_regions = defs.parent_regions as usize + defs.regions.len(); let num_types = defs.parent_types as usize + defs.types.len(); let mut substs = Substs { - regions: VecPerParamSpace { - type_limit: 0, - content: Vec::with_capacity(num_regions) - }, - types: VecPerParamSpace { - type_limit: 0, - content: Vec::with_capacity(num_types) - } + regions: Vec::with_capacity(num_regions), + types: Vec::with_capacity(num_types) }; substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type); @@ -121,22 +89,14 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { for def in &defs.regions { let region = mk_region(def, self); - self.regions.content.push(region); - - if def.space == TypeSpace { - self.regions.type_limit += 1; - assert_eq!(self.regions.content.len(), self.regions.type_limit); - } + assert_eq!(def.index as usize, self.regions.len()); + self.regions.push(region); } for def in &defs.types { let ty = mk_type(def, self); - self.types.content.push(ty); - - if def.space == TypeSpace { - self.types.type_limit += 1; - assert_eq!(self.types.content.len(), self.types.type_limit); - } + assert_eq!(def.index as usize, self.types.len()); + self.types.push(ty); } } @@ -145,11 +105,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { - *self.types.get(ty_param_def.space, ty_param_def.index as usize) + self.types[ty_param_def.index as usize] } pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region { - *self.regions.get(def.space, def.index as usize) + self.regions[def.index as usize] } /// Transform from substitutions for a child of `source_ancestor` @@ -162,14 +122,10 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { let defs = tcx.lookup_generics(source_ancestor); - assert_eq!(self.types.len(TypeSpace), defs.types.len()); - assert_eq!(target_substs.types.len(FnSpace), 0); - assert_eq!(self.regions.len(TypeSpace), defs.regions.len()); - assert_eq!(target_substs.regions.len(FnSpace), 0); - - let Substs { mut types, mut regions } = target_substs.clone(); - types.content.extend(&self.types.as_full_slice()[defs.types.len()..]); - regions.content.extend(&self.regions.as_full_slice()[defs.regions.len()..]); + let regions = target_substs.regions.iter() + .chain(&self.regions[defs.regions.len()..]).cloned().collect(); + let types = target_substs.types.iter() + .chain(&self.types[defs.types.len()..]).cloned().collect(); Substs::new(tcx, types, regions) } } @@ -193,200 +149,6 @@ impl<'tcx> Decodable for &'tcx Substs<'tcx> { } } -/////////////////////////////////////////////////////////////////////////// -// ParamSpace - -#[derive(PartialOrd, Ord, PartialEq, Eq, Copy, - Clone, Hash, RustcEncodable, RustcDecodable, Debug)] -pub enum ParamSpace { - TypeSpace, // Type parameters attached to a type definition, trait, or impl - FnSpace, // Type parameters attached to a method or fn -} - -impl ParamSpace { - pub fn all() -> [ParamSpace; 2] { - [TypeSpace, FnSpace] - } - - pub fn to_uint(self) -> usize { - match self { - TypeSpace => 0, - FnSpace => 1, - } - } - - pub fn from_uint(u: usize) -> ParamSpace { - match u { - 0 => TypeSpace, - 1 => FnSpace, - _ => bug!("Invalid ParamSpace: {}", u) - } - } -} - -/// Vector of things sorted by param space. Used to keep -/// the set of things declared on the type, self, or method -/// distinct. -#[derive(PartialEq, Eq, Clone, Hash, RustcEncodable, RustcDecodable)] -pub struct VecPerParamSpace { - // This was originally represented as a tuple with one Vec for - // each variant of ParamSpace, and that remains the abstraction - // that it provides to its clients. - // - // Here is how the representation corresponds to the abstraction - // i.e. the "abstraction function" AF: - // - // AF(self) = (self.content[..self.type_limit], - // self.content[self.type_limit..]) - type_limit: usize, - content: Vec, -} - -impl fmt::Debug for VecPerParamSpace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{:?};{:?}]", - self.get_slice(TypeSpace), - self.get_slice(FnSpace)) - } -} - -impl VecPerParamSpace { - fn limits(&self, space: ParamSpace) -> (usize, usize) { - match space { - TypeSpace => (0, self.type_limit), - FnSpace => (self.type_limit, self.content.len()), - } - } - - pub fn empty() -> VecPerParamSpace { - VecPerParamSpace { - type_limit: 0, - content: Vec::new() - } - } - - /// `t` is the type space. - /// `f` is the fn space. - pub fn new(t: Vec, f: Vec) -> VecPerParamSpace { - let type_limit = t.len(); - - let mut content = t; - content.extend(f); - - VecPerParamSpace { - type_limit: type_limit, - content: content, - } - } - - fn new_internal(content: Vec, type_limit: usize) -> VecPerParamSpace { - VecPerParamSpace { - type_limit: type_limit, - content: content, - } - } - - pub fn len(&self, space: ParamSpace) -> usize { - self.get_slice(space).len() - } - - pub fn is_empty_in(&self, space: ParamSpace) -> bool { - self.len(space) == 0 - } - - pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] { - let (start, limit) = self.limits(space); - &self.content[start.. limit] - } - - pub fn get<'a>(&'a self, space: ParamSpace, index: usize) -> &'a T { - &self.get_slice(space)[index] - } - - pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> { - EnumeratedItems::new(self) - } - - pub fn as_full_slice(&self) -> &[T] { - &self.content - } - - pub fn all

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { - self.as_full_slice().iter().all(pred) - } - - pub fn any

(&self, pred: P) -> bool where P: FnMut(&T) -> bool { - self.as_full_slice().iter().any(pred) - } - - pub fn is_empty(&self) -> bool { - self.content.is_empty() - } - - pub fn map(&self, pred: P) -> VecPerParamSpace where P: FnMut(&T) -> U { - let result = self.as_full_slice().iter().map(pred).collect(); - VecPerParamSpace::new_internal(result, self.type_limit) - } - - pub fn map_enumerated(&self, pred: P) -> VecPerParamSpace where - P: FnMut((ParamSpace, usize, &T)) -> U, - { - let result = self.iter_enumerated().map(pred).collect(); - VecPerParamSpace::new_internal(result, self.type_limit) - } -} - -#[derive(Clone)] -pub struct EnumeratedItems<'a,T:'a> { - vec: &'a VecPerParamSpace, - space_index: usize, - elem_index: usize -} - -impl<'a,T> EnumeratedItems<'a,T> { - fn new(v: &'a VecPerParamSpace) -> EnumeratedItems<'a,T> { - let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 }; - result.adjust_space(); - result - } - - fn adjust_space(&mut self) { - let spaces = ParamSpace::all(); - while - self.space_index < spaces.len() && - self.elem_index >= self.vec.len(spaces[self.space_index]) - { - self.space_index += 1; - self.elem_index = 0; - } - } -} - -impl<'a,T> Iterator for EnumeratedItems<'a,T> { - type Item = (ParamSpace, usize, &'a T); - - fn next(&mut self) -> Option<(ParamSpace, usize, &'a T)> { - let spaces = ParamSpace::all(); - if self.space_index < spaces.len() { - let space = spaces[self.space_index]; - let index = self.elem_index; - let item = self.vec.get(space, index); - - self.elem_index += 1; - self.adjust_space(); - - Some((space, index, item)) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let size = self.vec.as_full_slice().len(); - (size, Some(size)) - } -} - /////////////////////////////////////////////////////////////////////////// // Public trait `Subst` @@ -461,7 +223,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { // the specialized routine `ty::replace_late_regions()`. match r { ty::ReEarlyBound(data) => { - match self.substs.regions.get_slice(data.space).get(data.index as usize) { + match self.substs.regions.get(data.index as usize) { Some(&r) => { self.shift_region_through_binders(r) } @@ -471,10 +233,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { span, "Region parameter out of range \ when substituting in region {} (root type={:?}) \ - (space={:?}, index={})", + (index={})", data.name, self.root_ty, - data.space, data.index); } } @@ -517,18 +278,17 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.types.get_slice(p.space).get(p.idx as usize); + let opt_ty = self.substs.types.get(p.idx as usize); let ty = match opt_ty { Some(t) => *t, None => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, - "Type parameter `{:?}` ({:?}/{:?}/{}) out of range \ + "Type parameter `{:?}` ({:?}/{}) out of range \ when substituting (root type={:?}) substs={:?}", p, source_ty, - p.space, p.idx, self.root_ty, self.substs); @@ -606,10 +366,9 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { trait_id: DefId, substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { - let Substs { mut types, mut regions } = substs.clone(); let defs = tcx.lookup_generics(trait_id); - types.content.truncate(defs.types.len()); - regions.content.truncate(defs.regions.len()); + let regions = substs.regions[..defs.regions.len()].to_vec(); + let types = substs.types[..defs.types.len()].to_vec(); ty::TraitRef { def_id: trait_id, @@ -624,8 +383,7 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { -> ty::ExistentialTraitRef<'tcx> { let Substs { mut types, regions } = trait_ref.substs.clone(); - types.type_limit -= 1; - types.content.remove(0); + types.remove(0); ty::ExistentialTraitRef { def_id: trait_ref.def_id, @@ -648,8 +406,7 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { self.map_bound(|trait_ref| { let Substs { mut types, regions } = trait_ref.substs.clone(); - types.type_limit += 1; - types.content.insert(0, self_ty); + types.insert(0, self_ty); ty::TraitRef { def_id: trait_ref.def_id, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 5a73439beac6e..51710c13a7dea 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -476,7 +476,6 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { self.hash(tys.len()); } TyParam(p) => { - self.hash(p.space); self.hash(p.idx); self.hash(p.name.as_str()); } @@ -694,8 +693,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> { return false; } - let types_a = substs_a.types.as_full_slice(); - let types_b = substs_b.types.as_full_slice(); + let types_a = &substs_a.types; + let types_b = &substs_b.types; types_a.iter().zip(types_b).all(|(&a, &b)| same_type(a, b)) } diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 3bf539245571e..8a9ee45351dfc 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -79,7 +79,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.push(mt.ty); } ty::TyProjection(ref data) => { - push_reversed(stack, data.trait_ref.substs.types.as_full_slice()); + push_reversed(stack, &data.trait_ref.substs.types); } ty::TyTrait(ref obj) => { push_reversed(stack, obj.principal.input_types()); @@ -90,17 +90,17 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | ty::TyAnon(_, ref substs) => { - push_reversed(stack, substs.types.as_full_slice()); + push_reversed(stack, &substs.types); } ty::TyClosure(_, ref substs) => { - push_reversed(stack, substs.func_substs.types.as_full_slice()); + push_reversed(stack, &substs.func_substs.types); push_reversed(stack, &substs.upvar_tys); } ty::TyTuple(ref ts) => { push_reversed(stack, ts); } ty::TyFnDef(_, substs, ref ft) => { - push_reversed(stack, substs.types.as_full_slice()); + push_reversed(stack, &substs.types); push_sig_subtypes(stack, &ft.sig); } ty::TyFnPtr(ref ft) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 77d0835bf6bc1..54b19362b1d86 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -261,7 +261,6 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); self.out.extend( trait_ref.substs.types - .as_full_slice() .iter() .filter(|ty| !ty.has_escaping_regions()) .map(|ty| traits::Obligation::new(cause.clone(), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a62ee37613e50..02ad8fb7033ed 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -56,7 +56,7 @@ fn fn_sig(f: &mut fmt::Formatter, } /// Namespace of the path given to parameterized to print. -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum Ns { Type, Value @@ -71,16 +71,43 @@ pub fn parameterized(f: &mut fmt::Formatter, let mut verbose = false; let mut num_supplied_defaults = 0; let mut has_self = false; - let (fn_trait_kind, item_name) = ty::tls::with(|tcx| { - verbose = tcx.sess.verbose(); + let mut num_regions = 0; + let mut num_types = 0; + let mut item_name = None; + let fn_trait_kind = ty::tls::with(|tcx| { let mut generics = tcx.lookup_generics(did); + let mut path_def_id = did; + verbose = tcx.sess.verbose(); + has_self = generics.has_self; + if let Some(def_id) = generics.parent { + // Methods. + assert_eq!(ns, Ns::Value); generics = tcx.lookup_generics(def_id); + num_regions = generics.regions.len(); + num_types = generics.types.len(); + + if has_self { + write!(f, "<{} as ", substs.types[0])?; + } + + item_name = Some(tcx.item_name(did)); + path_def_id = def_id; + } else { + if ns == Ns::Value { + // Functions. + assert_eq!(has_self, false); + } else { + // Types and traits. + num_regions = generics.regions.len(); + num_types = generics.types.len(); + } } + if !verbose { if generics.types.last().map_or(false, |def| def.default.is_some()) { if let Some(substs) = tcx.lift(&substs) { - let tps = substs.types.get_slice(subst::TypeSpace); + let tps = &substs.types[..num_types]; for (def, actual) in generics.types.iter().zip(tps).rev() { if def.default.subst(tcx, substs) != Some(actual) { break; @@ -91,31 +118,13 @@ pub fn parameterized(f: &mut fmt::Formatter, } } - has_self = generics.has_self; - if ns == Ns::Value && has_self { - write!(f, "<{} as ", substs.types.get(subst::TypeSpace, 0))?; - } - - let (did, item_name) = if ns == Ns::Value { - // Try to get the impl/trait parent, if this is an - // associated value item (method or constant). - tcx.trait_of_item(did).or_else(|| { - // An impl could be a trait impl or an inherent one. - tcx.impl_of_method(did).map(|impl_def_id| { - tcx.trait_id_of_impl(impl_def_id) - .unwrap_or(impl_def_id) - }) - }).map_or((did, None), |parent| (parent, Some(tcx.item_name(did)))) - } else { - (did, None) - }; - write!(f, "{}", tcx.item_path_str(did))?; - Ok((tcx.lang_items.fn_trait_kind(did), item_name)) + write!(f, "{}", tcx.item_path_str(path_def_id))?; + Ok(tcx.lang_items.fn_trait_kind(path_def_id)) })?; if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { let projection_ty = projections[0].ty; - if let TyTuple(ref args) = substs.types.get(subst::TypeSpace, 1).sty { + if let TyTuple(ref args) = substs.types[1].sty { return fn_sig(f, args, false, projection_ty); } } @@ -158,9 +167,9 @@ pub fn parameterized(f: &mut fmt::Formatter, Ok(()) }; - print_regions(f, "<", substs.regions.get_slice(subst::TypeSpace))?; + print_regions(f, "<", &substs.regions[..num_regions])?; - let tps = substs.types.get_slice(subst::TypeSpace); + let tps = &substs.types[..num_types]; for &ty in &tps[has_self as usize..tps.len() - num_supplied_defaults] { start_or_continue(f, "<", ", ")?; @@ -188,10 +197,10 @@ pub fn parameterized(f: &mut fmt::Formatter, write!(f, "::{}", item_name)?; } - print_regions(f, "::<", substs.regions.get_slice(subst::FnSpace))?; + print_regions(f, "::<", &substs.regions[num_regions..])?; // FIXME: consider being smart with defaults here too - for ty in substs.types.get_slice(subst::FnSpace) { + for ty in &substs.types[num_types..] { start_or_continue(f, "::<", ", ")?; write!(f, "{}", ty)?; } @@ -328,19 +337,19 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> { impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeParameterDef({}, {:?}, {:?}/{})", + write!(f, "TypeParameterDef({}, {:?}, {})", self.name, self.def_id, - self.space, self.index) + self.index) } } impl fmt::Debug for ty::RegionParameterDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionParameterDef({}, {:?}, {:?}/{}, {:?})", + write!(f, "RegionParameterDef({}, {:?}, {}, {:?})", self.name, self.def_id, - self.space, self.index, + self.index, self.bounds) } } @@ -526,8 +535,7 @@ impl fmt::Debug for ty::Region { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::ReEarlyBound(ref data) => { - write!(f, "ReEarlyBound({:?}, {}, {})", - data.space, + write!(f, "ReEarlyBound({}, {})", data.index, data.name) } @@ -1011,7 +1019,7 @@ impl fmt::Display for ty::ParamTy { impl fmt::Debug for ty::ParamTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}/{:?}.{}", self, self.space, self.idx) + write!(f, "{}/#{}", self, self.idx) } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 9f300b5b29ba8..111646912ade3 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -859,7 +859,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil())); let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new_fn(tcx, vec![ty], vec![]); + let substs = Substs::new(tcx, vec![ty], vec![]); let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); self.patch.new_block(BasicBlockData { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index c84b195dd4b30..32d0bbbfdb6b7 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -20,7 +20,6 @@ use rustc::middle::region::{self, CodeExtent}; use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; -use rustc::ty::subst; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -276,19 +275,17 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx.mk_tup(vec![ty1, ty2]) } - pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> { + pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(space, index, token::intern(&name[..])) + self.infcx.tcx.mk_param(index, token::intern(&name[..])) } pub fn re_early_bound(&self, - space: subst::ParamSpace, index: u32, name: &'static str) -> ty::Region { let name = token::intern(name); ty::ReEarlyBound(ty::EarlyBoundRegion { - space: space, index: index, name: name, }) @@ -674,11 +671,11 @@ fn subst_ty_renumber_bound() { // t_source = fn(A) let t_source = { - let t_param = env.t_param(subst::TypeSpace, 0); + let t_param = env.t_param(0); env.t_fn(&[t_param], env.t_nil()) }; - let substs = Substs::new_type(env.infcx.tcx, vec![t_rptr_bound1], vec![]); + let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) @@ -709,11 +706,11 @@ fn subst_ty_renumber_some_bounds() { // t_source = (A, fn(A)) let t_source = { - let t_param = env.t_param(subst::TypeSpace, 0); + let t_param = env.t_param(0); env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) }; - let substs = Substs::new_type(env.infcx.tcx, vec![t_rptr_bound1], vec![]); + let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = (&'a isize, fn(&'a isize)) @@ -755,7 +752,7 @@ fn escaping() { assert!(t_rptr_bound2.has_escaping_regions()); // t_fn = fn(A) - let t_param = env.t_param(subst::TypeSpace, 0); + let t_param = env.t_param(0); assert!(!t_param.has_escaping_regions()); let t_fn = env.t_fn(&[t_param], env.t_nil()); assert!(!t_fn.has_escaping_regions()); @@ -771,11 +768,11 @@ fn subst_region_renumber_region() { // type t_source<'a> = fn(&'a isize) let t_source = { - let re_early = env.re_early_bound(subst::TypeSpace, 0, "'a"); + let re_early = env.re_early_bound(0, "'a"); env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) }; - let substs = Substs::new_type(env.infcx.tcx, vec![], vec![re_bound1]); + let substs = Substs::new(env.infcx.tcx, vec![], vec![re_bound1]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index e8e3679a60ca2..c76cf23639237 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -20,7 +20,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use middle::region; -use rustc::ty::subst::{self, Substs, VecPerParamSpace}; +use rustc::ty::subst::Substs; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rbml; @@ -128,23 +128,19 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - fn parse_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where - F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T, - { - let (mut a, mut b) = (vec![], vec![]); - for r in &mut [&mut a, &mut b] { - assert_eq!(self.next(), '['); - while self.peek() != ']' { - r.push(f(self)); - } - assert_eq!(self.next(), ']'); + pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { + let mut regions = vec![]; + let mut types = vec![]; + assert_eq!(self.next(), '['); + while self.peek() != '|' { + regions.push(self.parse_region()); } - VecPerParamSpace::new(a, b) - } + assert_eq!(self.next(), '|'); + while self.peek() != ']' { + types.push(self.parse_ty()); + } + assert_eq!(self.next(), ']'); - pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { - let regions = self.parse_vec_per_param_space(|this| this.parse_region()); - let types = self.parse_vec_per_param_space(|this| this.parse_ty()); Substs::new(self.tcx, types, regions) } @@ -155,14 +151,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let parent_types = self.parse_u32(); let mut regions = vec![]; + let mut types = vec![]; assert_eq!(self.next(), '['); - while self.peek() != ']' { + while self.peek() != '|' { regions.push(self.parse_region_param_def()); } - assert_eq!(self.next(), ']'); - - let mut types = vec![]; - assert_eq!(self.next(), '['); + assert_eq!(self.next(), '|'); while self.peek() != ']' { types.push(self.parse_type_param_def()); } @@ -225,13 +219,10 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'B' => { assert_eq!(self.next(), '['); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let name = token::intern(&self.parse_str(']')); ty::ReEarlyBound(ty::EarlyBoundRegion { - space: space, index: index, name: name }) @@ -406,10 +397,8 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { assert_eq!(self.next(), '['); let index = self.parse_u32(); assert_eq!(self.next(), '|'); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); let name = token::intern(&self.parse_str(']')); - return tcx.mk_param(space, index, name); + return tcx.mk_param(index, name); } '~' => return tcx.mk_box(self.parse_ty()), '*' => return tcx.mk_ptr(self.parse_mt()), @@ -552,10 +541,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { m } - fn parse_param_space(&mut self) -> subst::ParamSpace { - subst::ParamSpace::from_uint(self.parse_uint()) - } - fn parse_abi_set(&mut self) -> abi::Abi { assert_eq!(self.next(), '['); let bytes = self.scan(|c| c == ']'); @@ -656,8 +641,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { let name = self.parse_name(':'); let def_id = self.parse_def(); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let default_def_id = self.parse_def(); @@ -667,7 +650,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { ty::TypeParameterDef { name: name, def_id: def_id, - space: space, index: index, default_def_id: default_def_id, default: default, @@ -678,8 +660,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { let name = self.parse_name(':'); let def_id = self.parse_def(); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); let mut bounds = vec![]; @@ -695,7 +675,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { ty::RegionParameterDef { name: name, def_id: def_id, - space: space, index: index, bounds: bounds, } diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 27907596ca788..90fd8a0eb2f65 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -19,8 +19,7 @@ use std::io::prelude::*; use rustc::hir::def_id::DefId; use middle::region; -use rustc::ty::subst::{self, Substs, VecPerParamSpace}; -use rustc::ty::ParamTy; +use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FnvHashMap; @@ -163,8 +162,8 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyInfer(_) => { bug!("cannot encode inference variable types"); } - ty::TyParam(ParamTy {space, idx, name}) => { - write!(w, "p[{}|{}|{}]", idx, space.to_uint(), name); + ty::TyParam(p) => { + write!(w, "p[{}|{}]", p.idx, p.name); } ty::TyStruct(def, substs) => { write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); @@ -249,27 +248,17 @@ fn enc_opt(w: &mut Cursor>, t: Option, enc_f: F) where } } -fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Cursor>, - cx: &ctxt<'a, 'tcx>, - v: &VecPerParamSpace, - mut op: F) where - F: FnMut(&mut Cursor>, &ctxt<'a, 'tcx>, &T), -{ - for &space in &subst::ParamSpace::all() { - write!(w, "["); - for t in v.get_slice(space) { - op(w, cx, t); - } - write!(w, "]"); - } -} - pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, substs: &Substs<'tcx>) { - enc_vec_per_param_space(w, cx, &substs.regions, - |w, cx, &r| enc_region(w, cx, r)); - enc_vec_per_param_space(w, cx, &substs.types, - |w, cx, &ty| enc_ty(w, cx, ty)); + write!(w, "["); + for &r in &substs.regions { + enc_region(w, cx, r); + } + write!(w, "|"); + for &ty in &substs.types { + enc_ty(w, cx, ty); + } + write!(w, "]"); } pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, @@ -284,7 +273,7 @@ pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, for r in &generics.regions { enc_region_param_def(w, cx, r) } - write!(w, "]["); + write!(w, "|"); for t in &generics.types { enc_type_param_def(w, cx, t); } @@ -305,8 +294,7 @@ pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: ty::Region) { write!(w, "]"); } ty::ReEarlyBound(ref data) => { - write!(w, "B[{}|{}|{}]", - data.space.to_uint(), + write!(w, "B[{}|{}]", data.index, data.name); } @@ -446,18 +434,17 @@ fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBound fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { - write!(w, "{}:{}|{}|{}|{}|", - v.name, (cx.ds)(cx.tcx, v.def_id), - v.space.to_uint(), v.index, (cx.ds)(cx.tcx, v.default_def_id)); + write!(w, "{}:{}|{}|{}|", + v.name, (cx.ds)(cx.tcx, v.def_id), + v.index, (cx.ds)(cx.tcx, v.default_def_id)); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); enc_object_lifetime_default(w, cx, v.object_lifetime_default); } fn enc_region_param_def(w: &mut Cursor>, cx: &ctxt, v: &ty::RegionParameterDef) { - write!(w, "{}:{}|{}|{}|", - v.name, (cx.ds)(cx.tcx, v.def_id), - v.space.to_uint(), v.index); + write!(w, "{}:{}|{}|", + v.name, (cx.ds)(cx.tcx, v.def_id), v.index); for &r in &v.bounds { write!(w, "R"); enc_region(w, cx, r); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 229890483882c..5e4053a82ad8a 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -750,7 +750,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> TerminatorKind<'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new_fn(tcx, vec![data.item_ty], vec![]); + let substs = Substs::new(tcx, vec![data.item_ty], vec![]); TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index bb27a308f71f7..25a1479c28948 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -252,7 +252,7 @@ impl<'a, 'tcx> Instance<'tcx> { // and should not matter anyhow. let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_full_slice()); + let hash = get_symbol_hash(scx, &def_path, instance_ty, &substs.types); let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index e80dd28c5e502..f505efb1ab2f9 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -346,7 +346,7 @@ impl<'tcx> TypeMap<'tcx> { // Add the def-index as the second part output.push_str(&format!("{:x}", def_id.index.as_usize())); - let tps = substs.types.as_full_slice(); + let tps = &substs.types; if !tps.is_empty() { output.push('<'); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 684628e9a40fb..1ee000992b9c5 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -358,7 +358,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, name_to_append_suffix_to: &mut String) -> DIArray { - let actual_types = param_substs.types.as_full_slice(); + let actual_types = ¶m_substs.types; if actual_types.is_empty() { return create_DIArray(DIB(cx), &[]); diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 20dbc8ac78eaf..2a996ca75a37e 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -181,7 +181,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push('<'); - for &type_parameter in substs.types.as_full_slice() { + for &type_parameter in &substs.types { push_debuginfo_type_name(cx, type_parameter, true, output); output.push_str(", "); } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 133a98a2470f0..ecee470551059 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -15,7 +15,7 @@ use intrinsics::{self, Intrinsic}; use libc; use llvm; use llvm::{ValueRef, TypeKind}; -use rustc::ty::subst::{FnSpace, Substs}; +use rustc::ty::subst::Substs; use abi::{Abi, FnType}; use adt; use base::*; @@ -136,8 +136,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, callee::ArgExprs(arg_exprs) => { assert_eq!(arg_exprs.len(), 1); - let (in_type, out_type) = (*substs.types.get(FnSpace, 0), - *substs.types.get(FnSpace, 1)); + let (in_type, out_type) = (substs.types[0], + substs.types[1]); let llintype = type_of::type_of(ccx, in_type); let llouttype = type_of::type_of(ccx, out_type); @@ -346,12 +346,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, Call(bcx, llfn, &[], call_debug_location) } (_, "size_of") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } (_, "size_of_val") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; if !type_is_sized(tcx, tp_ty) { let (llsize, _) = glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]); @@ -362,11 +362,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } (_, "min_align_of") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; C_uint(ccx, type_of::align_of(ccx, tp_ty)) } (_, "min_align_of_val") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; if !type_is_sized(tcx, tp_ty) { let (_, llalign) = glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]); @@ -376,12 +376,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } (_, "pref_align_of") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)) } (_, "drop_in_place") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; let ptr = if type_is_sized(tcx, tp_ty) { llargs[0] } else { @@ -395,22 +395,22 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) } (_, "type_name") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; let ty_name = token::intern_and_get_ident(&tp_ty.to_string()); C_str_slice(ccx, ty_name) } (_, "type_id") => { - C_u64(ccx, ccx.tcx().type_id_hash(*substs.types.get(FnSpace, 0))) + C_u64(ccx, ccx.tcx().type_id_hash(substs.types[0])) } (_, "init_dropped") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; if !type_is_zero_size(ccx, tp_ty) { drop_done_fill_mem(bcx, llresult, tp_ty); } C_nil(ccx) } (_, "init") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; if !type_is_zero_size(ccx, tp_ty) { // Just zero out the stack slot. (See comment on base::memzero for explanation) init_zero_mem(bcx, llresult, tp_ty); @@ -422,7 +422,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) } (_, "needs_drop") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty)) } @@ -441,7 +441,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, false, false, - *substs.types.get(FnSpace, 0), + substs.types[0], llargs[1], llargs[0], llargs[2], @@ -451,7 +451,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, true, false, - *substs.types.get(FnSpace, 0), + substs.types[0], llargs[1], llargs[0], llargs[2], @@ -460,7 +460,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "write_bytes") => { memset_intrinsic(bcx, false, - *substs.types.get(FnSpace, 0), + substs.types[0], llargs[0], llargs[1], llargs[2], @@ -471,7 +471,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, false, true, - *substs.types.get(FnSpace, 0), + substs.types[0], llargs[0], llargs[1], llargs[2], @@ -481,7 +481,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, true, true, - *substs.types.get(FnSpace, 0), + substs.types[0], llargs[0], llargs[1], llargs[2], @@ -490,14 +490,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "volatile_set_memory") => { memset_intrinsic(bcx, true, - *substs.types.get(FnSpace, 0), + substs.types[0], llargs[0], llargs[1], llargs[2], call_debug_location) } (_, "volatile_load") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; let mut ptr = llargs[0]; if let Some(ty) = fn_ty.ret.cast { ptr = PointerCast(bcx, ptr, ty.ptr_to()); @@ -509,7 +509,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, to_immediate(bcx, load, tp_ty) }, (_, "volatile_store") => { - let tp_ty = *substs.types.get(FnSpace, 0); + let tp_ty = substs.types[0]; if type_is_fat_ptr(bcx.tcx(), tp_ty) { VolatileStore(bcx, llargs[1], expr::get_dataptr(bcx, llargs[0])); VolatileStore(bcx, llargs[2], expr::get_meta(bcx, llargs[0])); @@ -609,10 +609,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }, (_, "discriminant_value") => { - let val_ty = substs.types.get(FnSpace, 0); + let val_ty = substs.types[0]; match val_ty.sty { ty::TyEnum(..) => { - let repr = adt::represent_type(ccx, *val_ty); + let repr = adt::represent_type(ccx, val_ty); adt::trans_get_discr(bcx, &repr, llargs[0], Some(llret_ty), true) } @@ -663,7 +663,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, match split[1] { "cxchg" | "cxchgweak" => { - let sty = &substs.types.get(FnSpace, 0).sty; + let sty = &substs.types[0].sty; if int_type_width_signed(sty, ccx).is_some() { let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False }; let val = AtomicCmpXchg(bcx, llargs[0], llargs[1], llargs[2], @@ -682,7 +682,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "load" => { - let sty = &substs.types.get(FnSpace, 0).sty; + let sty = &substs.types[0].sty; if int_type_width_signed(sty, ccx).is_some() { AtomicLoad(bcx, llargs[0], order) } else { @@ -695,7 +695,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "store" => { - let sty = &substs.types.get(FnSpace, 0).sty; + let sty = &substs.types[0].sty; if int_type_width_signed(sty, ccx).is_some() { AtomicStore(bcx, llargs[1], llargs[0], order); } else { @@ -734,7 +734,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => ccx.sess().fatal("unknown atomic operation") }; - let sty = &substs.types.get(FnSpace, 0).sty; + let sty = &substs.types[0].sty; if int_type_width_signed(sty, ccx).is_some() { AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order) } else { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 26278e886c29a..d1837883aaeb0 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -180,7 +180,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { impl<'tcx> Instance<'tcx> { pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> Instance<'tcx> { - assert!(substs.regions.as_full_slice().iter().all(|&r| r == ty::ReErased)); + assert!(substs.regions.iter().all(|&r| r == ty::ReErased)); Instance { def: def_id, substs: substs } } pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> { diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 1e90f273301ff..87d0ea0fe81f3 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -125,7 +125,6 @@ use rustc::hir::map::DefPathData; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::TyCtxt; use rustc::ty::item_path::characteristic_def_id_of_type; -use rustc::ty::subst; use std::cmp::Ordering; use std::hash::{Hash, Hasher, SipHasher}; use std::sync::Arc; @@ -488,7 +487,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // DefId, we use the location of the impl after all. if tcx.trait_of_item(instance.def).is_some() { - let self_ty = *instance.substs.types.get(subst::TypeSpace, 0); + let self_ty = instance.substs.types[0]; // This is an implementation of a trait method. return characteristic_def_id_of_type(self_ty).or(Some(instance.def)); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index ebd4a80deb9ab..580882e31dd60 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -28,7 +28,7 @@ use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::subst::{Substs, VecPerParamSpace}; +use rustc::ty::subst::Substs; use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; @@ -560,7 +560,7 @@ fn push_item_name(tcx: TyCtxt, } fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - types: &'tcx VecPerParamSpace>, + types: &[Ty<'tcx>], projections: &[ty::PolyExistentialProjection<'tcx>], output: &mut String) { if types.is_empty() && projections.is_empty() { @@ -569,7 +569,7 @@ fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push('<'); - for &type_parameter in types.as_full_slice() { + for &type_parameter in types { push_unique_type_name(tcx, type_parameter, output); output.push_str(", "); } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 7e592d1b74d7c..6862002ed83b2 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -256,18 +256,13 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. let repr = adt::represent_type(cx, t); - let tps = substs.types.as_full_slice(); - let name = llvm_type_name(cx, def.did, tps); + let name = llvm_type_name(cx, def.did, &substs.types); adt::incomplete_type_of(cx, &repr, &name[..]) } ty::TyClosure(..) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. let repr = adt::represent_type(cx, t); - // Unboxed closures can have substitutions in all spaces - // inherited from their environment, so we use entire - // contents of the VecPerParamSpace to construct the llvm - // name adt::incomplete_type_of(cx, &repr, "closure") } @@ -335,8 +330,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // in *after* placing it into the type cache. This prevents // infinite recursion with recursive struct types. let repr = adt::represent_type(cx, t); - let tps = substs.types.as_full_slice(); - let name = llvm_type_name(cx, def.did, tps); + let name = llvm_type_name(cx, def.did, &substs.types); adt::incomplete_type_of(cx, &repr, &name[..]) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index aec8f8245da5e..f6984f42cab34 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use hir::def_id::DefId; use hir::print as pprust; use middle::resolve_lifetime as rl; use rustc::lint; -use rustc::ty::subst::{TypeSpace, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -207,9 +207,8 @@ pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime) issue_32330)) } - Some(&rl::DefEarlyBoundRegion(space, index, _)) => { + Some(&rl::DefEarlyBoundRegion(index, _)) => { ty::ReEarlyBound(ty::EarlyBoundRegion { - space: space, index: index, name: lifetime.name }) @@ -473,10 +472,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { - assert_eq!(def.space, TypeSpace); regions[def.index as usize] }, |def, substs| { - assert!(def.space == TypeSpace); let i = def.index as usize; // Handle Self first, so we can adjust the index to match the AST. @@ -940,8 +937,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == self.tcx().lang_items.owned_box() { - assert_eq!(substs.types.len(TypeSpace), 1); - return self.tcx().mk_box(*substs.types.get(TypeSpace, 0)); + assert_eq!(substs.types.len(), 1); + return self.tcx().mk_box(substs.types[0]); } decl_ty.subst(self.tcx(), substs) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 087549a2f1c4c..377ca5eaebe30 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,7 +13,6 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; -use rustc::ty::subst; use rustc::ty::{self, ToPolyTraitRef, Ty}; use std::cmp; use syntax::abi::Abi; @@ -204,7 +203,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } - let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1); + let arg_param_ty = trait_ref.substs().types[1]; let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 4cbb2d7f09f02..6bcf21563cb98 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -225,7 +225,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); // This is the only tricky bit of the new way we check implementation methods - // We need to build a set of predicates where only the FnSpace bounds + // We need to build a set of predicates where only the method-level bounds // are from the trait and we assume all other bounds from the implementation // to be previously satisfied. // diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index d1da95f39df40..82545d564a20c 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use rustc::infer; use middle::region; -use rustc::ty::subst::{self, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; use util::nodemap::FnvHashSet; @@ -438,7 +438,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( ty::TyStruct(def, substs) if def.is_phantom_data() => { // PhantomData - behaves identically to T - let ity = *substs.types.get(subst::TypeSpace, 0); + let ity = substs.types[0]; iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index b2af51c12e6bb..b2873bf686578 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,7 +13,7 @@ use intrinsics; use rustc::infer::TypeOrigin; -use rustc::ty::subst::{self, Substs}; +use rustc::ty::subst::Substs; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; use {CrateCtxt, require_same_types}; @@ -70,7 +70,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { let name = token::intern(&format!("P{}", n)); - ccx.tcx.mk_param(subst::FnSpace, n, name) + ccx.tcx.mk_param(n, name) } let tcx = ccx.tcx; @@ -316,7 +316,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { let param = |n| { let name = token::intern(&format!("P{}", n)); - ccx.tcx.mk_param(subst::FnSpace, n, name) + ccx.tcx.mk_param(n, name) }; let tcx = ccx.tcx; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 8aa4ad56aea88..9e0b38fd9fe51 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -12,7 +12,7 @@ use super::probe; use check::{FnCtxt, callee}; use hir::def_id::DefId; -use rustc::ty::subst::{self, Substs}; +use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; @@ -328,18 +328,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // // FIXME -- permit users to manually specify lifetimes Substs::for_item(self.tcx, method.def_id, |def, _| { - if def.space != subst::FnSpace { - substs.region_for_def(def) + if let Some(&r) = substs.regions.get(def.index as usize) { + r } else { self.region_var_for_def(self.span, def) } }, |def, cur_substs| { - if def.space != subst::FnSpace { - substs.type_for_def(def) + if let Some(&ty) = substs.types.get(def.index as usize) { + ty } else if supplied_method_types.is_empty() { self.type_var_for_def(self.span, def, cur_substs) } else { - supplied_method_types[def.index as usize] + supplied_method_types[def.index as usize - substs.types.len()] } }) } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index b057ad3150b51..bcb410e1b8d01 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -13,7 +13,7 @@ use check::FnCtxt; use hir::def::Def; use hir::def_id::DefId; -use rustc::ty::subst::{self, Substs}; +use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; @@ -191,7 +191,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { self.region_var_for_def(span, def) }, |def, substs| { - assert_eq!(def.space, subst::TypeSpace); if def.index == 0 { self_ty } else if let Some(ref input_types) = opt_input_types { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c52bb36911a2a..c306463ec1de0 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,7 +16,7 @@ use super::suggest; use check::{FnCtxt}; use hir::def_id::DefId; use hir::def::Def; -use rustc::ty::subst::{self, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::infer::{InferOk, TypeOrigin}; @@ -519,9 +519,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_ref.substs, m); assert_eq!(m.generics.parent_types as usize, - trait_ref.substs.types.len(subst::TypeSpace)); + trait_ref.substs.types.len()); assert_eq!(m.generics.parent_regions as usize, - trait_ref.substs.regions.len(subst::TypeSpace)); + trait_ref.substs.regions.len()); } // Because this trait derives from a where-clause, it @@ -1220,8 +1220,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - assert_eq!(substs.types.len(subst::FnSpace), 0); - assert_eq!(substs.regions.len(subst::FnSpace), 0); + assert_eq!(substs.types.len(), method.generics.parent_types as usize); + assert_eq!(substs.regions.len(), method.generics.parent_regions as usize); if self.mode == Mode::Path { return impl_ty; @@ -1236,16 +1236,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { xform_self_ty.subst(self.tcx, substs) } else { let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { - if def.space != subst::FnSpace { - substs.region_for_def(def) + if let Some(&r) = substs.regions.get(def.index as usize) { + r } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. ty::ReErased } }, |def, cur_substs| { - if def.space != subst::FnSpace { - substs.type_for_def(def) + if let Some(&ty) = substs.types.get(def.index as usize) { + ty } else { self.type_var_for_def(self.span, def, cur_substs) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8c4ec8453177e..e573655b8c984 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,7 +88,7 @@ use hir::def::{Def, PathResolution}; use hir::def_id::DefId; use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; -use rustc::ty::subst::{self, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; @@ -1333,7 +1333,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { .filter_map(|predicate| { match *predicate { ty::Predicate::Trait(ref data) => { - if data.0.self_ty().is_param(def.space, def.index) { + if data.0.self_ty().is_param(def.index) { Some(data.to_poly_trait_ref()) } else { None @@ -1887,7 +1887,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Registers obligations that all types appearing in `substs` are well-formed. pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr) { - for &ty in substs.types.as_full_slice() { + for &ty in &substs.types { self.register_wf_obligation(ty, expr.span, traits::MiscObligation); } } @@ -4223,20 +4223,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - self.check_path_parameter_count(subst::TypeSpace, - span, - !require_type_space, - &mut type_segment); - self.check_path_parameter_count(subst::FnSpace, - span, - true, - &mut fn_segment); + self.check_path_parameter_count(span, !require_type_space, &mut type_segment); + self.check_path_parameter_count(span, true, &mut fn_segment); let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| { - let i = def.index as usize; - let segment = match def.space { - subst::TypeSpace => type_segment, - subst::FnSpace => fn_segment + let mut i = def.index as usize; + let type_regions = match (type_segment, fn_segment) { + (_, Some((_, generics))) => generics.parent_regions as usize, + (Some((_, generics)), None) => generics.regions.len(), + (None, None) => 0 + }; + + let segment = if i < type_regions { + type_segment + } else { + i -= type_regions; + fn_segment }; let lifetimes = match segment.map(|(s, _)| &s.parameters) { Some(&hir::AngleBracketedParameters(ref data)) => &data.lifetimes[..], @@ -4251,25 +4253,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }, |def, substs| { let mut i = def.index as usize; - let segment = match def.space { - subst::TypeSpace => { - // Handle Self first, so we can adjust the index to match the AST. - match (type_segment, fn_segment) { - (Some((_, generics)), _) | (_, Some((_, generics))) => { - if generics.has_self { - if i == 0 { - return opt_self_ty.unwrap_or_else(|| { - self.type_var_for_def(span, def, substs) - }); - } - i -= 1; - } - } - _ => {} - } - type_segment + let (type_types, has_self) = match (type_segment, fn_segment) { + (_, Some((_, generics))) => { + (generics.parent_types as usize, generics.has_self) } - subst::FnSpace => fn_segment + (Some((_, generics)), None) => { + (generics.types.len(), generics.has_self) + } + (None, None) => (0, false) + }; + + let can_omit = i >= type_types || !require_type_space; + let segment = if i < type_types { + // Handle Self first, so we can adjust the index to match the AST. + if has_self && i == 0 { + return opt_self_ty.unwrap_or_else(|| { + self.type_var_for_def(span, def, substs) + }); + } + i -= has_self as usize; + type_segment + } else { + i -= type_types; + fn_segment }; let types = match segment.map(|(s, _)| &s.parameters) { Some(&hir::AngleBracketedParameters(ref data)) => &data.types[..], @@ -4277,16 +4283,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => &[] }; - let can_omit = def.space != subst::TypeSpace || !require_type_space; - let default = if can_omit && types.len() == 0 { - def.default - } else { - None - }; + let omitted = can_omit && types.is_empty(); if let Some(ast_ty) = types.get(i) { // A provided type parameter. self.to_ty(ast_ty) - } else if let Some(default) = default { + } else if let (false, Some(default)) = (omitted, def.default) { // No type parameter provided, but a default exists. default.subst_spanned(self.tcx, substs, Some(span)) } else { @@ -4323,10 +4324,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. let impl_scheme = self.tcx.lookup_item_type(impl_def_id); - assert_eq!(substs.types.len(subst::TypeSpace), - impl_scheme.generics.types.len()); - assert_eq!(substs.regions.len(subst::TypeSpace), - impl_scheme.generics.regions.len()); let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { @@ -4355,7 +4352,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Report errors if the provided parameters are too few or too many. fn check_path_parameter_count(&self, - space: subst::ParamSpace, span: Span, can_omit: bool, segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) { @@ -4392,7 +4388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Check provided type parameters. let type_defs = segment.map_or(&[][..], |(_, generics)| { - if space == subst::TypeSpace { + if generics.parent.is_none() { &generics.types[generics.has_self as usize..] } else { &generics.types diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index f6ffbc60c2836..859d5ff0543d0 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1445,11 +1445,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for ®ion in substs.regions.as_full_slice() { + for ®ion in &substs.regions { self.sub_regions(origin.clone(), expr_region, region); } - for &ty in substs.types.as_full_slice() { + for &ty in &substs.types { let ty = self.resolve_type(ty); self.type_must_outlive(origin.clone(), ty, expr_region); } @@ -1575,11 +1575,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if env_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); - for &component_ty in projection_ty.trait_ref.substs.types.as_full_slice() { + for &component_ty in &projection_ty.trait_ref.substs.types { self.type_must_outlive(origin.clone(), component_ty, region); } - for &r in projection_ty.trait_ref.substs.regions.as_full_slice() { + for &r in &projection_ty.trait_ref.substs.regions { self.sub_regions(origin.clone(), region, r); } @@ -1597,7 +1597,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { let unique_bound = env_bounds[0]; debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); - if projection_ty.trait_ref.substs.regions.as_full_slice() + if projection_ty.trait_ref.substs.regions .iter() .any(|r| env_bounds.contains(r)) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ef5e1a26f4150..7ed4b2bcb1918 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -14,7 +14,6 @@ use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; -use rustc::ty::subst; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -459,9 +458,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let mut constrained_parameters: HashSet<_> = variances.types - .iter_enumerated() - .filter(|&(_, _, &variance)| variance != ty::Bivariant) - .map(|(_, index, _)| self.param_ty(ast_generics, index)) + .iter().enumerate() + .filter(|&(_, &variance)| variance != ty::Bivariant) + .map(|(index, _)| self.param_ty(ast_generics, index)) .map(|p| Parameter::Type(p)) .collect(); @@ -469,9 +468,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { None, &mut constrained_parameters); - for (space, index, _) in variances.types.iter_enumerated() { - assert_eq!(space, subst::TypeSpace); - + for (index, _) in variances.types.iter().enumerate() { let param_ty = self.param_ty(ast_generics, index); if constrained_parameters.contains(&Parameter::Type(param_ty)) { continue; @@ -480,9 +477,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.report_bivariance(span, param_ty.name); } - for (space, index, &variance) in variances.regions.iter_enumerated() { - assert_eq!(space, subst::TypeSpace); - + for (index, &variance) in variances.regions.iter().enumerate() { if variance != ty::Bivariant { continue; } @@ -495,7 +490,6 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn param_ty(&self, ast_generics: &hir::Generics, index: usize) -> ty::ParamTy { ty::ParamTy { - space: subst::TypeSpace, idx: index as u32, name: ast_generics.ty_params[index].name } @@ -603,7 +597,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait impl: take implied bounds from all types that // appear in the trait reference. let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); - trait_ref.substs.types.as_full_slice().to_vec() + trait_ref.substs.types.to_vec() } None => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 6a475864f3b7d..cfc1292c34b78 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -103,13 +103,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } let free_substs = fcx.parameter_environment.free_substs; - for (space, i, r) in free_substs.regions.iter_enumerated() { + for (i, r) in free_substs.regions.iter().enumerate() { match *r { ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. }) => { let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion { - space: space, index: i as u32, name: name, }); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 17a84e98e61e2..4a1e401f9820f 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -17,7 +17,7 @@ use hir::def_id::DefId; use middle::lang_items::UnsizeTraitLangItem; -use rustc::ty::subst::{self, Subst}; +use rustc::ty::subst::Subst; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let source = tcx.lookup_item_type(impl_did).ty; let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); - let target = *trait_ref.substs.types.get(subst::TypeSpace, 1); + let target = trait_ref.substs.types[1]; debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 939f8ac50a6c6..ed406b9379e35 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -65,7 +65,7 @@ use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; -use rustc::ty::subst::{Substs, FnSpace, ParamSpace, TypeSpace}; +use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; @@ -473,10 +473,10 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { results.extend(self.predicates.iter().filter(|predicate| { match **predicate { ty::Predicate::Trait(ref data) => { - data.skip_binder().self_ty().is_param(def.space, def.index) + data.skip_binder().self_ty().is_param(def.index) } ty::Predicate::TypeOutlives(ref data) => { - data.skip_binder().0.is_param(def.space, def.index) + data.skip_binder().0.is_param(def.index) } ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | @@ -571,7 +571,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generics = generics_of_def_id(ccx, def_id); let ty_generic_predicates = - ty_generic_predicates(ccx, FnSpace, &sig.generics, ty_generics.parent, vec![], false); + ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); let (fty, explicit_self_category) = { let anon_scope = match container { @@ -752,7 +752,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let def_id = ccx.tcx.map.local_def_id(it.id); let ty_generics = generics_of_def_id(ccx, def_id); let mut ty_predicates = - ty_generic_predicates(ccx, TypeSpace, generics, None, vec![], false); + ty_generic_predicates(ccx, generics, None, vec![], false); debug!("convert: impl_bounds={:?}", ty_predicates); @@ -1346,7 +1346,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) // add in the explicit where-clauses let mut trait_predicates = - ty_generic_predicates(ccx, TypeSpace, generics, None, base_predicates, true); + ty_generic_predicates(ccx, generics, None, base_predicates, true); let assoc_predicates = predicates_for_associated_types(ccx, generics, @@ -1419,31 +1419,33 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut allow_defaults = false; let no_generics = hir::Generics::empty(); - let (space, ast_generics) = match node { + let ast_generics = match node { NodeTraitItem(item) => { match item.node { - MethodTraitItem(ref sig, _) => (FnSpace, &sig.generics), - _ => (FnSpace, &no_generics) + MethodTraitItem(ref sig, _) => &sig.generics, + _ => &no_generics } } NodeImplItem(item) => { match item.node { - ImplItemKind::Method(ref sig, _) => (FnSpace, &sig.generics), - _ => (FnSpace, &no_generics) + ImplItemKind::Method(ref sig, _) => &sig.generics, + _ => &no_generics } } NodeItem(item) => { match item.node { - ItemFn(_, _, _, _, ref generics, _) => (FnSpace, generics), - ItemImpl(_, _, ref generics, _, _, _) => (TypeSpace, generics), + ItemFn(_, _, _, _, ref generics, _) | + ItemImpl(_, _, ref generics, _, _, _) => generics, + ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) => { allow_defaults = true; - (TypeSpace, generics) + generics } + ItemTrait(_, ref generics, _, _) => { // Add in the self type parameter. // @@ -1454,7 +1456,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let parent = ccx.tcx.map.get_parent(param_id); let def = ty::TypeParameterDef { - space: TypeSpace, index: 0, name: keywords::SelfType.name(), def_id: tcx.map.local_def_id(param_id), @@ -1466,20 +1467,21 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, opt_self = Some(def); allow_defaults = true; - (TypeSpace, generics) + generics } - _ => (TypeSpace, &no_generics) + + _ => &no_generics } } NodeForeignItem(item) => { match item.node { - ForeignItemStatic(..) => (TypeSpace, &no_generics), - ForeignItemFn(_, ref generics) => (FnSpace, generics) + ForeignItemStatic(..) => &no_generics, + ForeignItemFn(_, ref generics) => generics } } - _ => (TypeSpace, &no_generics) + _ => &no_generics }; let has_self = opt_self.is_some(); @@ -1491,15 +1493,14 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, assert_eq!(generics.parent_types, 0); assert_eq!(has_self, false); parent_has_self = generics.has_self; - (generics.regions.len(), generics.types.len()) + (generics.regions.len() as u32, generics.types.len() as u32) }); let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); let regions = early_lifetimes.iter().enumerate().map(|(i, l)| { ty::RegionParameterDef { name: l.lifetime.name, - space: space, - index: i as u32, + index: parent_regions + i as u32, def_id: tcx.map.local_def_id(l.lifetime.id), bounds: l.bounds.iter().map(|l| { ast_region_to_region(tcx, l) @@ -1509,8 +1510,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Now create the real type parameters. let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { - let i = has_self as u32 + i as u32; - get_or_create_type_parameter_def(ccx, ast_generics, space, i, p, allow_defaults) + let i = parent_types + has_self as u32 + i as u32; + get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults) }); let types: Vec<_> = opt_self.into_iter().chain(types).collect(); @@ -1631,15 +1632,15 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let def_id = ccx.tcx.map.local_def_id(it.id); let no_generics = hir::Generics::empty(); - let (space, generics) = match it.node { - hir::ItemFn(_, _, _, _, ref generics, _) => (FnSpace, generics), + let generics = match it.node { + hir::ItemFn(_, _, _, _, ref generics, _) | hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => (TypeSpace, generics), - _ => (TypeSpace, &no_generics) + hir::ItemStruct(_, ref generics) => generics, + _ => &no_generics }; - let predicates = ty_generic_predicates(ccx, space, generics, None, vec![], false); + let predicates = ty_generic_predicates(ccx, generics, None, vec![], false); let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, predicates.clone()); assert!(prev_predicates.is_none()); @@ -1658,12 +1659,12 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, type_scheme_of_def_id(ccx, def_id); let no_generics = hir::Generics::empty(); - let (space, generics) = match it.node { - hir::ForeignItemFn(_, ref generics) => (FnSpace, generics), - hir::ForeignItemStatic(..) => (TypeSpace, &no_generics) + let generics = match it.node { + hir::ForeignItemFn(_, ref generics) => generics, + hir::ForeignItemStatic(..) => &no_generics }; - let predicates = ty_generic_predicates(ccx, space, generics, None, vec![], false); + let predicates = ty_generic_predicates(ccx, generics, None, vec![], false); let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); assert!(prev_predicates.is_none()); } @@ -1733,7 +1734,6 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>( } fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - space: ParamSpace, ast_generics: &hir::Generics, parent: Option, super_predicates: Vec>, @@ -1741,6 +1741,13 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, -> ty::GenericPredicates<'tcx> { let tcx = ccx.tcx; + let (parent_regions, parent_types) = parent.map_or((0, 0), |def_id| { + let generics = generics_of_def_id(ccx, def_id); + assert_eq!(generics.parent, None); + assert_eq!(generics.parent_regions, 0); + assert_eq!(generics.parent_types, 0); + (generics.regions.len() as u32, generics.types.len() as u32) + }); let ref base_predicates = match parent { Some(def_id) => { assert_eq!(super_predicates, vec![]); @@ -1758,8 +1765,8 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). for (index, param) in ast_generics.ty_params.iter().enumerate() { - let index = has_self as u32 + index as u32; - let param_ty = ty::ParamTy::new(space, index, param.name).to_ty(ccx.tcx); + let index = parent_types + has_self as u32 + index as u32; + let param_ty = ty::ParamTy::new(index, param.name).to_ty(ccx.tcx); let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), param_ty, ¶m.bounds, @@ -1774,10 +1781,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // have to be careful to only iterate over early-bound regions. let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); for (index, param) in early_lifetimes.iter().enumerate() { - let index = index as u32; + let index = parent_regions + index as u32; let region = ty::ReEarlyBound(ty::EarlyBoundRegion { - space: space, index: index, name: param.lifetime.name }); @@ -1852,7 +1858,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ast_generics: &hir::Generics, - space: ParamSpace, index: u32, param: &hir::TyParam, allow_defaults: bool) @@ -1885,7 +1890,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } let def = ty::TypeParameterDef { - space: space, index: index, name: param.name, def_id: ccx.tcx.map.local_def_id(param.id), @@ -1900,8 +1904,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); - debug!("get_or_create_type_parameter_def: def for type param: {:?}, {:?}", - def, space); + debug!("get_or_create_type_parameter_def: def for type param: {:?}", def); def } @@ -2190,9 +2193,10 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .collect(); for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() { - let region = ty::EarlyBoundRegion { space: TypeSpace, - index: index as u32, - name: lifetime_def.lifetime.name }; + let region = ty::EarlyBoundRegion { + index: index as u32, + name: lifetime_def.lifetime.name + }; if lifetimes_in_associated_types.contains(®ion) && // (*) !input_parameters.contains(&ctp::Parameter::Region(region)) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 95ddb59c0e28a..536fa629fd611 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -16,7 +16,7 @@ use dep_graph::DepTrackingMapConfig; use hir::def_id::DefId; use middle::resolve_lifetime as rl; -use rustc::ty::subst::{self, ParamSpace, Substs}; +use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::ItemVariances; use rustc::hir::map as hir_map; @@ -144,7 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let tcx = self.terms_cx.tcx; assert!(is_lifetime(&tcx.map, param_id)); match tcx.named_region_map.defs.get(¶m_id) { - Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id)) + Some(&rl::DefEarlyBoundRegion(_, lifetime_decl_id)) => lifetime_decl_id, Some(_) => bug!("should not encounter non early-bound cases"), @@ -210,7 +210,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { param_def_id: DefId, item_def_id: DefId, kind: ParamKind, - space: ParamSpace, index: usize) -> VarianceTermPtr<'a> { assert_eq!(param_def_id.krate, item_def_id.krate); @@ -226,8 +225,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // variance already inferred, just look it up. let variances = self.tcx().item_variances(item_def_id); let variance = match kind { - TypeParam => *variances.types.get(space, index), - RegionParam => *variances.regions.get(space, index), + TypeParam => variances.types[index], + RegionParam => variances.regions[index], }; self.constant_term(variance) } @@ -401,8 +400,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyParam(ref data) => { - assert_eq!(data.space, subst::TypeSpace); assert_eq!(generics.parent, None); + assert!((data.idx as usize) < generics.types.len()); let def_id = generics.types[data.idx as usize].def_id; let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); match self.terms_cx.inferred_map.get(&node_id) { @@ -450,8 +449,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { for p in type_param_defs { let variance_decl = - self.declared_variance(p.def_id, def_id, TypeParam, - p.space, p.index as usize); + self.declared_variance(p.def_id, def_id, TypeParam, p.index as usize); let variance_i = self.xform(variance, variance_decl); let substs_ty = substs.type_for_def(p); debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}", @@ -461,8 +459,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { for p in region_param_defs { let variance_decl = - self.declared_variance(p.def_id, def_id, - RegionParam, p.space, p.index as usize); + self.declared_variance(p.def_id, def_id, RegionParam, p.index as usize); let variance_i = self.xform(variance, variance_decl); let substs_r = substs.region_for_def(p); self.add_constraints_from_region(generics, substs_r, variance_i); @@ -490,8 +487,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance: VarianceTermPtr<'a>) { match region { ty::ReEarlyBound(ref data) => { - assert_eq!(data.space, subst::TypeSpace); assert_eq!(generics.parent, None); + assert!((data.index as usize) < generics.regions.len()); let def_id = generics.regions[data.index as usize].def_id; let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); if self.is_to_be_inferred(node_id) { diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 9048d892b09d2..d3b63119bcb32 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -16,7 +16,6 @@ //! inferred is then written into the `variance_map` in the tcx. use rustc::ty; -use rustc::ty::subst; use std::rc::Rc; use super::constraints::*; @@ -110,41 +109,27 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { while index < num_inferred { let item_id = inferred_infos[index].item_id; - let (mut rt, mut rf) = (vec![], vec![]); - let (mut tt, mut tf) = (vec![], vec![]); + let mut item_variances = ty::ItemVariances::empty(); while index < num_inferred && inferred_infos[index].item_id == item_id { let info = &inferred_infos[index]; let variance = solutions[index]; - debug!("Index {} Info {} / {:?} / {:?} Variance {:?}", - index, info.index, info.kind, info.space, variance); + debug!("Index {} Info {} / {:?} Variance {:?}", + index, info.index, info.kind, variance); match info.kind { TypeParam => { - let types = match info.space { - subst::TypeSpace => &mut tt, - subst::FnSpace => &mut tf - }; - assert_eq!(types.len(), info.index); - types.push(variance); + assert_eq!(item_variances.types.len(), info.index); + item_variances.types.push(variance); } RegionParam => { - let regions = match info.space { - subst::TypeSpace => &mut rt, - subst::FnSpace => &mut rf - }; - assert_eq!(regions.len(), info.index); - regions.push(variance); + assert_eq!(item_variances.regions.len(), info.index); + item_variances.regions.push(variance); } } index += 1; } - let item_variances = ty::ItemVariances { - regions: subst::VecPerParamSpace::new(rt, rf), - types: subst::VecPerParamSpace::new(tt, tf) - }; - debug!("item_id={} item_variances={:?}", item_id, item_variances); diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 9dc38bb195c14..d30cbc8f117cf 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -21,7 +21,6 @@ use arena::TypedArena; use dep_graph::DepTrackingMapConfig; -use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace}; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::ItemVariances; use std::fmt; @@ -86,7 +85,6 @@ pub enum ParamKind { pub struct InferredInfo<'a> { pub item_id: ast::NodeId, pub kind: ParamKind, - pub space: ParamSpace, pub index: usize, pub param_id: ast::NodeId, pub term: VarianceTermPtr<'a>, @@ -166,15 +164,15 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { for (i, p) in generics.lifetimes.iter().enumerate() { let id = p.lifetime.id; - self.add_inferred(item_id, RegionParam, TypeSpace, i, id); + self.add_inferred(item_id, RegionParam, i, id); } if has_self { - self.add_inferred(item_id, TypeParam, TypeSpace, 0, item_id); + self.add_inferred(item_id, TypeParam, 0, item_id); } for (i, p) in generics.ty_params.iter().enumerate() { let i = has_self as usize + i; - self.add_inferred(item_id, TypeParam, TypeSpace, i, p.id); + self.add_inferred(item_id, TypeParam, i, p.id); } // If this item has no type or lifetime parameters, @@ -197,15 +195,13 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { fn add_inferred(&mut self, item_id: ast::NodeId, kind: ParamKind, - space: ParamSpace, index: usize, param_id: ast::NodeId) { let inf_index = InferredIndex(self.inferred_infos.len()); let term = self.arena.alloc(InferredTerm(inf_index)); - let initial_variance = self.pick_initial_variance(item_id, space, index); + let initial_variance = self.pick_initial_variance(item_id, index); self.inferred_infos.push(InferredInfo { item_id: item_id, kind: kind, - space: space, index: index, param_id: param_id, term: term, @@ -216,33 +212,23 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { debug!("add_inferred(item_path={}, \ item_id={}, \ kind={:?}, \ - space={:?}, \ index={}, \ param_id={}, \ inf_index={:?}, \ initial_variance={:?})", self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)), - item_id, kind, space, index, param_id, inf_index, + item_id, kind, index, param_id, inf_index, initial_variance); } fn pick_initial_variance(&self, item_id: ast::NodeId, - space: ParamSpace, index: usize) -> ty::Variance { - match space { - FnSpace => { - ty::Bivariant - } - - TypeSpace => { - match self.lang_items.iter().find(|&&(n, _)| n == item_id) { - Some(&(_, ref variances)) => variances[index], - None => ty::Bivariant - } - } + match self.lang_items.iter().find(|&&(n, _)| n == item_id) { + Some(&(_, ref variances)) => variances[index], + None => ty::Bivariant } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 427468069d04e..013433336a1d5 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -388,8 +388,6 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } ty::TypeTraitItem(ref assoc_ty) => { let did = assoc_ty.def_id; - // Not sure the choice of ParamSpace actually matters here, - // because an associated type won't have generics on the LHS let typedef = clean::Typedef { type_: assoc_ty.ty.unwrap().clean(cx), generics: clean::Generics { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 90288b17dfcce..75d21399f05e6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; -use rustc::ty::subst::{self, Substs, VecPerParamSpace}; +use rustc::ty::subst::Substs; use rustc::ty; use rustc::middle::stability; @@ -82,12 +82,6 @@ impl, U> Clean> for [T] { } } -impl, U> Clean> for VecPerParamSpace { - fn clean(&self, cx: &DocContext) -> VecPerParamSpace { - self.map(|x| x.clean(cx)) - } -} - impl, U> Clean for P { fn clean(&self, cx: &DocContext) -> U { (**self).clean(cx) @@ -632,12 +626,8 @@ impl Clean for hir::TyParamBound { fn external_path_params(cx: &DocContext, trait_did: Option, has_self: bool, bindings: Vec, substs: &Substs) -> PathParameters { - let lifetimes = substs.regions.get_slice(subst::TypeSpace) - .iter() - .filter_map(|v| v.clean(cx)) - .collect(); - let types = substs.types.get_slice(subst::TypeSpace); - let types = types[has_self as usize..].to_vec(); + let lifetimes = substs.regions.iter().filter_map(|v| v.clean(cx)).collect(); + let types = substs.types[has_self as usize..].to_vec(); match (trait_did, cx.tcx_opt()) { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C @@ -731,7 +721,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { let path = external_path(cx, &tcx.item_name(self.def_id).as_str(), Some(self.def_id), true, vec![], self.substs); - debug!("ty::TraitRef\n substs.types(TypeSpace): {:?}\n", + debug!("ty::TraitRef\n substs.types: {:?}\n", &self.input_types()[1..]); // collect any late bound regions @@ -769,9 +759,9 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { impl<'tcx> Clean>> for Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { let mut v = Vec::new(); - v.extend(self.regions.as_full_slice().iter().filter_map(|r| r.clean(cx)) + v.extend(self.regions.iter().filter_map(|r| r.clean(cx)) .map(RegionBound)); - v.extend(self.types.as_full_slice().iter().map(|t| TraitBound(PolyTrait { + v.extend(self.types.iter().map(|t| TraitBound(PolyTrait { trait_: t.clean(cx), lifetimes: vec![] }, hir::TraitBoundModifier::None))); @@ -1637,7 +1627,7 @@ impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> { fn fold_lifetime(&mut self, lt: hir::Lifetime) -> hir::Lifetime { let def = self.tcx.named_region_map.defs.get(<.id).cloned(); match def { - Some(DefEarlyBoundRegion(_, _, node_id)) | + Some(DefEarlyBoundRegion(_, node_id)) | Some(DefLateBoundRegion(_, node_id)) | Some(DefFreeRegion(_, node_id)) => { if let Some(lt) = self.lt_substs.get(&node_id).cloned() { diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index 9aa4d29c4ecf7..5539a26d2a170 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -20,12 +20,12 @@ trait Trait<'a> { } #[rustc_variance] -struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[+];[]], regions=[[-];[]]) +struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[+], regions=[-]) field: (T, &'a ()) } #[rustc_variance] -struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[[o];[]], regions=[[o];[]]) +struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[o], regions=[o]) field: >::Type } diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index 3c8b27f965a61..2f422bfd38cc7 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -18,7 +18,7 @@ use std::cell::Cell; // For better or worse, associated types are invariant, and hence we // get an invariant result for `'a`. #[rustc_variance] -struct Foo<'a> { //~ ERROR regions=[[o];[]] +struct Foo<'a> { //~ ERROR regions=[o] x: Box &'a i32 + 'static> } diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs index ae5a8674f446c..99416057b2540 100644 --- a/src/test/compile-fail/variance-region-bounds.rs +++ b/src/test/compile-fail/variance-region-bounds.rs @@ -13,11 +13,11 @@ #![feature(rustc_attrs)] #[rustc_variance] -trait Foo: 'static { //~ ERROR types=[[o];[]] +trait Foo: 'static { //~ ERROR types=[o] } #[rustc_variance] -trait Bar { //~ ERROR types=[[o, o];[]] +trait Bar { //~ ERROR types=[o, o] fn do_it(&self) where T: 'static; } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 93d3d2773149e..78591063de8ab 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -16,7 +16,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[]] +struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -] x: &'a isize, y: &'b [isize], c: &'c str @@ -25,7 +25,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[]] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[]] +struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), c: extern "Rust" fn(&'c str), @@ -34,7 +34,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[]] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[]] +struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o] x: &'a mut &'b isize, } @@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[]] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[]] +struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o] x: extern "Rust" fn(&'a mut &'b isize), } @@ -52,14 +52,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[]] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b:'a> { //~ ERROR regions=[[-, o];[]] +struct Test6<'a, 'b:'a> { //~ ERROR regions=[-, o] x: &'a mut extern "Rust" fn(&'b isize), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR regions=[[*];[]] +struct Test7<'a> { //~ ERROR regions=[*] //~^ ERROR parameter `'a` is never used x: isize } @@ -67,7 +67,7 @@ struct Test7<'a> { //~ ERROR regions=[[*];[]] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[]] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index eeb981b707e31..d8af30da163bf 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -15,7 +15,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *] //~^ ERROR parameter `'d` is never used Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), @@ -23,25 +23,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[]] } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[*, o, -, +] //~^ ERROR parameter `'w` is never used f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[o, o, *] //~^ ERROR parameter `'c` is never used f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[o, -, *] //~^ ERROR parameter `'c` is never used f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 860dd6deefd5b..150a1aa56fe72 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -15,48 +15,48 @@ // influence variance. #[rustc_variance] -trait Getter { //~ ERROR types=[[o, o];[]] +trait Getter { //~ ERROR types=[o, o] fn get(&self) -> T; } #[rustc_variance] -trait Setter { //~ ERROR types=[[o, o];[]] +trait Setter { //~ ERROR types=[o, o] fn get(&self, T); } #[rustc_variance] -struct TestStruct> { //~ ERROR types=[[+, +];[]] +struct TestStruct> { //~ ERROR types=[+, +] t: T, u: U } #[rustc_variance] -enum TestEnum> {//~ ERROR types=[[*, +];[]] +enum TestEnum> {//~ ERROR types=[*, +] //~^ ERROR parameter `U` is never used Foo(T) } #[rustc_variance] -trait TestTrait> { //~ ERROR types=[[o, o, o];[]] +trait TestTrait> { //~ ERROR types=[o, o, o] fn getter(&self, u: U) -> T; } #[rustc_variance] -trait TestTrait2 : Getter { //~ ERROR types=[[o, o];[]] +trait TestTrait2 : Getter { //~ ERROR types=[o, o] } #[rustc_variance] -trait TestTrait3 { //~ ERROR types=[[o, o];[]] +trait TestTrait3 { //~ ERROR types=[o, o] fn getter>(&self); } #[rustc_variance] -struct TestContraStruct> { //~ ERROR types=[[*, +];[]] +struct TestContraStruct> { //~ ERROR types=[*, +] //~^ ERROR parameter `U` is never used t: T } #[rustc_variance] -struct TestBox+Setter> { //~ ERROR types=[[*, +];[]] +struct TestBox+Setter> { //~ ERROR types=[*, +] //~^ ERROR parameter `U` is never used t: T } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index b37007a6d34e4..4244b0e1d8b8b 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -21,7 +21,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[[-];[]] +struct TOption<'a> { //~ ERROR regions=[-] v: Option>, } diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index 8eb96814fa8f0..c47710d6d376d 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -14,46 +14,46 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct TestImm { //~ ERROR types=[[+, +];[]] +struct TestImm { //~ ERROR types=[+, +] x: A, y: B, } #[rustc_variance] -struct TestMut { //~ ERROR types=[[+, o];[]] +struct TestMut { //~ ERROR types=[+, o] x: A, y: &'static mut B, } #[rustc_variance] -struct TestIndirect { //~ ERROR types=[[+, o];[]] +struct TestIndirect { //~ ERROR types=[+, o] m: TestMut } #[rustc_variance] -struct TestIndirect2 { //~ ERROR types=[[o, o];[]] +struct TestIndirect2 { //~ ERROR types=[o, o] n: TestMut, m: TestMut } #[rustc_variance] -trait Getter { //~ ERROR types=[[o, o];[]] +trait Getter { //~ ERROR types=[o, o] fn get(&self) -> A; } #[rustc_variance] -trait Setter { //~ ERROR types=[[o, o];[]] +trait Setter { //~ ERROR types=[o, o] fn set(&mut self, a: A); } #[rustc_variance] -trait GetterSetter { //~ ERROR types=[[o, o];[]] +trait GetterSetter { //~ ERROR types=[o, o] fn get(&self) -> A; fn set(&mut self, a: A); } #[rustc_variance] -trait GetterInTypeBound { //~ ERROR types=[[o, o];[]] +trait GetterInTypeBound { //~ ERROR types=[o, o] // Here, the use of `A` in the method bound *does* affect // variance. Think of it as if the method requested a dictionary // for `T:Getter`. Since this dictionary is an input, it is @@ -63,12 +63,12 @@ trait GetterInTypeBound { //~ ERROR types=[[o, o];[]] } #[rustc_variance] -trait SetterInTypeBound { //~ ERROR types=[[o, o];[]] +trait SetterInTypeBound { //~ ERROR types=[o, o] fn do_it>(&self); } #[rustc_variance] -struct TestObject { //~ ERROR types=[[o, o];[]] +struct TestObject { //~ ERROR types=[o, o] n: Box+Send>, m: Box+Send>, } diff --git a/src/test/compile-fail/variance-types.rs b/src/test/compile-fail/variance-types.rs index 791b56caea02b..d5164412358fc 100644 --- a/src/test/compile-fail/variance-types.rs +++ b/src/test/compile-fail/variance-types.rs @@ -17,32 +17,32 @@ use std::cell::Cell; // not considered bivariant. #[rustc_variance] -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[[o, o];[]], regions=[[-];[]] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[o, o], regions=[-] t: &'a mut (A,B) } #[rustc_variance] -struct InvariantCell { //~ ERROR types=[[o];[]] +struct InvariantCell { //~ ERROR types=[o] t: Cell } #[rustc_variance] -struct InvariantIndirect { //~ ERROR types=[[o];[]] +struct InvariantIndirect { //~ ERROR types=[o] t: InvariantCell } #[rustc_variance] -struct Covariant { //~ ERROR types=[[+];[]] +struct Covariant { //~ ERROR types=[+] t: A, u: fn() -> A } #[rustc_variance] -struct Contravariant { //~ ERROR types=[[-];[]] +struct Contravariant { //~ ERROR types=[-] t: fn(A) } #[rustc_variance] -enum Enum { //~ ERROR types=[[+, -, o];[]] +enum Enum { //~ ERROR types=[+, -, o] Foo(Covariant), Bar(Contravariant), Zed(Covariant,Contravariant) diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index b116d9c3c41cf..f93447b642a20 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + fn main() { let a = 0; { @@ -25,7 +27,7 @@ fn main() { // StorageLive(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25 // StorageLive(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24 // tmp2 = var0; // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp1 = std::prelude::v1::Some(tmp2,); // scope 1 at storage_ranges.rs:14:18: 14:25 +// tmp1 = std::option::Option::Some(tmp2,); // scope 1 at storage_ranges.rs:14:18: 14:25 // var1 = &tmp1; // scope 1 at storage_ranges.rs:14:17: 14:25 // StorageDead(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24 // tmp0 = (); // scope 2 at storage_ranges.rs:13:5: 15:6 From 879637f7b000c34f1c2aa6aa48d7c5bedcb55e0b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 16 Aug 2016 10:27:07 +1200 Subject: [PATCH 072/768] Review changes --- src/librustdoc/html/render.rs | 103 +++++++++++++-------- src/librustdoc/html/static/rustdoc.css | 9 +- src/librustdoc/html/static/styles/main.css | 2 +- src/test/rustdoc/assoc-types.rs | 2 + src/test/rustdoc/issue-19190.rs | 3 + src/test/rustdoc/issue-21092.rs | 1 + src/test/rustdoc/issue-25001.rs | 3 + src/test/rustdoc/src-links.rs | 2 + src/test/rustdoc/structfields.rs | 6 ++ 9 files changed, 92 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 51068d5648e4d..d654429146d83 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2036,14 +2036,18 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item) -> fmt::Result { let name = m.name.as_ref().unwrap(); - let id = derive_id(format!("{}.{}", item_type(m), name)); - write!(w, "

", + let item_type = item_type(m); + let id = derive_id(format!("{}.{}", item_type, name)); + let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); + write!(w, "

\ +

")?; + write!(w, "

")?; document(w, cx, m)?; Ok(()) } @@ -2282,12 +2286,19 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if fields.peek().is_some() { write!(w, "

Fields

")?; for (field, ty) in fields { - write!(w, " -
+ let id = derive_id(format!("{}.{}", + ItemType::StructField, + field.name.as_ref().unwrap())); + let ns_id = derive_id(format!("{}.{}", + field.name.as_ref().unwrap(), + ItemType::StructField.name_space())); + write!(w, " + ", + ", item_type = ItemType::StructField, - name_space = ItemType::StructField.name_space(), + id = id, + ns_id = ns_id, stab = field.stability_class(), name = field.name.as_ref().unwrap(), ty = ty)?; @@ -2356,10 +2367,16 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if !e.variants.is_empty() { write!(w, "

Variants

\n")?; for variant in &e.variants { - write!(w, "\ - {name}", - item_type = ItemType::Variant, - name_space = ItemType::Variant.name_space(), + let id = derive_id(format!("{}.{}", + ItemType::Variant, + variant.name.as_ref().unwrap())); + let ns_id = derive_id(format!("{}.{}", + variant.name.as_ref().unwrap(), + ItemType::Variant.name_space())); + write!(w, "\ + ")?; + write!(w, "")?; document(w, cx, variant)?; use clean::{Variant, StructVariant}; @@ -2383,14 +2400,21 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, for field in &s.fields { use clean::StructFieldItem; if let StructFieldItem(ref ty) = field.inner { + let id = derive_id(format!("variant.{}.field.{}", + variant.name.as_ref().unwrap(), + field.name.as_ref().unwrap())); + let ns_id = derive_id(format!("{}.{}.{}.{}", + variant.name.as_ref().unwrap(), + ItemType::Variant.name_space(), + field.name.as_ref().unwrap(), + ItemType::StructField.name_space())); write!(w, "\ - \ - {f}: {t}", - v = variant.name.as_ref().unwrap(), + id='{id}'>\ + ", + id = id, + ns_id = ns_id, f = field.name.as_ref().unwrap(), - vns = ItemType::Variant.name_space(), - fns = ItemType::StructField.name_space(), t = *ty)?; document(w, cx, field)?; write!(w, "")?; @@ -2606,10 +2630,10 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } } - fn doctraititem(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, - link: AssocItemLink, render_static: bool, - is_default_item: bool, outer_version: Option<&str>, - trait_: Option<&clean::Trait>) -> fmt::Result { + fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, + link: AssocItemLink, render_static: bool, + is_default_item: bool, outer_version: Option<&str>, + trait_: Option<&clean::Trait>) -> fmt::Result { let item_type = item_type(item); let name = item.name.as_ref().unwrap(); @@ -2624,42 +2648,47 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi // Only render when the method is not static or we allow static methods if !is_static || render_static { let id = derive_id(format!("{}.{}", item_type, name)); + let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; - write!(w, "", name, item_type.name_space())?; + write!(w, "

\n")?; + write!(w, "

\n")?; } } clean::TypedefItem(ref tydef, _) => { let id = derive_id(format!("{}.{}", ItemType::AssociatedType, name)); + let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; - write!(w, "", name, item_type.name_space())?; + write!(w, "

\n")?; + write!(w, "

\n")?; } clean::AssociatedConstItem(ref ty, ref default) => { let id = derive_id(format!("{}.{}", item_type, name)); + let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; - write!(w, "", name, item_type.name_space())?; + write!(w, "

\n")?; + write!(w, "

\n")?; } clean::ConstantItem(ref c) => { let id = derive_id(format!("{}.{}", item_type, name)); + let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; - write!(w, "", name, item_type.name_space())?; + write!(w, "

\n")?; + write!(w, "

\n")?; } clean::AssociatedTypeItem(ref bounds, ref default) => { let id = derive_id(format!("{}.{}", item_type, name)); + let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; - write!(w, "", name, item_type.name_space())?; + write!(w, "

\n")?; + write!(w, "
\n")?; } clean::StrippedItem(..) => return Ok(()), _ => panic!("can't make docs for trait item with name {:?}", item.name) @@ -2698,8 +2727,8 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "
")?; for trait_item in &i.inner_impl().items { - doctraititem(w, cx, trait_item, link, render_header, - false, outer_version, trait_)?; + doc_impl_item(w, cx, trait_item, link, render_header, + false, outer_version, trait_)?; } fn render_default_items(w: &mut fmt::Formatter, @@ -2716,8 +2745,8 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi let did = i.trait_.as_ref().unwrap().def_id().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods); - doctraititem(w, cx, trait_item, assoc_link, render_static, true, - outer_version, None)?; + doc_impl_item(w, cx, trait_item, assoc_link, render_static, true, + outer_version, None)?; } Ok(()) } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index de0457592fc88..c97cacd10c381 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -284,7 +284,7 @@ h3.impl > .out-of-band { font-size: 21px; } -h4 > code, h3 > code { +h4 > code, h3 > code, invisible > code { position: inherit; } @@ -292,6 +292,12 @@ h4 > code, h3 > code { z-index: 5; } +.invisible { + background: rgba(0, 0, 0, 0); + width: 100%; + display: inline-block; +} + .content .in-band { margin: 0px; padding: 0px; @@ -660,6 +666,7 @@ span.since { :target > code { background: #FDFFD3; + opacity: 1; } /* Media Queries */ diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index aee6d15b7ca37..c64fb1b67f3d7 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -26,7 +26,7 @@ h1.fqn { h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { border-bottom-color: #DDDDDD; } -.in-band, code { +.in-band { background-color: white; } diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs index d5047ade062dc..e5485c356c292 100644 --- a/src/test/rustdoc/assoc-types.rs +++ b/src/test/rustdoc/assoc-types.rs @@ -13,7 +13,9 @@ // @has assoc_types/trait.Index.html pub trait Index { // @has - '//*[@id="associatedtype.Output"]//code' 'type Output: ?Sized' + // @has - '//*[@id="Output.t"]//code' 'type Output: ?Sized' type Output: ?Sized; + // @has - '//*[@id="index.v"]//code' 'fn index' // @has - '//*[@id="tymethod.index"]//code' \ // "fn index<'a>(&'a self, index: I) -> &'a Self::Output" fn index<'a>(&'a self, index: I) -> &'a Self::Output; diff --git a/src/test/rustdoc/issue-19190.rs b/src/test/rustdoc/issue-19190.rs index 6289fcc6fe526..15f7528b4ba21 100644 --- a/src/test/rustdoc/issue-19190.rs +++ b/src/test/rustdoc/issue-19190.rs @@ -23,6 +23,9 @@ impl Deref for Bar { fn deref(&self) -> &Foo { loop {} } } +// @has issue_19190/Bar.t.html // @has issue_19190/struct.Bar.html +// @has - '//*[@id="foo.v"]' 'fn foo(&self)' // @has - '//*[@id="method.foo"]' 'fn foo(&self)' +// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()' // @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' diff --git a/src/test/rustdoc/issue-21092.rs b/src/test/rustdoc/issue-21092.rs index ff48c70fc58dc..8c5bda7584c9f 100644 --- a/src/test/rustdoc/issue-21092.rs +++ b/src/test/rustdoc/issue-21092.rs @@ -13,6 +13,7 @@ extern crate issue_21092; +// @has issue_21092/Bar.t.html // @has issue_21092/struct.Bar.html // @has - '//*[@id="associatedtype.Bar"]' 'type Bar = i32' pub use issue_21092::{Foo, Bar}; diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs index 25c97ee2c76a9..0b6a8104661af 100644 --- a/src/test/rustdoc/issue-25001.rs +++ b/src/test/rustdoc/issue-25001.rs @@ -19,14 +19,17 @@ pub trait Bar { impl Foo { // @has - '//*[@id="method.pass"]//code' 'fn pass()' + // @has - '//*[@id="pass.v"]//code' 'fn pass()' pub fn pass() {} } impl Foo { // @has - '//*[@id="method.pass-1"]//code' 'fn pass() -> usize' + // @has - '//*[@id="pass.v-1"]//code' 'fn pass() -> usize' pub fn pass() -> usize { 42 } } impl Foo { // @has - '//*[@id="method.pass-2"]//code' 'fn pass() -> isize' + // @has - '//*[@id="pass.v-2"]//code' 'fn pass() -> isize' pub fn pass() -> isize { 42 } } diff --git a/src/test/rustdoc/src-links.rs b/src/test/rustdoc/src-links.rs index 4d7dad64b47ae..e946e2423167a 100644 --- a/src/test/rustdoc/src-links.rs +++ b/src/test/rustdoc/src-links.rs @@ -24,11 +24,13 @@ pub mod bar { // @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/src-links.rs.html' pub mod baz { /// Dox + // @has foo/bar/baz/baz.v.html // @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/src-links.rs.html' pub fn baz() { } } /// Dox + // @has foo/bar/Foobar.t.html // @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/src-links.rs.html' pub trait Foobar { fn dummy(&self) { } } diff --git a/src/test/rustdoc/structfields.rs b/src/test/rustdoc/structfields.rs index c4327f70728cb..c0bfe3ffe3cf9 100644 --- a/src/test/rustdoc/structfields.rs +++ b/src/test/rustdoc/structfields.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// @has structfields/Foo.t.html +// @has - struct.Foo.html // @has structfields/struct.Foo.html pub struct Foo { // @has - //pre "pub a: ()" @@ -22,6 +24,8 @@ pub struct Foo { pub d: usize, } +// @has structfields/Bar.t.html +// @has - struct.Bar.html // @has structfields/struct.Bar.html pub struct Bar { // @has - //pre "pub a: ()" @@ -29,6 +33,8 @@ pub struct Bar { // @!has - //pre "// some fields omitted" } +// @has structfields/Qux.t.html +// @has - enum.Qux.html // @has structfields/enum.Qux.html pub enum Qux { Quz { From 4254b31078ea9a84f9e87f5829711ffd7d13a314 Mon Sep 17 00:00:00 2001 From: Neil Williams Date: Tue, 16 Aug 2016 21:30:17 -0700 Subject: [PATCH 073/768] Update minimum CMake version in README The minimum got bumped in the LLVM upgrade of #34743. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 283efdd241156..dbe48a50cfa70 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Read ["Installing Rust"] from [The Book]. * `g++` 4.7 or later or `clang++` 3.x * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later - * `cmake` 2.8.8 or later + * `cmake` 3.4.3 or later * `curl` * `git` From 7675e4b514f9ad3095ad830488861777cfd6c198 Mon Sep 17 00:00:00 2001 From: Jacob Date: Tue, 16 Aug 2016 22:21:31 -0700 Subject: [PATCH 074/768] Update E0009 to new format --- src/librustc_const_eval/check_match.rs | 9 +++++---- src/test/compile-fail/E0009.rs | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 20673dc1e181a..a85fd896f0f95 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -1120,10 +1120,11 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, .span_label(p.span, &format!("moves value into pattern guard")) .emit(); } else if by_ref_span.is_some() { - let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009, - "cannot bind by-move and by-ref in the same pattern"); - span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here"); - err.emit(); + struct_span_err!(cx.tcx.sess, p.span, E0009, + "cannot bind by-move and by-ref in the same pattern") + .span_label(p.span, &format!("by-move pattern here")) + .span_label(by_ref_span.unwrap(), &format!("both by-ref and by-move used")) + .emit(); } }; diff --git a/src/test/compile-fail/E0009.rs b/src/test/compile-fail/E0009.rs index 51f71ea10c9e4..4ce3b72e449df 100644 --- a/src/test/compile-fail/E0009.rs +++ b/src/test/compile-fail/E0009.rs @@ -12,7 +12,10 @@ fn main() { struct X { x: (), } let x = Some((X { x: () }, X { x: () })); match x { - Some((y, ref z)) => {}, //~ ERROR E0009 + Some((y, ref z)) => {}, + //~^ ERROR E0009 + //~| NOTE by-move pattern here + //~| NOTE both by-ref and by-move used None => panic!() } } From b5fa8ab593a106dd58c8c98b7f9b00a47561a663 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 14:27:06 -0400 Subject: [PATCH 075/768] move CrateIndex into its own module --- src/librustc_metadata/encoder.rs | 45 ++++---------------- src/librustc_metadata/index_builder.rs | 59 ++++++++++++++++++++++++++ src/librustc_metadata/lib.rs | 1 + 3 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 src/librustc_metadata/index_builder.rs diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 320ba3c8d9dc8..3ce9064f80ab5 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -25,7 +25,7 @@ use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls}; use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; -use rustc::dep_graph::{DepGraph, DepNode, DepTask}; +use rustc::dep_graph::DepNode; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; @@ -54,6 +54,8 @@ use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; +use super::index_builder::{CrateIndex, XRef}; + pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -71,35 +73,6 @@ impl<'a, 'tcx> EncodeContext<'a,'tcx> { } } -/// "interned" entries referenced by id -#[derive(PartialEq, Eq, Hash)] -pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } - -struct CrateIndex<'a, 'tcx> { - dep_graph: &'a DepGraph, - items: IndexData, - xrefs: FnvHashMap, u32>, // sequentially-assigned -} - -impl<'a, 'tcx> CrateIndex<'a, 'tcx> { - /// Records that `id` is being emitted at the current offset. - /// This data is later used to construct the item index in the - /// metadata so we can quickly find the data for a given item. - /// - /// Returns a dep-graph task that you should keep live as long as - /// the data for this item is being emitted. - fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> { - let position = rbml_w.mark_stable_position(); - self.items.record(id, position); - self.dep_graph.in_task(DepNode::MetaData(id)) - } - - fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { - let old_len = self.xrefs.len() as u32; - *self.xrefs.entry(xref).or_insert(old_len) - } -} - fn encode_name(rbml_w: &mut Encoder, name: Name) { rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str()); } @@ -1380,11 +1353,7 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, -> CrateIndex<'a, 'tcx> { let krate = ecx.tcx.map.krate(); - let mut index = CrateIndex { - dep_graph: &ecx.tcx.dep_graph, - items: IndexData::new(ecx.tcx.map.num_local_def_ids()), - xrefs: FnvHashMap() - }; + let mut index = CrateIndex::new(ecx); rbml_w.start_tag(tag_items_data); { @@ -1929,12 +1898,14 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; rbml_w.end_tag(); + let (items, xrefs) = index.into_fields(); + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_item_index(rbml_w, index.items); + encode_item_index(rbml_w, items); stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_xrefs(&ecx, rbml_w, index.xrefs); + encode_xrefs(&ecx, rbml_w, xrefs); stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; encode_struct_field_attrs(&ecx, rbml_w, krate); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs new file mode 100644 index 0000000000000..3921a9160ef15 --- /dev/null +++ b/src/librustc_metadata/index_builder.rs @@ -0,0 +1,59 @@ +// Copyright 2012-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. + +use encoder::EncodeContext; +use index::IndexData; +use rbml::writer::Encoder; +use rustc::dep_graph::{DepGraph, DepNode, DepTask}; +use rustc::hir::def_id::DefId; +use rustc::ty; +use rustc_data_structures::fnv::FnvHashMap; + +pub struct CrateIndex<'a, 'tcx> { + dep_graph: &'a DepGraph, + items: IndexData, + xrefs: FnvHashMap, u32>, // sequentially-assigned +} + +/// "interned" entries referenced by id +#[derive(PartialEq, Eq, Hash)] +pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } + +impl<'a, 'tcx> CrateIndex<'a, 'tcx> { + pub fn new(ecx: &EncodeContext<'a, 'tcx>) -> Self { + CrateIndex { + dep_graph: &ecx.tcx.dep_graph, + items: IndexData::new(ecx.tcx.map.num_local_def_ids()), + xrefs: FnvHashMap() + } + } + + /// Records that `id` is being emitted at the current offset. + /// This data is later used to construct the item index in the + /// metadata so we can quickly find the data for a given item. + /// + /// Returns a dep-graph task that you should keep live as long as + /// the data for this item is being emitted. + pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> { + let position = rbml_w.mark_stable_position(); + self.items.record(id, position); + self.dep_graph.in_task(DepNode::MetaData(id)) + } + + pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { + let old_len = self.xrefs.len() as u32; + *self.xrefs.entry(xref).or_insert(old_len) + } + + pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { + (self.items, self.xrefs) + } +} + diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index cd92493e3db70..a96fa8a006d89 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -54,6 +54,7 @@ pub mod def_key; pub mod tyencode; pub mod tydecode; pub mod encoder; +mod index_builder; pub mod decoder; pub mod creader; pub mod csearch; From 85ac63e9ec9b61bec8584b9df3a67aa504eb1076 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 14:27:36 -0400 Subject: [PATCH 076/768] rename CrateIndex to IndexBuilder --- src/librustc_metadata/encoder.rs | 36 +++++++++++++------------- src/librustc_metadata/index_builder.rs | 6 ++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3ce9064f80ab5..97c780f84e9ff 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -54,7 +54,7 @@ use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; -use super::index_builder::{CrateIndex, XRef}; +use super::index_builder::{IndexBuilder, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, @@ -134,7 +134,7 @@ fn encode_item_variances(rbml_w: &mut Encoder, fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, id: NodeId) { encode_bounds_and_type(rbml_w, ecx, @@ -145,7 +145,7 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, scheme: &ty::TypeScheme<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { encode_generics(rbml_w, ecx, index, &scheme.generics, &predicates); @@ -204,7 +204,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, did: DefId, vis: &hir::Visibility, - index: &mut CrateIndex<'a, 'tcx>) { + index: &mut IndexBuilder<'a, 'tcx>) { debug!("encode_enum_variant_info(did={:?})", did); let repr_hints = ecx.tcx.lookup_repr_hints(did); let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0)); @@ -424,7 +424,7 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, field: ty::FieldDef<'tcx>, - index: &mut CrateIndex<'a, 'tcx>) { + index: &mut IndexBuilder<'a, 'tcx>) { let nm = field.name; let id = ecx.local_id(field.did); @@ -448,7 +448,7 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, name: Name, struct_def: &hir::VariantData, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, struct_id: NodeId) { let ctor_id = struct_def.id(); let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); @@ -480,7 +480,7 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { @@ -493,7 +493,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, } fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { @@ -510,7 +510,7 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, method_ty: &ty::Method<'tcx>) { encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.name); @@ -528,7 +528,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, associated_const: &ty::AssociatedConst, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -570,7 +570,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, m: &ty::Method<'tcx>, is_default_impl: bool, parent_id: NodeId, @@ -618,7 +618,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'a, 'tcx>, + index: &mut IndexBuilder<'a, 'tcx>, associated_type: &ty::AssociatedType<'tcx>, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -765,7 +765,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, item: &hir::Item, - index: &mut CrateIndex<'a, 'tcx>) { + index: &mut IndexBuilder<'a, 'tcx>) { let tcx = ecx.tcx; debug!("encoding info for item at {}", @@ -1237,7 +1237,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, nitem: &hir::ForeignItem, - index: &mut CrateIndex<'a, 'tcx>) { + index: &mut IndexBuilder<'a, 'tcx>) { debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); @@ -1285,7 +1285,7 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn my_visit_expr(expr: &hir::Expr, rbml_w: &mut Encoder, ecx: &EncodeContext, - index: &mut CrateIndex) { + index: &mut IndexBuilder) { match expr.node { hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); @@ -1316,7 +1316,7 @@ fn my_visit_expr(expr: &hir::Expr, struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w_for_visit_item: &'a mut Encoder<'b>, ecx: &'a EncodeContext<'c, 'tcx>, - index: &'a mut CrateIndex<'c, 'tcx>, + index: &'a mut IndexBuilder<'c, 'tcx>, } impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { @@ -1350,10 +1350,10 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder) - -> CrateIndex<'a, 'tcx> { + -> IndexBuilder<'a, 'tcx> { let krate = ecx.tcx.map.krate(); - let mut index = CrateIndex::new(ecx); + let mut index = IndexBuilder::new(ecx); rbml_w.start_tag(tag_items_data); { diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 3921a9160ef15..b7af35da751d9 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -16,7 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::ty; use rustc_data_structures::fnv::FnvHashMap; -pub struct CrateIndex<'a, 'tcx> { +pub struct IndexBuilder<'a, 'tcx> { dep_graph: &'a DepGraph, items: IndexData, xrefs: FnvHashMap, u32>, // sequentially-assigned @@ -26,9 +26,9 @@ pub struct CrateIndex<'a, 'tcx> { #[derive(PartialEq, Eq, Hash)] pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } -impl<'a, 'tcx> CrateIndex<'a, 'tcx> { +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { pub fn new(ecx: &EncodeContext<'a, 'tcx>) -> Self { - CrateIndex { + IndexBuilder { dep_graph: &ecx.tcx.dep_graph, items: IndexData::new(ecx.tcx.map.num_local_def_ids()), xrefs: FnvHashMap() From 25bb51d98fee9d991c06169784a48e4533fff035 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 14:35:45 -0400 Subject: [PATCH 077/768] store ecx, not dep-graph --- src/librustc_metadata/index_builder.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index b7af35da751d9..0f52252c6a005 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -17,7 +17,7 @@ use rustc::ty; use rustc_data_structures::fnv::FnvHashMap; pub struct IndexBuilder<'a, 'tcx> { - dep_graph: &'a DepGraph, + ecx: &'a EncodeContext<'a, 'tcx>, items: IndexData, xrefs: FnvHashMap, u32>, // sequentially-assigned } @@ -29,12 +29,16 @@ pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { pub fn new(ecx: &EncodeContext<'a, 'tcx>) -> Self { IndexBuilder { - dep_graph: &ecx.tcx.dep_graph, + ecx: ecx, items: IndexData::new(ecx.tcx.map.num_local_def_ids()), xrefs: FnvHashMap() } } + pub fn ecx(&self) { + self.ecx + } + /// Records that `id` is being emitted at the current offset. /// This data is later used to construct the item index in the /// metadata so we can quickly find the data for a given item. @@ -44,7 +48,7 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> { let position = rbml_w.mark_stable_position(); self.items.record(id, position); - self.dep_graph.in_task(DepNode::MetaData(id)) + self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)) } pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { From 92f269e665bd7fdccf83da6f545ee755b211bbb9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 14:49:22 -0400 Subject: [PATCH 078/768] put ecx into IndexBuilder so we don't have to pass --- src/librustc_metadata/encoder.rs | 95 ++++++++++++++------------ src/librustc_metadata/index_builder.rs | 8 +-- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 97c780f84e9ff..6f0ccf5af9963 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -762,10 +762,10 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, +fn encode_info_for_item<'a, 'tcx>(rbml_w: &mut Encoder, item: &hir::Item, index: &mut IndexBuilder<'a, 'tcx>) { + let ecx = index.ecx(); let tcx = ecx.tcx; debug!("encoding info for item at {}", @@ -1234,10 +1234,11 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } } -fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, +fn encode_info_for_foreign_item<'a, 'tcx>(rbml_w: &mut Encoder, nitem: &hir::ForeignItem, index: &mut IndexBuilder<'a, 'tcx>) { + let ecx = index.ecx(); + debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); @@ -1282,10 +1283,50 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -fn my_visit_expr(expr: &hir::Expr, - rbml_w: &mut Encoder, - ecx: &EncodeContext, - index: &mut IndexBuilder) { +struct EncodeVisitor<'a, 'data:'a, 'ecx: 'a, 'tcx: 'ecx> { + rbml_w_for_visit_item: &'a mut Encoder<'data>, + index: &'a mut IndexBuilder<'ecx, 'tcx>, +} + +impl<'a, 'data, 'ecx, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'data, 'ecx, 'tcx> { + fn visit_expr(&mut self, ex: &'tcx hir::Expr) { + intravisit::walk_expr(self, ex); + encode_info_for_expr(ex, self.rbml_w_for_visit_item, self.index); + } + fn visit_item(&mut self, i: &'tcx hir::Item) { + intravisit::walk_item(self, i); + encode_info_for_item(self.rbml_w_for_visit_item, i, self.index); + } + fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { + intravisit::walk_foreign_item(self, ni); + encode_info_for_foreign_item(self.rbml_w_for_visit_item, ni, self.index); + } + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { + intravisit::walk_ty(self, ty); + encode_info_for_ty(ty, self.rbml_w_for_visit_item, self.index); + } +} + +fn encode_info_for_ty(ty: &hir::Ty, + rbml_w: &mut Encoder, + index: &mut IndexBuilder) { + let ecx = index.ecx(); + if let hir::TyImplTrait(_) = ty.node { + let def_id = ecx.tcx.map.local_def_id(ty.id); + let _task = index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'y'); + encode_bounds_and_type_for_item(rbml_w, ecx, index, ty.id); + rbml_w.end_tag(); + } +} + +fn encode_info_for_expr(expr: &hir::Expr, + rbml_w: &mut Encoder, + index: &mut IndexBuilder) { + let ecx = index.ecx(); + match expr.node { hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); @@ -1313,42 +1354,7 @@ fn my_visit_expr(expr: &hir::Expr, } } -struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { - rbml_w_for_visit_item: &'a mut Encoder<'b>, - ecx: &'a EncodeContext<'c, 'tcx>, - index: &'a mut IndexBuilder<'c, 'tcx>, -} - -impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr) { - intravisit::walk_expr(self, ex); - my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index); - } - fn visit_item(&mut self, i: &'tcx hir::Item) { - intravisit::walk_item(self, i); - encode_info_for_item(self.ecx, self.rbml_w_for_visit_item, i, self.index); - } - fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { - intravisit::walk_foreign_item(self, ni); - encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index); - } - fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - intravisit::walk_ty(self, ty); - - if let hir::TyImplTrait(_) = ty.node { - let rbml_w = &mut *self.rbml_w_for_visit_item; - let def_id = self.ecx.tcx.map.local_def_id(ty.id); - let _task = self.index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(self.ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id); - rbml_w.end_tag(); - } - } -} - -fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, +fn encode_info_for_items<'a, 'tcx>(ecx: &'a EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder) -> IndexBuilder<'a, 'tcx> { let krate = ecx.tcx.map.krate(); @@ -1369,7 +1375,6 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, krate.visit_all_items(&mut EncodeVisitor { index: &mut index, - ecx: ecx, rbml_w_for_visit_item: &mut *rbml_w, }); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 0f52252c6a005..1e1ae06443643 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -11,12 +11,12 @@ use encoder::EncodeContext; use index::IndexData; use rbml::writer::Encoder; -use rustc::dep_graph::{DepGraph, DepNode, DepTask}; +use rustc::dep_graph::{DepNode, DepTask}; use rustc::hir::def_id::DefId; use rustc::ty; use rustc_data_structures::fnv::FnvHashMap; -pub struct IndexBuilder<'a, 'tcx> { +pub struct IndexBuilder<'a, 'tcx: 'a> { ecx: &'a EncodeContext<'a, 'tcx>, items: IndexData, xrefs: FnvHashMap, u32>, // sequentially-assigned @@ -27,7 +27,7 @@ pub struct IndexBuilder<'a, 'tcx> { pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { - pub fn new(ecx: &EncodeContext<'a, 'tcx>) -> Self { + pub fn new(ecx: &'a EncodeContext<'a, 'tcx>) -> Self { IndexBuilder { ecx: ecx, items: IndexData::new(ecx.tcx.map.num_local_def_ids()), @@ -35,7 +35,7 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } - pub fn ecx(&self) { + pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { self.ecx } From b2c7922d7f6cab865751c4c0977072942b78c287 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 15:33:36 -0400 Subject: [PATCH 079/768] move free encode fns into methods of IndexBuilder --- src/librustc_metadata/encoder.rs | 1798 +++++++++++++++--------------- 1 file changed, 902 insertions(+), 896 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 6f0ccf5af9963..f256d1269340c 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -132,24 +132,23 @@ fn encode_item_variances(rbml_w: &mut Encoder, rbml_w.end_tag(); } -fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut IndexBuilder<'a, 'tcx>, - id: NodeId) { - encode_bounds_and_type(rbml_w, - ecx, - index, - &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), - &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); -} - -fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut IndexBuilder<'a, 'tcx>, - scheme: &ty::TypeScheme<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) { - encode_generics(rbml_w, ecx, index, &scheme.generics, &predicates); - encode_type(ecx, rbml_w, scheme.ty); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_bounds_and_type_for_item(&mut self, + rbml_w: &mut Encoder, + id: NodeId) { + let ecx = self.ecx(); + self.encode_bounds_and_type(rbml_w, + &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), + &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); + } + + fn encode_bounds_and_type(&mut self, + rbml_w: &mut Encoder, + scheme: &ty::TypeScheme<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) { + self.encode_generics(rbml_w, &scheme.generics, &predicates); + self.encode_type(rbml_w, scheme.ty); + } } fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { @@ -165,92 +164,95 @@ fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.mark_stable_position(); } -fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - typ: Ty<'tcx>) { - rbml_w.start_tag(tag_items_data_item_type); - tyencode::enc_ty(rbml_w.writer, &ecx.ty_str_ctxt(), typ); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); -} - -fn encode_disr_val(_: &EncodeContext, +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_type(&mut self, rbml_w: &mut Encoder, - disr_val: ty::Disr) { - // convert to u64 so just the number is printed, without any type info - rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); -} + typ: Ty<'tcx>) { + rbml_w.start_tag(tag_items_data_item_type); + tyencode::enc_ty(rbml_w.writer, &self.ecx().ty_str_ctxt(), typ); + rbml_w.mark_stable_position(); + rbml_w.end_tag(); + } -fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); -} + fn encode_disr_val(&mut self, + rbml_w: &mut Encoder, + disr_val: ty::Disr) { + // convert to u64 so just the number is printed, without any type info + rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); + } -fn encode_struct_fields(rbml_w: &mut Encoder, - variant: ty::VariantDef) { - for f in &variant.fields { - if variant.kind == ty::VariantKind::Tuple { - rbml_w.start_tag(tag_item_unnamed_field); - } else { - rbml_w.start_tag(tag_item_field); - encode_name(rbml_w, f.name); - } - encode_struct_field_family(rbml_w, f.vis); - encode_def_id(rbml_w, f.did); - rbml_w.end_tag(); + fn encode_parent_item(&mut self, rbml_w: &mut Encoder, id: DefId) { + rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); } -} -fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - did: DefId, - vis: &hir::Visibility, - index: &mut IndexBuilder<'a, 'tcx>) { - debug!("encode_enum_variant_info(did={:?})", did); - let repr_hints = ecx.tcx.lookup_repr_hints(did); - let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0)); - let mut disr_val = repr_type.initial_discriminant(ecx.tcx); - let def = ecx.tcx.lookup_adt_def(did); - for variant in &def.variants { - let vid = variant.did; - let variant_node_id = ecx.local_id(vid); - - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); + fn encode_struct_fields(&mut self, + rbml_w: &mut Encoder, + variant: ty::VariantDef) { + for f in &variant.fields { + if variant.kind == ty::VariantKind::Tuple { + rbml_w.start_tag(tag_item_unnamed_field); + } else { + rbml_w.start_tag(tag_item_field); + encode_name(rbml_w, f.name); + } + self.encode_struct_field_family(rbml_w, f.vis); + encode_def_id(rbml_w, f.did); + rbml_w.end_tag(); } + } - let _task = index.record(vid, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, vid); - encode_family(rbml_w, match variant.kind { - ty::VariantKind::Struct => 'V', - ty::VariantKind::Tuple => 'v', - ty::VariantKind::Unit => 'w', - }); - encode_name(rbml_w, variant.name); - encode_parent_item(rbml_w, did); - encode_visibility(rbml_w, vis); - - let attrs = ecx.tcx.get_attrs(vid); - encode_attributes(rbml_w, &attrs); - encode_repr_attrs(rbml_w, ecx, &attrs); + fn encode_enum_variant_info(&mut self, + rbml_w: &mut Encoder, + did: DefId, + vis: &hir::Visibility) { + debug!("encode_enum_variant_info(did={:?})", did); + let ecx = self.ecx(); + let repr_hints = ecx.tcx.lookup_repr_hints(did); + let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0)); + let mut disr_val = repr_type.initial_discriminant(ecx.tcx); + let def = ecx.tcx.lookup_adt_def(did); + for variant in &def.variants { + let vid = variant.did; + let variant_node_id = ecx.local_id(vid); + + for field in &variant.fields { + self.encode_field(rbml_w, field); + } - let stab = ecx.tcx.lookup_stability(vid); - let depr = ecx.tcx.lookup_deprecation(vid); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + let _task = self.record(vid, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, vid); + encode_family(rbml_w, match variant.kind { + ty::VariantKind::Struct => 'V', + ty::VariantKind::Tuple => 'v', + ty::VariantKind::Unit => 'w', + }); + encode_name(rbml_w, variant.name); + self.encode_parent_item(rbml_w, did); + self.encode_visibility(rbml_w, vis); + + let attrs = ecx.tcx.get_attrs(vid); + encode_attributes(rbml_w, &attrs); + self.encode_repr_attrs(rbml_w, &attrs); + + let stab = ecx.tcx.lookup_stability(vid); + let depr = ecx.tcx.lookup_deprecation(vid); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - encode_struct_fields(rbml_w, variant); + self.encode_struct_fields(rbml_w, variant); - let specified_disr_val = variant.disr_val; - if specified_disr_val != disr_val { - encode_disr_val(ecx, rbml_w, specified_disr_val); - disr_val = specified_disr_val; - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); + let specified_disr_val = variant.disr_val; + if specified_disr_val != disr_val { + self.encode_disr_val(rbml_w, specified_disr_val); + disr_val = specified_disr_val; + } + self.encode_bounds_and_type_for_item(rbml_w, variant_node_id); - rbml_w.end_tag(); + rbml_w.end_tag(); - disr_val = disr_val.wrap_incr(); + disr_val = disr_val.wrap_incr(); + } } } @@ -300,57 +302,61 @@ fn encode_reexports(ecx: &EncodeContext, } } -fn encode_info_for_mod(ecx: &EncodeContext, - rbml_w: &mut Encoder, - md: &hir::Mod, - attrs: &[ast::Attribute], - id: NodeId, - name: Name, - vis: &hir::Visibility) { - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); - encode_family(rbml_w, 'm'); - encode_name(rbml_w, name); - debug!("(encoding info for module) encoding info for module ID {}", id); - - // Encode info about all the module children. - for item_id in &md.item_ids { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_info_for_mod(&mut self, + rbml_w: &mut Encoder, + md: &hir::Mod, + attrs: &[ast::Attribute], + id: NodeId, + name: Name, + vis: &hir::Visibility) { + let ecx = self.ecx(); - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); + encode_family(rbml_w, 'm'); + encode_name(rbml_w, name); + debug!("(encoding info for module) encoding info for module ID {}", id); + + // Encode info about all the module children. + for item_id in &md.item_ids { rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); - } + def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); + + let item = ecx.tcx.map.expect_item(item_id.id); + each_auxiliary_node_id(item, |auxiliary_node_id| { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); + true + }); + } - encode_visibility(rbml_w, vis); + self.encode_visibility(rbml_w, vis); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - // Encode the reexports of this module, if this module is public. - if *vis == hir::Public { - debug!("(encoding info for module) encoding reexports for {}", id); - encode_reexports(ecx, rbml_w, id); - } - encode_attributes(rbml_w, attrs); + // Encode the reexports of this module, if this module is public. + if *vis == hir::Public { + debug!("(encoding info for module) encoding reexports for {}", id); + encode_reexports(ecx, rbml_w, id); + } + encode_attributes(rbml_w, attrs); - rbml_w.end_tag(); -} + rbml_w.end_tag(); + } -fn encode_struct_field_family(rbml_w: &mut Encoder, - visibility: ty::Visibility) { - encode_family(rbml_w, if visibility.is_public() { 'g' } else { 'N' }); -} + fn encode_struct_field_family(&mut self, rbml_w: &mut Encoder, + visibility: ty::Visibility) { + encode_family(rbml_w, if visibility.is_public() { 'g' } else { 'N' }); + } -fn encode_visibility(rbml_w: &mut Encoder, visibility: T) { - let ch = if visibility.is_public() { 'y' } else { 'i' }; - rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); + fn encode_visibility(&mut self, rbml_w: &mut Encoder, visibility: T) { + let ch = if visibility.is_public() { 'y' } else { 'i' }; + rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); + } } trait HasVisibility: Sized { @@ -421,281 +427,287 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); } -fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - field: ty::FieldDef<'tcx>, - index: &mut IndexBuilder<'a, 'tcx>) { - let nm = field.name; - let id = ecx.local_id(field.did); - - let _task = index.record(field.did, rbml_w); - rbml_w.start_tag(tag_items_data_item); - debug!("encode_field: encoding {} {}", nm, id); - encode_struct_field_family(rbml_w, field.vis); - encode_name(rbml_w, nm); - encode_bounds_and_type_for_item(rbml_w, ecx, index, id); - encode_def_id_and_key(ecx, rbml_w, field.did); - - let stab = ecx.tcx.lookup_stability(field.did); - let depr = ecx.tcx.lookup_deprecation(field.did); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - - rbml_w.end_tag(); -} - -fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - name: Name, - struct_def: &hir::VariantData, - index: &mut IndexBuilder<'a, 'tcx>, - struct_id: NodeId) { - let ctor_id = struct_def.id(); - let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - - let _task = index.record(ctor_def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, ctor_def_id); - encode_family(rbml_w, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', - }); - encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id); - encode_name(rbml_w, name); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_field(&mut self, + rbml_w: &mut Encoder, + field: ty::FieldDef<'tcx>) { + let ecx = self.ecx(); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); - let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + let nm = field.name; + let id = ecx.local_id(field.did); - // indicate that this is a tuple struct ctor, because downstream users will normally want - // the tuple struct definition, but without this there is no way for them to tell that - // they actually have a ctor rather than a normal function - rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + let _task = self.record(field.did, rbml_w); + rbml_w.start_tag(tag_items_data_item); + debug!("encode_field: encoding {} {}", nm, id); + self.encode_struct_field_family(rbml_w, field.vis); + encode_name(rbml_w, nm); + self.encode_bounds_and_type_for_item(rbml_w, id); + encode_def_id_and_key(ecx, rbml_w, field.did); + + let stab = ecx.tcx.lookup_stability(field.did); + let depr = ecx.tcx.lookup_deprecation(field.did); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + rbml_w.end_tag(); + } } -fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut IndexBuilder<'a, 'tcx>, - generics: &ty::Generics<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) -{ - rbml_w.start_tag(tag_item_generics); - tyencode::enc_generics(rbml_w.writer, &ecx.ty_str_ctxt(), generics); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_info_for_struct_ctor(&mut self, + rbml_w: &mut Encoder, + name: Name, + struct_def: &hir::VariantData, + struct_id: NodeId) { + let ecx = self.ecx(); + let ctor_id = struct_def.id(); + let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); + + let _task = self.record(ctor_def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, ctor_def_id); + encode_family(rbml_w, match *struct_def { + hir::VariantData::Struct(..) => 'S', + hir::VariantData::Tuple(..) => 's', + hir::VariantData::Unit(..) => 'u', + }); + self.encode_bounds_and_type_for_item(rbml_w, ctor_id); + encode_name(rbml_w, name); + self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); - encode_predicates(rbml_w, index, predicates, tag_item_predicates); -} + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); -fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, - index: &mut IndexBuilder<'a, 'tcx>, - predicates: &ty::GenericPredicates<'tcx>, - tag: usize) -{ - rbml_w.start_tag(tag); - if let Some(def_id) = predicates.parent { - rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); + // indicate that this is a tuple struct ctor, because downstream users will normally want + // the tuple struct definition, but without this there is no way for them to tell that + // they actually have a ctor rather than a normal function + rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + + rbml_w.end_tag(); } - for predicate in &predicates.predicates { - rbml_w.wr_tagged_u32(tag_predicate, - index.add_xref(XRef::Predicate(predicate.clone()))); + + fn encode_generics(&mut self, + rbml_w: &mut Encoder, + generics: &ty::Generics<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) + { + let ecx = self.ecx(); + rbml_w.start_tag(tag_item_generics); + tyencode::enc_generics(rbml_w.writer, &ecx.ty_str_ctxt(), generics); + rbml_w.mark_stable_position(); + rbml_w.end_tag(); + self.encode_predicates(rbml_w, predicates, tag_item_predicates); } - rbml_w.end_tag(); -} -fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut IndexBuilder<'a, 'tcx>, - method_ty: &ty::Method<'tcx>) { - encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); - encode_name(rbml_w, method_ty.name); - encode_generics(rbml_w, ecx, index, - &method_ty.generics, &method_ty.predicates); - encode_visibility(rbml_w, method_ty.vis); - encode_explicit_self(rbml_w, &method_ty.explicit_self); - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(rbml_w, STATIC_METHOD_FAMILY); + fn encode_predicates(&mut self, + rbml_w: &mut Encoder, + predicates: &ty::GenericPredicates<'tcx>, + tag: usize) { + rbml_w.start_tag(tag); + if let Some(def_id) = predicates.parent { + rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); + } + for predicate in &predicates.predicates { + rbml_w.wr_tagged_u32(tag_predicate, + self.add_xref(XRef::Predicate(predicate.clone()))); } - _ => encode_family(rbml_w, METHOD_FAMILY) + rbml_w.end_tag(); } -} -fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut IndexBuilder<'a, 'tcx>, - associated_const: &ty::AssociatedConst, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - debug!("encode_info_for_associated_const({:?},{:?})", - associated_const.def_id, - associated_const.name); - - let _task = index.record(associated_const.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - encode_name(rbml_w, associated_const.name); - encode_visibility(rbml_w, associated_const.vis); - encode_family(rbml_w, 'C'); - - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'C'); - - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(associated_const.def_id)); - - let stab = ecx.tcx.lookup_stability(associated_const.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - - if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_defaultness(rbml_w, ii.defaultness); - encode_inlined_item(ecx, - rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - ii)); - encode_mir(ecx, rbml_w, ii.id); + fn encode_method_ty_fields(&mut self, + rbml_w: &mut Encoder, + method_ty: &ty::Method<'tcx>) { + let ecx = self.ecx(); + encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); + encode_name(rbml_w, method_ty.name); + self.encode_generics(rbml_w, &method_ty.generics, &method_ty.predicates); + self.encode_visibility(rbml_w, method_ty.vis); + encode_explicit_self(rbml_w, &method_ty.explicit_self); + match method_ty.explicit_self { + ty::ExplicitSelfCategory::Static => { + encode_family(rbml_w, STATIC_METHOD_FAMILY); + } + _ => encode_family(rbml_w, METHOD_FAMILY) + } } - rbml_w.end_tag(); -} + fn encode_info_for_associated_const(&mut self, + rbml_w: &mut Encoder, + associated_const: &ty::AssociatedConst, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { + let ecx = self.ecx(); + debug!("encode_info_for_associated_const({:?},{:?})", + associated_const.def_id, + associated_const.name); + + let _task = self.record(associated_const.def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); -fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut IndexBuilder<'a, 'tcx>, - m: &ty::Method<'tcx>, - is_default_impl: bool, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - - debug!("encode_info_for_method: {:?} {:?}", m.def_id, - m.name); - let _task = index.record(m.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_method_ty_fields(ecx, rbml_w, index, m); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'r'); - - let stab = ecx.tcx.lookup_stability(m.def_id); - let depr = ecx.tcx.lookup_deprecation(m.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - - let m_node_id = ecx.local_id(m.def_id); - encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id); - - if let Some(impl_item) = impl_item_opt { - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(rbml_w, &impl_item.attrs); - let generics = ecx.tcx.lookup_generics(m.def_id); - let types = generics.parent_types as usize + generics.types.len(); - let needs_inline = types > 0 || is_default_impl || - attr::requests_inline(&impl_item.attrs); - if needs_inline || sig.constness == hir::Constness::Const { - encode_inlined_item(ecx, - rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - impl_item)); - encode_mir(ecx, rbml_w, impl_item.id); - } - encode_constness(rbml_w, sig.constness); - encode_defaultness(rbml_w, impl_item.defaultness); - encode_method_argument_names(rbml_w, &sig.decl); + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); + encode_name(rbml_w, associated_const.name); + self.encode_visibility(rbml_w, associated_const.vis); + encode_family(rbml_w, 'C'); + + self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 'C'); + + self.encode_bounds_and_type_for_item(rbml_w, ecx.local_id(associated_const.def_id)); + + let stab = ecx.tcx.lookup_stability(associated_const.def_id); + let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + + if let Some(ii) = impl_item_opt { + encode_attributes(rbml_w, &ii.attrs); + encode_defaultness(rbml_w, ii.defaultness); + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + ii)); + self.encode_mir(rbml_w, ii.id); } + + rbml_w.end_tag(); } - rbml_w.end_tag(); -} + fn encode_info_for_method(&mut self, + rbml_w: &mut Encoder, + m: &ty::Method<'tcx>, + is_default_impl: bool, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { + let ecx = self.ecx(); + + debug!("encode_info_for_method: {:?} {:?}", m.def_id, + m.name); + let _task = self.record(m.def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); -fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut IndexBuilder<'a, 'tcx>, - associated_type: &ty::AssociatedType<'tcx>, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - debug!("encode_info_for_associated_type({:?},{:?})", - associated_type.def_id, - associated_type.name); - - let _task = index.record(associated_type.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_name(rbml_w, associated_type.name); - encode_visibility(rbml_w, associated_type.vis); - encode_family(rbml_w, 'y'); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 't'); - - let stab = ecx.tcx.lookup_stability(associated_type.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - - if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_defaultness(rbml_w, ii.defaultness); - } else { - encode_predicates(rbml_w, index, - &ecx.tcx.lookup_predicates(associated_type.def_id), - tag_item_generics); - } + self.encode_method_ty_fields(rbml_w, m); + self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 'r'); + + let stab = ecx.tcx.lookup_stability(m.def_id); + let depr = ecx.tcx.lookup_deprecation(m.def_id); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - if let Some(ty) = associated_type.ty { - encode_type(ecx, rbml_w, ty); + let m_node_id = ecx.local_id(m.def_id); + self.encode_bounds_and_type_for_item(rbml_w, m_node_id); + + if let Some(impl_item) = impl_item_opt { + if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { + encode_attributes(rbml_w, &impl_item.attrs); + let generics = ecx.tcx.lookup_generics(m.def_id); + let types = generics.parent_types as usize + generics.types.len(); + let needs_inline = types > 0 || is_default_impl || + attr::requests_inline(&impl_item.attrs); + if needs_inline || sig.constness == hir::Constness::Const { + encode_inlined_item( + ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + impl_item)); + self.encode_mir(rbml_w, impl_item.id); + } + encode_constness(rbml_w, sig.constness); + encode_defaultness(rbml_w, impl_item.defaultness); + self.encode_method_argument_names(rbml_w, &sig.decl); + } + } + + rbml_w.end_tag(); } - rbml_w.end_tag(); -} + fn encode_info_for_associated_type(&mut self, + rbml_w: &mut Encoder, + associated_type: &ty::AssociatedType<'tcx>, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { + let ecx = self.ecx(); + debug!("encode_info_for_associated_type({:?},{:?})", + associated_type.def_id, + associated_type.name); + + let _task = self.record(associated_type.def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); + encode_name(rbml_w, associated_type.name); + self.encode_visibility(rbml_w, associated_type.vis); + encode_family(rbml_w, 'y'); + self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 't'); + + let stab = ecx.tcx.lookup_stability(associated_type.def_id); + let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); -fn encode_method_argument_names(rbml_w: &mut Encoder, - decl: &hir::FnDecl) { - rbml_w.start_tag(tag_method_argument_names); - for arg in &decl.inputs { - let tag = tag_method_argument_name; - if let PatKind::Binding(_, ref path1, _) = arg.pat.node { - let name = path1.node.as_str(); - rbml_w.wr_tagged_bytes(tag, name.as_bytes()); + if let Some(ii) = impl_item_opt { + encode_attributes(rbml_w, &ii.attrs); + encode_defaultness(rbml_w, ii.defaultness); } else { - rbml_w.wr_tagged_bytes(tag, &[]); + // TODO this looks bogus and unnecessary + self.encode_predicates(rbml_w, + &ecx.tcx.lookup_predicates(associated_type.def_id), + tag_item_generics); } + + if let Some(ty) = associated_type.ty { + self.encode_type(rbml_w, ty); + } + + rbml_w.end_tag(); } - rbml_w.end_tag(); -} -fn encode_repr_attrs(rbml_w: &mut Encoder, - ecx: &EncodeContext, - attrs: &[ast::Attribute]) { - let mut repr_attrs = Vec::new(); - for attr in attrs { - repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(), - attr)); + fn encode_method_argument_names(&mut self, + rbml_w: &mut Encoder, + decl: &hir::FnDecl) { + rbml_w.start_tag(tag_method_argument_names); + for arg in &decl.inputs { + let tag = tag_method_argument_name; + if let PatKind::Binding(_, ref path1, _) = arg.pat.node { + let name = path1.node.as_str(); + rbml_w.wr_tagged_bytes(tag, name.as_bytes()); + } else { + rbml_w.wr_tagged_bytes(tag, &[]); + } + } + rbml_w.end_tag(); } - rbml_w.start_tag(tag_items_data_item_repr); - repr_attrs.encode(rbml_w); - rbml_w.end_tag(); -} -fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) { - let def_id = ecx.tcx.map.local_def_id(node_id); - if let Some(mir) = ecx.mir_map.map.get(&def_id) { - rbml_w.start_tag(tag_mir as usize); - rbml_w.emit_opaque(|opaque_encoder| { - tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| { - Encodable::encode(mir, opaque_encoder) - }) - }).unwrap(); + fn encode_repr_attrs(&mut self, + rbml_w: &mut Encoder, + attrs: &[ast::Attribute]) { + let ecx = self.ecx(); + let mut repr_attrs = Vec::new(); + for attr in attrs { + repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(), + attr)); + } + rbml_w.start_tag(tag_items_data_item_repr); + repr_attrs.encode(rbml_w); rbml_w.end_tag(); } + + fn encode_mir(&mut self, rbml_w: &mut Encoder, node_id: NodeId) { + let ecx = self.ecx(); + let def_id = ecx.tcx.map.local_def_id(node_id); + if let Some(mir) = ecx.mir_map.map.get(&def_id) { + rbml_w.start_tag(tag_mir as usize); + rbml_w.emit_opaque(|opaque_encoder| { + tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| { + Encodable::encode(mir, opaque_encoder) + }) + }).unwrap(); + rbml_w.end_tag(); + } + } } const FN_FAMILY: char = 'f'; @@ -762,544 +774,539 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -fn encode_info_for_item<'a, 'tcx>(rbml_w: &mut Encoder, - item: &hir::Item, - index: &mut IndexBuilder<'a, 'tcx>) { - let ecx = index.ecx(); - let tcx = ecx.tcx; - - debug!("encoding info for item at {}", - tcx.sess.codemap().span_to_string(item.span)); - - let vis = &item.vis; - let def_id = ecx.tcx.map.local_def_id(item.id); - - let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { - (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)), - tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id))) - }); - - match item.node { - hir::ItemStatic(_, m, _) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - if m == hir::MutMutable { - encode_family(rbml_w, 'b'); - } else { - encode_family(rbml_w, 'c'); - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_attributes(rbml_w, &item.attrs); - rbml_w.end_tag(); - } - hir::ItemConst(_, _) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'C'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - encode_mir(ecx, rbml_w, item.id); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); - } - hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, FN_FAMILY); - let tps_len = generics.ty_params.len(); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - encode_mir(ecx, rbml_w, item.id); - } - encode_constness(rbml_w, constness); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_method_argument_names(rbml_w, &decl); - rbml_w.end_tag(); - } - hir::ItemMod(ref m) => { - let _task = index.record(def_id, rbml_w); - encode_info_for_mod(ecx, - rbml_w, - m, - &item.attrs, - item.id, - item.name, - &item.vis); - } - hir::ItemForeignMod(ref fm) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'n'); - encode_name(rbml_w, item.name); - - // Encode all the items in this module. - for foreign_item in &fm.items { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); - } - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); - } - hir::ItemTy(..) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); - } - hir::ItemEnum(ref enum_definition, _) => { - let _task = index.record(def_id, rbml_w); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 't'); - encode_item_variances(rbml_w, ecx, item.id); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_repr_attrs(rbml_w, ecx, &item.attrs); - for v in &enum_definition.variants { - encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); - } - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - encode_mir(ecx, rbml_w, item.id); - - // Encode inherent implementations for this enumeration. - encode_inherent_implementations(ecx, rbml_w, def_id); - - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_info_for_item(&mut self, + rbml_w: &mut Encoder, + item: &hir::Item) { + let ecx = self.ecx(); + let tcx = ecx.tcx; - encode_enum_variant_info(ecx, - rbml_w, - def_id, - vis, - index); - } - hir::ItemStruct(ref struct_def, _) => { - /* Index the class*/ - let _task = index.record(def_id, rbml_w); + debug!("encoding info for item at {}", + tcx.sess.codemap().span_to_string(item.span)); - let def = ecx.tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); + let vis = &item.vis; + let def_id = ecx.tcx.map.local_def_id(item.id); - /* Now, make an item for the class itself */ - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', + let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { + (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)), + tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id))) }); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - - encode_item_variances(rbml_w, ecx, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_visibility(rbml_w, vis); - encode_repr_attrs(rbml_w, ecx, &item.attrs); - - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ - encode_struct_fields(rbml_w, variant); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - encode_mir(ecx, rbml_w, item.id); - - // Encode inherent implementations for this structure. - encode_inherent_implementations(ecx, rbml_w, def_id); - - if !struct_def.is_struct() { - let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); - rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, - def_to_u64(ctor_did)); - } - - rbml_w.end_tag(); - - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); - } - - // If this is a tuple-like struct, encode the type of the constructor. - if !struct_def.is_struct() { - encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def, index, item.id); - } - } - hir::ItemDefaultImpl(unsafety, _) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'd'); - encode_name(rbml_w, item.name); - encode_unsafety(rbml_w, unsafety); - - let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); - rbml_w.end_tag(); - } - hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { - let _task = index.record(def_id, rbml_w); - - // We need to encode information about the default methods we - // have inherited, so we drive this based on the impl structure. - let impl_items = tcx.impl_items.borrow(); - let items = impl_items.get(&def_id).unwrap(); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'i'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_unsafety(rbml_w, unsafety); - encode_polarity(rbml_w, polarity); - - match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) { - Some(&kind) => { - rbml_w.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(rbml_w); + match item.node { + hir::ItemStatic(_, m, _) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + if m == hir::MutMutable { + encode_family(rbml_w, 'b'); + } else { + encode_family(rbml_w, 'c'); + } + self.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + encode_attributes(rbml_w, &item.attrs); rbml_w.end_tag(); } - None => {} - } - - for &item_def_id in items { - rbml_w.start_tag(tag_item_impl_item); - match item_def_id { - ty::ConstTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'C'); + hir::ItemConst(_, _) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'C'); + self.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(rbml_w, item.id); + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + rbml_w.end_tag(); + } + hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, FN_FAMILY); + let tps_len = generics.ty_params.len(); + self.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); + if needs_inline || constness == hir::Constness::Const { + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(rbml_w, item.id); } - ty::MethodTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'r'); + encode_constness(rbml_w, constness); + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + self.encode_method_argument_names(rbml_w, &decl); + rbml_w.end_tag(); + } + hir::ItemMod(ref m) => { + let _task = self.record(def_id, rbml_w); + self.encode_info_for_mod(rbml_w, + m, + &item.attrs, + item.id, + item.name, + &item.vis); + } + hir::ItemForeignMod(ref fm) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'n'); + encode_name(rbml_w, item.name); + + // Encode all the items in this module. + for foreign_item in &fm.items { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); } - ty::TypeTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 't'); + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + rbml_w.end_tag(); + } + hir::ItemTy(..) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'y'); + self.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + rbml_w.end_tag(); + } + hir::ItemEnum(ref enum_definition, _) => { + let _task = self.record(def_id, rbml_w); + + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 't'); + encode_item_variances(rbml_w, ecx, item.id); + self.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + self.encode_repr_attrs(rbml_w, &item.attrs); + for v in &enum_definition.variants { + encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); } + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(rbml_w, item.id); + + // Encode inherent implementations for this enumeration. + encode_inherent_implementations(ecx, rbml_w, def_id); + + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + rbml_w.end_tag(); + + self.encode_enum_variant_info(rbml_w, + def_id, + vis); } - rbml_w.end_tag(); - } - let did = ecx.tcx.map.local_def_id(item.id); - if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); - - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); - let parent = trait_def.ancestors(did) - .skip(1) - .next() - .and_then(|node| match node { - specialization_graph::Node::Impl(parent) => Some(parent), - _ => None, + hir::ItemStruct(ref struct_def, _) => { + /* Index the class*/ + let _task = self.record(def_id, rbml_w); + + let def = ecx.tcx.lookup_adt_def(def_id); + let variant = def.struct_variant(); + + /* Now, make an item for the class itself */ + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, match *struct_def { + hir::VariantData::Struct(..) => 'S', + hir::VariantData::Tuple(..) => 's', + hir::VariantData::Unit(..) => 'u', }); - encode_parent_impl(rbml_w, parent); - } - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); - - // Iterate down the trait items, emitting them. We rely on the - // assumption that all of the actually implemented trait items - // appear first in the impl structure, in the same order they do - // in the ast. This is a little sketchy. - let num_implemented_methods = ast_items.len(); - for (i, &trait_item_def_id) in items.iter().enumerate() { - let ast_item = if i < num_implemented_methods { - Some(&ast_items[i]) - } else { - None - }; - - match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { - ty::ConstTraitItem(ref associated_const) => { - encode_info_for_associated_const(ecx, - rbml_w, - index, - &associated_const, - item.id, - ast_item) + self.encode_bounds_and_type_for_item(rbml_w, item.id); + + encode_item_variances(rbml_w, ecx, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + self.encode_visibility(rbml_w, vis); + self.encode_repr_attrs(rbml_w, &item.attrs); + + /* Encode def_ids for each field and method + for methods, write all the stuff get_trait_method + needs to know*/ + self.encode_struct_fields(rbml_w, variant); + + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(rbml_w, item.id); + + // Encode inherent implementations for this structure. + encode_inherent_implementations(ecx, rbml_w, def_id); + + if !struct_def.is_struct() { + let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); + rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, + def_to_u64(ctor_did)); } - ty::MethodTraitItem(ref method_type) => { - encode_info_for_method(ecx, - rbml_w, - index, - &method_type, - false, - item.id, - ast_item) + + rbml_w.end_tag(); + + for field in &variant.fields { + self.encode_field(rbml_w, field); } - ty::TypeTraitItem(ref associated_type) => { - encode_info_for_associated_type(ecx, - rbml_w, - index, - &associated_type, - item.id, - ast_item) + + // If this is a tuple-like struct, encode the type of the constructor. + if !struct_def.is_struct() { + self.encode_info_for_struct_ctor(rbml_w, item.name, struct_def, item.id); } } - } - } - hir::ItemTrait(_, _, _, ref ms) => { - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'I'); - encode_item_variances(rbml_w, ecx, item.id); - let trait_def = tcx.lookup_trait_def(def_id); - let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(rbml_w, trait_def.unsafety); - encode_paren_sugar(rbml_w, trait_def.paren_sugar); - encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); - encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - encode_generics(rbml_w, ecx, index, - &trait_def.generics, &trait_predicates); - encode_predicates(rbml_w, index, - &tcx.lookup_super_predicates(def_id), - tag_item_super_predicates); - encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - rbml_w.start_tag(tag_item_trait_item); - match method_def_id { - ty::ConstTraitItemId(const_def_id) => { - encode_def_id(rbml_w, const_def_id); - encode_item_sort(rbml_w, 'C'); + hir::ItemDefaultImpl(unsafety, _) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'd'); + encode_name(rbml_w, item.name); + encode_unsafety(rbml_w, unsafety); + + let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); + encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + rbml_w.end_tag(); + } + hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { + let _task = self.record(def_id, rbml_w); + + // We need to encode information about the default methods we + // have inherited, so we drive this based on the impl structure. + let impl_items = tcx.impl_items.borrow(); + let items = impl_items.get(&def_id).unwrap(); + + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'i'); + self.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_unsafety(rbml_w, unsafety); + encode_polarity(rbml_w, polarity); + + match tcx.custom_coerce_unsized_kinds + .borrow() + .get(&ecx.tcx.map.local_def_id(item.id)) { + Some(&kind) => { + rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(rbml_w); + rbml_w.end_tag(); + } + None => {} } - ty::MethodTraitItemId(method_def_id) => { - encode_def_id(rbml_w, method_def_id); - encode_item_sort(rbml_w, 'r'); + + for &item_def_id in items { + rbml_w.start_tag(tag_item_impl_item); + match item_def_id { + ty::ConstTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 'C'); + } + ty::MethodTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 'r'); + } + ty::TypeTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 't'); + } + } + rbml_w.end_tag(); } - ty::TypeTraitItemId(type_def_id) => { - encode_def_id(rbml_w, type_def_id); - encode_item_sort(rbml_w, 't'); + let did = ecx.tcx.map.local_def_id(item.id); + if let Some(trait_ref) = tcx.impl_trait_ref(did) { + encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + + let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let parent = trait_def.ancestors(did) + .skip(1) + .next() + .and_then(|node| match node { + specialization_graph::Node::Impl(parent) => + Some(parent), + _ => None, + }); + encode_parent_impl(rbml_w, parent); } - } - rbml_w.end_tag(); - - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(method_def_id.def_id())); - } + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + rbml_w.end_tag(); - // Encode inherent implementations for this trait. - encode_inherent_implementations(ecx, rbml_w, def_id); + // Iterate down the trait items, emitting them. We rely on the + // assumption that all of the actually implemented trait items + // appear first in the impl structure, in the same order they do + // in the ast. This is a little sketchy. + let num_implemented_methods = ast_items.len(); + for (i, &trait_item_def_id) in items.iter().enumerate() { + let ast_item = if i < num_implemented_methods { + Some(&ast_items[i]) + } else { + None + }; + + match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { + ty::ConstTraitItem(ref associated_const) => { + self.encode_info_for_associated_const(rbml_w, + &associated_const, + item.id, + ast_item) + } + ty::MethodTraitItem(ref method_type) => { + self.encode_info_for_method(rbml_w, + &method_type, + false, + item.id, + ast_item) + } + ty::TypeTraitItem(ref associated_type) => { + self.encode_info_for_associated_type(rbml_w, + &associated_type, + item.id, + ast_item) + } + } + } + } + hir::ItemTrait(_, _, _, ref ms) => { + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'I'); + encode_item_variances(rbml_w, ecx, item.id); + let trait_def = tcx.lookup_trait_def(def_id); + let trait_predicates = tcx.lookup_predicates(def_id); + encode_unsafety(rbml_w, trait_def.unsafety); + encode_paren_sugar(rbml_w, trait_def.paren_sugar); + encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); + encode_associated_type_names(rbml_w, &trait_def.associated_type_names); + self.encode_generics(rbml_w, &trait_def.generics, &trait_predicates); + self.encode_predicates(rbml_w, &tcx.lookup_super_predicates(def_id), tag_item_super_predicates); + encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + self.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { + rbml_w.start_tag(tag_item_trait_item); + match method_def_id { + ty::ConstTraitItemId(const_def_id) => { + encode_def_id(rbml_w, const_def_id); + encode_item_sort(rbml_w, 'C'); + } + ty::MethodTraitItemId(method_def_id) => { + encode_def_id(rbml_w, method_def_id); + encode_item_sort(rbml_w, 'r'); + } + ty::TypeTraitItemId(type_def_id) => { + encode_def_id(rbml_w, type_def_id); + encode_item_sort(rbml_w, 't'); + } + } + rbml_w.end_tag(); - rbml_w.end_tag(); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); + } - // Now output the trait item info for each trait item. - let r = tcx.trait_item_def_ids(def_id); - for (i, &item_def_id) in r.iter().enumerate() { - assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); + // Encode inherent implementations for this trait. + encode_inherent_implementations(ecx, rbml_w, def_id); - let _task = index.record(item_def_id.def_id(), rbml_w); - rbml_w.start_tag(tag_items_data_item); + rbml_w.end_tag(); - encode_parent_item(rbml_w, def_id); + // Now output the trait item info for each trait item. + let r = tcx.trait_item_def_ids(def_id); + for (i, &item_def_id) in r.iter().enumerate() { + assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - let stab = tcx.lookup_stability(item_def_id.def_id()); - let depr = tcx.lookup_deprecation(item_def_id.def_id()); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + let _task = self.record(item_def_id.def_id(), rbml_w); + rbml_w.start_tag(tag_items_data_item); - let trait_item_type = - tcx.impl_or_trait_item(item_def_id.def_id()); - let is_nonstatic_method; - match trait_item_type { - ty::ConstTraitItem(associated_const) => { - encode_name(rbml_w, associated_const.name); - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - encode_visibility(rbml_w, associated_const.vis); + self.encode_parent_item(rbml_w, def_id); - encode_family(rbml_w, 'C'); + let stab = tcx.lookup_stability(item_def_id.def_id()); + let depr = tcx.lookup_deprecation(item_def_id.def_id()); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(associated_const.def_id)); + let trait_item_type = + tcx.impl_or_trait_item(item_def_id.def_id()); + let is_nonstatic_method; + match trait_item_type { + ty::ConstTraitItem(associated_const) => { + encode_name(rbml_w, associated_const.name); + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); + self.encode_visibility(rbml_w, associated_const.vis); - is_nonstatic_method = false; - } - ty::MethodTraitItem(method_ty) => { - let method_def_id = item_def_id.def_id(); + encode_family(rbml_w, 'C'); - encode_method_ty_fields(ecx, rbml_w, index, &method_ty); + self.encode_bounds_and_type_for_item( + rbml_w, + ecx.local_id(associated_const.def_id)); - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(rbml_w, - STATIC_METHOD_FAMILY); + is_nonstatic_method = false; } - _ => { - encode_family(rbml_w, - METHOD_FAMILY); + ty::MethodTraitItem(method_ty) => { + let method_def_id = item_def_id.def_id(); + + self.encode_method_ty_fields(rbml_w, &method_ty); + + match method_ty.explicit_self { + ty::ExplicitSelfCategory::Static => { + encode_family(rbml_w, + STATIC_METHOD_FAMILY); + } + _ => { + encode_family(rbml_w, + METHOD_FAMILY); + } + } + self.encode_bounds_and_type_for_item(rbml_w, + ecx.local_id(method_def_id)); + + is_nonstatic_method = method_ty.explicit_self != + ty::ExplicitSelfCategory::Static; } - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(method_def_id)); - - is_nonstatic_method = method_ty.explicit_self != - ty::ExplicitSelfCategory::Static; - } - ty::TypeTraitItem(associated_type) => { - encode_name(rbml_w, associated_type.name); - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_item_sort(rbml_w, 't'); - encode_family(rbml_w, 'y'); - - if let Some(ty) = associated_type.ty { - encode_type(ecx, rbml_w, ty); - } + ty::TypeTraitItem(associated_type) => { + encode_name(rbml_w, associated_type.name); + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); + encode_item_sort(rbml_w, 't'); + encode_family(rbml_w, 'y'); - is_nonstatic_method = false; - } - } + if let Some(ty) = associated_type.ty { + self.encode_type(rbml_w, ty); + } - let trait_item = &ms[i]; - encode_attributes(rbml_w, &trait_item.attrs); - match trait_item.node { - hir::ConstTraitItem(_, ref default) => { - if default.is_some() { - encode_item_sort(rbml_w, 'C'); - } else { - encode_item_sort(rbml_w, 'c'); + is_nonstatic_method = false; + } } - encode_inlined_item(ecx, rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - encode_mir(ecx, rbml_w, trait_item.id); - } - hir::MethodTraitItem(ref sig, ref body) => { - // If this is a static method, we've already - // encoded this. - if is_nonstatic_method { - // FIXME: I feel like there is something funny - // going on. - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(item_def_id.def_id())); - } + let trait_item = &ms[i]; + encode_attributes(rbml_w, &trait_item.attrs); + match trait_item.node { + hir::ConstTraitItem(_, ref default) => { + if default.is_some() { + encode_item_sort(rbml_w, 'C'); + } else { + encode_item_sort(rbml_w, 'c'); + } + + encode_inlined_item(ecx, rbml_w, + InlinedItemRef::TraitItem(def_id, trait_item)); + self.encode_mir(rbml_w, trait_item.id); + } + hir::MethodTraitItem(ref sig, ref body) => { + // If this is a static method, we've already + // encoded this. + if is_nonstatic_method { + self.encode_bounds_and_type_for_item( + rbml_w, + ecx.local_id(item_def_id.def_id())); + } + + if body.is_some() { + encode_item_sort(rbml_w, 'p'); + encode_inlined_item(ecx, rbml_w, + InlinedItemRef::TraitItem(def_id, trait_item)); + self.encode_mir(rbml_w, trait_item.id); + } else { + encode_item_sort(rbml_w, 'r'); + } + self.encode_method_argument_names(rbml_w, &sig.decl); + } - if body.is_some() { - encode_item_sort(rbml_w, 'p'); - encode_inlined_item(ecx, rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - encode_mir(ecx, rbml_w, trait_item.id); - } else { - encode_item_sort(rbml_w, 'r'); + hir::TypeTraitItem(..) => {} } - encode_method_argument_names(rbml_w, &sig.decl); - } - hir::TypeTraitItem(..) => {} + rbml_w.end_tag(); + } + } + hir::ItemExternCrate(_) | hir::ItemUse(_) => { + // these are encoded separately } - - rbml_w.end_tag(); } - } - hir::ItemExternCrate(_) | hir::ItemUse(_) => { - // these are encoded separately - } } } -fn encode_info_for_foreign_item<'a, 'tcx>(rbml_w: &mut Encoder, - nitem: &hir::ForeignItem, - index: &mut IndexBuilder<'a, 'tcx>) { - let ecx = index.ecx(); - - debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); - let def_id = ecx.tcx.map.local_def_id(nitem.id); - let abi = ecx.tcx.map.get_foreign_abi(nitem.id); - - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - let parent_id = ecx.tcx.map.get_parent(nitem.id); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_visibility(rbml_w, &nitem.vis); - match nitem.node { - hir::ForeignItemFn(ref fndecl, _) => { - encode_family(rbml_w, FN_FAMILY); - encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); - encode_name(rbml_w, nitem.name); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem)); - encode_mir(ecx, rbml_w, nitem.id); - } - encode_attributes(rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_method_argument_names(rbml_w, &fndecl); - } - hir::ForeignItemStatic(_, mutbl) => { - if mutbl { - encode_family(rbml_w, 'b'); - } else { - encode_family(rbml_w, 'c'); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_info_for_foreign_item(&mut self, + rbml_w: &mut Encoder, + nitem: &hir::ForeignItem) { + let ecx = self.ecx(); + + debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); + let def_id = ecx.tcx.map.local_def_id(nitem.id); + let abi = ecx.tcx.map.get_foreign_abi(nitem.id); + + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + let parent_id = ecx.tcx.map.get_parent(nitem.id); + self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + self.encode_visibility(rbml_w, &nitem.vis); + match nitem.node { + hir::ForeignItemFn(ref fndecl, _) => { + encode_family(rbml_w, FN_FAMILY); + self.encode_bounds_and_type_for_item(rbml_w, nitem.id); + encode_name(rbml_w, nitem.name); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem)); + self.encode_mir(rbml_w, nitem.id); + } + encode_attributes(rbml_w, &nitem.attrs); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + self.encode_method_argument_names(rbml_w, &fndecl); + } + hir::ForeignItemStatic(_, mutbl) => { + if mutbl { + encode_family(rbml_w, 'b'); + } else { + encode_family(rbml_w, 'c'); + } + self.encode_bounds_and_type_for_item(rbml_w, nitem.id); + encode_attributes(rbml_w, &nitem.attrs); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + encode_name(rbml_w, nitem.name); + } } - encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); - encode_attributes(rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_name(rbml_w, nitem.name); - } + rbml_w.end_tag(); } - rbml_w.end_tag(); } struct EncodeVisitor<'a, 'data:'a, 'ecx: 'a, 'tcx: 'ecx> { - rbml_w_for_visit_item: &'a mut Encoder<'data>, + rbml_w: &'a mut Encoder<'data>, index: &'a mut IndexBuilder<'ecx, 'tcx>, } impl<'a, 'data, 'ecx, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'data, 'ecx, 'tcx> { fn visit_expr(&mut self, ex: &'tcx hir::Expr) { intravisit::walk_expr(self, ex); - encode_info_for_expr(ex, self.rbml_w_for_visit_item, self.index); + self.index.encode_info_for_expr(ex, self.rbml_w); } fn visit_item(&mut self, i: &'tcx hir::Item) { intravisit::walk_item(self, i); - encode_info_for_item(self.rbml_w_for_visit_item, i, self.index); + self.index.encode_info_for_item(self.rbml_w, i); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - encode_info_for_foreign_item(self.rbml_w_for_visit_item, ni, self.index); + self.index.encode_info_for_foreign_item(self.rbml_w, ni); } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { intravisit::walk_ty(self, ty); @@ -1307,50 +1314,50 @@ impl<'a, 'data, 'ecx, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'data, 'ecx, 'tc } } -fn encode_info_for_ty(ty: &hir::Ty, - rbml_w: &mut Encoder, - index: &mut IndexBuilder) { - let ecx = index.ecx(); - if let hir::TyImplTrait(_) = ty.node { - let def_id = ecx.tcx.map.local_def_id(ty.id); - let _task = index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, ty.id); - rbml_w.end_tag(); +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { + fn encode_info_for_ty(&mut self, + ty: &hir::Ty, + rbml_w: &mut Encoder) { + let ecx = self.ecx(); + if let hir::TyImplTrait(_) = ty.node { + let def_id = ecx.tcx.map.local_def_id(ty.id); + let _task = self.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'y'); + self.encode_bounds_and_type_for_item(rbml_w, ecx, ty.id); + rbml_w.end_tag(); + } } -} -fn encode_info_for_expr(expr: &hir::Expr, - rbml_w: &mut Encoder, - index: &mut IndexBuilder) { - let ecx = index.ecx(); + fn encode_info_for_expr(&mut self, expr: &hir::Expr, rbml_w: &mut Encoder) { + let ecx = self.ecx(); - match expr.node { - hir::ExprClosure(..) => { - let def_id = ecx.tcx.map.local_def_id(expr.id); + match expr.node { + hir::ExprClosure(..) => { + let def_id = ecx.tcx.map.local_def_id(expr.id); - let _task = index.record(def_id, rbml_w); + let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_name(rbml_w, syntax::parse::token::intern("")); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_name(rbml_w, syntax::parse::token::intern("")); - rbml_w.start_tag(tag_items_closure_ty); - write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); - rbml_w.end_tag(); + rbml_w.start_tag(tag_items_closure_ty); + write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); + rbml_w.end_tag(); - rbml_w.start_tag(tag_items_closure_kind); - ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); - rbml_w.end_tag(); + rbml_w.start_tag(tag_items_closure_kind); + ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); + rbml_w.end_tag(); - assert!(ecx.mir_map.map.contains_key(&def_id)); - encode_mir(ecx, rbml_w, expr.id); + assert!(ecx.mir_map.map.contains_key(&def_id)); + self.encode_mir(rbml_w, expr.id); - rbml_w.end_tag(); + rbml_w.end_tag(); + } + _ => { } } - _ => { } } } @@ -1364,18 +1371,17 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &'a EncodeContext<'a, 'tcx>, { let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); - encode_info_for_mod(ecx, - rbml_w, - &krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public); + index.encode_info_for_mod(rbml_w, + &krate.module, + &[], + CRATE_NODE_ID, + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public); } krate.visit_all_items(&mut EncodeVisitor { index: &mut index, - rbml_w_for_visit_item: &mut *rbml_w, + rbml_w: &mut *rbml_w, }); rbml_w.end_tag(); From 6b76932ba84958666d0866d5ae21703b3be14701 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 17:29:24 -0400 Subject: [PATCH 080/768] introduce Deref/DerefMut to model subtype rel The idea is that ItemContentBuilder is a base-type of IndexBuilder. --- src/librustc_metadata/encoder.rs | 18 ++++++---- src/librustc_metadata/index_builder.rs | 50 +++++++++++++++++++------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f256d1269340c..49bd861b131e4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -54,7 +54,7 @@ use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; -use super::index_builder::{IndexBuilder, XRef}; +use super::index_builder::{IndexBuilder, ItemContentBuilder, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, @@ -132,7 +132,7 @@ fn encode_item_variances(rbml_w: &mut Encoder, rbml_w.end_tag(); } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_bounds_and_type_for_item(&mut self, rbml_w: &mut Encoder, id: NodeId) { @@ -164,7 +164,7 @@ fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.mark_stable_position(); } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_type(&mut self, rbml_w: &mut Encoder, typ: Ty<'tcx>) { @@ -200,7 +200,9 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { rbml_w.end_tag(); } } +} +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { fn encode_enum_variant_info(&mut self, rbml_w: &mut Encoder, did: DefId, @@ -302,7 +304,7 @@ fn encode_reexports(ecx: &EncodeContext, } } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_info_for_mod(&mut self, rbml_w: &mut Encoder, md: &hir::Mod, @@ -487,7 +489,9 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { rbml_w.end_tag(); } +} +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_generics(&mut self, rbml_w: &mut Encoder, generics: &ty::Generics<'tcx>, @@ -532,7 +536,9 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { _ => encode_family(rbml_w, METHOD_FAMILY) } } +} +impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { fn encode_info_for_associated_const(&mut self, rbml_w: &mut Encoder, associated_const: &ty::AssociatedConst, @@ -680,7 +686,9 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } rbml_w.end_tag(); } +} +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_repr_attrs(&mut self, rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { @@ -1237,9 +1245,7 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } } -} -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { fn encode_info_for_foreign_item(&mut self, rbml_w: &mut Encoder, nitem: &hir::ForeignItem) { diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 1e1ae06443643..915bf98519c90 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -15,11 +15,20 @@ use rustc::dep_graph::{DepNode, DepTask}; use rustc::hir::def_id::DefId; use rustc::ty; use rustc_data_structures::fnv::FnvHashMap; +use std::ops::{Deref, DerefMut}; +/// Builder that can encode new items, adding them into the index. +/// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'tcx: 'a> { - ecx: &'a EncodeContext<'a, 'tcx>, items: IndexData, + builder: ItemContentBuilder<'a, 'tcx>, +} + +/// Builder that can encode the content of items, but can't start a +/// new item itself. Most code is attached to here. +pub struct ItemContentBuilder<'a, 'tcx: 'a> { xrefs: FnvHashMap, u32>, // sequentially-assigned + ecx: &'a EncodeContext<'a, 'tcx>, } /// "interned" entries referenced by id @@ -29,16 +38,14 @@ pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { pub fn new(ecx: &'a EncodeContext<'a, 'tcx>) -> Self { IndexBuilder { - ecx: ecx, items: IndexData::new(ecx.tcx.map.num_local_def_ids()), - xrefs: FnvHashMap() + builder: ItemContentBuilder { + ecx: ecx, + xrefs: FnvHashMap(), + }, } } - pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { - self.ecx - } - /// Records that `id` is being emitted at the current offset. /// This data is later used to construct the item index in the /// metadata so we can quickly find the data for a given item. @@ -51,13 +58,32 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)) } - pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { - let old_len = self.xrefs.len() as u32; - *self.xrefs.entry(xref).or_insert(old_len) + pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { + (self.items, self.builder.xrefs) } +} - pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { - (self.items, self.xrefs) +impl<'a, 'tcx> Deref for IndexBuilder<'a, 'tcx> { + type Target = ItemContentBuilder<'a, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.builder + } +} + +impl<'a, 'tcx> DerefMut for IndexBuilder<'a, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.builder } } +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { + pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { + self.ecx + } + + pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { + let old_len = self.xrefs.len() as u32; + *self.xrefs.entry(xref).or_insert(old_len) + } +} From baccdc01ae608920602fda8411f1ff8f127ebef2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Aug 2016 21:37:53 -0400 Subject: [PATCH 081/768] make record take a closure --- src/librustc_metadata/encoder.rs | 1049 ++++++++++++------------ src/librustc_metadata/index_builder.rs | 12 +- 2 files changed, 518 insertions(+), 543 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 49bd861b131e4..87c7b36cf87e6 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -221,37 +221,35 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { self.encode_field(rbml_w, field); } - let _task = self.record(vid, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, vid); - encode_family(rbml_w, match variant.kind { - ty::VariantKind::Struct => 'V', - ty::VariantKind::Tuple => 'v', - ty::VariantKind::Unit => 'w', - }); - encode_name(rbml_w, variant.name); - self.encode_parent_item(rbml_w, did); - self.encode_visibility(rbml_w, vis); - - let attrs = ecx.tcx.get_attrs(vid); - encode_attributes(rbml_w, &attrs); - self.encode_repr_attrs(rbml_w, &attrs); + self.record(vid, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, vid); + encode_family(rbml_w, match variant.kind { + ty::VariantKind::Struct => 'V', + ty::VariantKind::Tuple => 'v', + ty::VariantKind::Unit => 'w', + }); + encode_name(rbml_w, variant.name); + this.encode_parent_item(rbml_w, did); + this.encode_visibility(rbml_w, vis); - let stab = ecx.tcx.lookup_stability(vid); - let depr = ecx.tcx.lookup_deprecation(vid); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + let attrs = ecx.tcx.get_attrs(vid); + encode_attributes(rbml_w, &attrs); + this.encode_repr_attrs(rbml_w, &attrs); - self.encode_struct_fields(rbml_w, variant); + let stab = ecx.tcx.lookup_stability(vid); + let depr = ecx.tcx.lookup_deprecation(vid); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - let specified_disr_val = variant.disr_val; - if specified_disr_val != disr_val { - self.encode_disr_val(rbml_w, specified_disr_val); - disr_val = specified_disr_val; - } - self.encode_bounds_and_type_for_item(rbml_w, variant_node_id); + this.encode_struct_fields(rbml_w, variant); - rbml_w.end_tag(); + let specified_disr_val = variant.disr_val; + if specified_disr_val != disr_val { + this.encode_disr_val(rbml_w, specified_disr_val); + disr_val = specified_disr_val; + } + this.encode_bounds_and_type_for_item(rbml_w, variant_node_id); + }); disr_val = disr_val.wrap_incr(); } @@ -314,7 +312,6 @@ impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { vis: &hir::Visibility) { let ecx = self.ecx(); - rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); encode_family(rbml_w, 'm'); encode_name(rbml_w, name); @@ -346,8 +343,6 @@ impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { encode_reexports(ecx, rbml_w, id); } encode_attributes(rbml_w, attrs); - - rbml_w.end_tag(); } fn encode_struct_field_family(&mut self, rbml_w: &mut Encoder, @@ -438,20 +433,18 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let nm = field.name; let id = ecx.local_id(field.did); - let _task = self.record(field.did, rbml_w); - rbml_w.start_tag(tag_items_data_item); - debug!("encode_field: encoding {} {}", nm, id); - self.encode_struct_field_family(rbml_w, field.vis); - encode_name(rbml_w, nm); - self.encode_bounds_and_type_for_item(rbml_w, id); - encode_def_id_and_key(ecx, rbml_w, field.did); - - let stab = ecx.tcx.lookup_stability(field.did); - let depr = ecx.tcx.lookup_deprecation(field.did); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + self.record(field.did, rbml_w, |this, rbml_w| { + debug!("encode_field: encoding {} {}", nm, id); + this.encode_struct_field_family(rbml_w, field.vis); + encode_name(rbml_w, nm); + this.encode_bounds_and_type_for_item(rbml_w, id); + encode_def_id_and_key(ecx, rbml_w, field.did); - rbml_w.end_tag(); + let stab = ecx.tcx.lookup_stability(field.did); + let depr = ecx.tcx.lookup_deprecation(field.did); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + }); } } @@ -465,29 +458,29 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let ctor_id = struct_def.id(); let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - let _task = self.record(ctor_def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, ctor_def_id); - encode_family(rbml_w, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', - }); - self.encode_bounds_and_type_for_item(rbml_w, ctor_id); - encode_name(rbml_w, name); - self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); - - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + self.record(ctor_def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, ctor_def_id); + encode_family(rbml_w, match *struct_def { + hir::VariantData::Struct(..) => 'S', + hir::VariantData::Tuple(..) => 's', + hir::VariantData::Unit(..) => 'u', + }); + this.encode_bounds_and_type_for_item(rbml_w, ctor_id); + encode_name(rbml_w, name); + this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); - // indicate that this is a tuple struct ctor, because downstream users will normally want - // the tuple struct definition, but without this there is no way for them to tell that - // they actually have a ctor rather than a normal function - rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + // indicate that this is a tuple struct ctor, because + // downstream users will normally want the tuple struct + // definition, but without this there is no way for them + // to tell that they actually have a ctor rather than a + // normal function + rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + }); } } @@ -549,35 +542,32 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { associated_const.def_id, associated_const.name); - let _task = self.record(associated_const.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - encode_name(rbml_w, associated_const.name); - self.encode_visibility(rbml_w, associated_const.vis); - encode_family(rbml_w, 'C'); - - self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'C'); + self.record(associated_const.def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); + encode_name(rbml_w, associated_const.name); + this.encode_visibility(rbml_w, associated_const.vis); + encode_family(rbml_w, 'C'); - self.encode_bounds_and_type_for_item(rbml_w, ecx.local_id(associated_const.def_id)); + this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 'C'); - let stab = ecx.tcx.lookup_stability(associated_const.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + this.encode_bounds_and_type_for_item(rbml_w, ecx.local_id(associated_const.def_id)); - if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_defaultness(rbml_w, ii.defaultness); - encode_inlined_item(ecx, - rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - ii)); - self.encode_mir(rbml_w, ii.id); - } + let stab = ecx.tcx.lookup_stability(associated_const.def_id); + let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + if let Some(ii) = impl_item_opt { + encode_attributes(rbml_w, &ii.attrs); + encode_defaultness(rbml_w, ii.defaultness); + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + ii)); + this.encode_mir(rbml_w, ii.id); + } + }); } fn encode_info_for_method(&mut self, @@ -590,43 +580,40 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); - let _task = self.record(m.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - self.encode_method_ty_fields(rbml_w, m); - self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'r'); + self.record(m.def_id, rbml_w, |this, rbml_w| { + this.encode_method_ty_fields(rbml_w, m); + this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 'r'); - let stab = ecx.tcx.lookup_stability(m.def_id); - let depr = ecx.tcx.lookup_deprecation(m.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + let stab = ecx.tcx.lookup_stability(m.def_id); + let depr = ecx.tcx.lookup_deprecation(m.def_id); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - let m_node_id = ecx.local_id(m.def_id); - self.encode_bounds_and_type_for_item(rbml_w, m_node_id); - - if let Some(impl_item) = impl_item_opt { - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(rbml_w, &impl_item.attrs); - let generics = ecx.tcx.lookup_generics(m.def_id); - let types = generics.parent_types as usize + generics.types.len(); - let needs_inline = types > 0 || is_default_impl || - attr::requests_inline(&impl_item.attrs); - if needs_inline || sig.constness == hir::Constness::Const { - encode_inlined_item( - ecx, - rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - impl_item)); - self.encode_mir(rbml_w, impl_item.id); + let m_node_id = ecx.local_id(m.def_id); + this.encode_bounds_and_type_for_item(rbml_w, m_node_id); + + if let Some(impl_item) = impl_item_opt { + if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { + encode_attributes(rbml_w, &impl_item.attrs); + let generics = ecx.tcx.lookup_generics(m.def_id); + let types = generics.parent_types as usize + generics.types.len(); + let needs_inline = types > 0 || is_default_impl || + attr::requests_inline(&impl_item.attrs); + if needs_inline || sig.constness == hir::Constness::Const { + encode_inlined_item( + ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + impl_item)); + this.encode_mir(rbml_w, impl_item.id); + } + encode_constness(rbml_w, sig.constness); + encode_defaultness(rbml_w, impl_item.defaultness); + this.encode_method_argument_names(rbml_w, &sig.decl); } - encode_constness(rbml_w, sig.constness); - encode_defaultness(rbml_w, impl_item.defaultness); - self.encode_method_argument_names(rbml_w, &sig.decl); } - } - - rbml_w.end_tag(); + }); } fn encode_info_for_associated_type(&mut self, @@ -639,38 +626,37 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { associated_type.def_id, associated_type.name); - let _task = self.record(associated_type.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_name(rbml_w, associated_type.name); - self.encode_visibility(rbml_w, associated_type.vis); - encode_family(rbml_w, 'y'); - self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 't'); - - let stab = ecx.tcx.lookup_stability(associated_type.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + self.record(associated_type.def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); + encode_name(rbml_w, associated_type.name); + this.encode_visibility(rbml_w, associated_type.vis); + encode_family(rbml_w, 'y'); + this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 't'); - if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_defaultness(rbml_w, ii.defaultness); - } else { - // TODO this looks bogus and unnecessary - self.encode_predicates(rbml_w, - &ecx.tcx.lookup_predicates(associated_type.def_id), - tag_item_generics); - } + let stab = ecx.tcx.lookup_stability(associated_type.def_id); + let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - if let Some(ty) = associated_type.ty { - self.encode_type(rbml_w, ty); - } + if let Some(ii) = impl_item_opt { + encode_attributes(rbml_w, &ii.attrs); + encode_defaultness(rbml_w, ii.defaultness); + } else { + // TODO this looks bogus and unnecessary + this.encode_predicates(rbml_w, + &ecx.tcx.lookup_predicates(associated_type.def_id), + tag_item_generics); + } - rbml_w.end_tag(); + if let Some(ty) = associated_type.ty { + this.encode_type(rbml_w, ty); + } + }); } +} +impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_method_argument_names(&mut self, rbml_w: &mut Encoder, decl: &hir::FnDecl) { @@ -686,9 +672,7 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } rbml_w.end_tag(); } -} -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { fn encode_repr_attrs(&mut self, rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { @@ -802,120 +786,114 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { match item.node { hir::ItemStatic(_, m, _) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - if m == hir::MutMutable { - encode_family(rbml_w, 'b'); - } else { - encode_family(rbml_w, 'c'); - } - self.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_attributes(rbml_w, &item.attrs); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + if m == hir::MutMutable { + encode_family(rbml_w, 'b'); + } else { + encode_family(rbml_w, 'c'); + } + this.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + encode_attributes(rbml_w, &item.attrs); + }); } hir::ItemConst(_, _) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'C'); - self.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(rbml_w, item.id); - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'C'); + this.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(rbml_w, item.id); + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + }); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, FN_FAMILY); - let tps_len = generics.ty_params.len(); - self.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(rbml_w, item.id); - } - encode_constness(rbml_w, constness); - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - self.encode_method_argument_names(rbml_w, &decl); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, FN_FAMILY); + let tps_len = generics.ty_params.len(); + this.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); + if needs_inline || constness == hir::Constness::Const { + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(rbml_w, item.id); + } + encode_constness(rbml_w, constness); + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + this.encode_method_argument_names(rbml_w, &decl); + }); } hir::ItemMod(ref m) => { - let _task = self.record(def_id, rbml_w); - self.encode_info_for_mod(rbml_w, - m, - &item.attrs, - item.id, - item.name, - &item.vis); + self.record(def_id, rbml_w, |this, rbml_w| { + this.encode_info_for_mod(rbml_w, + m, + &item.attrs, + item.id, + item.name, + &item.vis); + }); } hir::ItemForeignMod(ref fm) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'n'); - encode_name(rbml_w, item.name); - - // Encode all the items in this module. - for foreign_item in &fm.items { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); - } - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'n'); + encode_name(rbml_w, item.name); + + // Encode all the items in this module. + for foreign_item in &fm.items { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); + } + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + }); } hir::ItemTy(..) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - self.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'y'); + this.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + }); } hir::ItemEnum(ref enum_definition, _) => { - let _task = self.record(def_id, rbml_w); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 't'); - encode_item_variances(rbml_w, ecx, item.id); - self.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - self.encode_repr_attrs(rbml_w, &item.attrs); - for v in &enum_definition.variants { - encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); - } - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(rbml_w, item.id); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 't'); + encode_item_variances(rbml_w, ecx, item.id); + this.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + this.encode_repr_attrs(rbml_w, &item.attrs); + for v in &enum_definition.variants { + encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); + } + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(rbml_w, item.id); - // Encode inherent implementations for this enumeration. - encode_inherent_implementations(ecx, rbml_w, def_id); + // Encode inherent implementations for this enumeration. + encode_inherent_implementations(ecx, rbml_w, def_id); - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + }); self.encode_enum_variant_info(rbml_w, def_id, @@ -923,47 +901,44 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } hir::ItemStruct(ref struct_def, _) => { /* Index the class*/ - let _task = self.record(def_id, rbml_w); - let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - /* Now, make an item for the class itself */ - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', - }); - self.encode_bounds_and_type_for_item(rbml_w, item.id); - - encode_item_variances(rbml_w, ecx, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - self.encode_visibility(rbml_w, vis); - self.encode_repr_attrs(rbml_w, &item.attrs); - - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ - self.encode_struct_fields(rbml_w, variant); + self.record(def_id, rbml_w, |this, rbml_w| { + /* Now, make an item for the class itself */ + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, match *struct_def { + hir::VariantData::Struct(..) => 'S', + hir::VariantData::Tuple(..) => 's', + hir::VariantData::Unit(..) => 'u', + }); + this.encode_bounds_and_type_for_item(rbml_w, item.id); + + encode_item_variances(rbml_w, ecx, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + this.encode_visibility(rbml_w, vis); + this.encode_repr_attrs(rbml_w, &item.attrs); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(rbml_w, item.id); + /* Encode def_ids for each field and method + for methods, write all the stuff get_trait_method + needs to know*/ + this.encode_struct_fields(rbml_w, variant); - // Encode inherent implementations for this structure. - encode_inherent_implementations(ecx, rbml_w, def_id); + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(rbml_w, item.id); - if !struct_def.is_struct() { - let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); - rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, - def_to_u64(ctor_did)); - } + // Encode inherent implementations for this structure. + encode_inherent_implementations(ecx, rbml_w, def_id); - rbml_w.end_tag(); + if !struct_def.is_struct() { + let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); + rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, + def_to_u64(ctor_did)); + } + }); for field in &variant.fields { self.encode_field(rbml_w, field); @@ -975,81 +950,81 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } hir::ItemDefaultImpl(unsafety, _) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'd'); - encode_name(rbml_w, item.name); - encode_unsafety(rbml_w, unsafety); + self.record(def_id, rbml_w, |_this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'd'); + encode_name(rbml_w, item.name); + encode_unsafety(rbml_w, unsafety); - let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); - rbml_w.end_tag(); + let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); + encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + }); } hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { - let _task = self.record(def_id, rbml_w); - // We need to encode information about the default methods we // have inherited, so we drive this based on the impl structure. let impl_items = tcx.impl_items.borrow(); - let items = impl_items.get(&def_id).unwrap(); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'i'); - self.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_unsafety(rbml_w, unsafety); - encode_polarity(rbml_w, polarity); - - match tcx.custom_coerce_unsized_kinds - .borrow() - .get(&ecx.tcx.map.local_def_id(item.id)) { - Some(&kind) => { - rbml_w.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(rbml_w); - rbml_w.end_tag(); + let items = &impl_items[&def_id]; + + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'i'); + this.encode_bounds_and_type_for_item(rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_unsafety(rbml_w, unsafety); + encode_polarity(rbml_w, polarity); + + match + tcx.custom_coerce_unsized_kinds + .borrow() + .get(&ecx.tcx.map.local_def_id(item.id)) + { + Some(&kind) => { + rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(rbml_w); + rbml_w.end_tag(); + } + None => {} } - None => {} - } - for &item_def_id in items { - rbml_w.start_tag(tag_item_impl_item); - match item_def_id { - ty::ConstTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'C'); - } - ty::MethodTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'r'); - } - ty::TypeTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 't'); + for &item_def_id in items { + rbml_w.start_tag(tag_item_impl_item); + match item_def_id { + ty::ConstTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 'C'); + } + ty::MethodTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 'r'); + } + ty::TypeTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 't'); + } } + rbml_w.end_tag(); } - rbml_w.end_tag(); - } - let did = ecx.tcx.map.local_def_id(item.id); - if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); - let parent = trait_def.ancestors(did) - .skip(1) - .next() - .and_then(|node| match node { - specialization_graph::Node::Impl(parent) => - Some(parent), - _ => None, - }); - encode_parent_impl(rbml_w, parent); - } - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - rbml_w.end_tag(); + let did = ecx.tcx.map.local_def_id(item.id); + if let Some(trait_ref) = tcx.impl_trait_ref(did) { + encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + + let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let parent = trait_def.ancestors(did) + .skip(1) + .next() + .and_then(|node| match node { + specialization_graph::Node::Impl(parent) => + Some(parent), + _ => None, + }); + encode_parent_impl(rbml_w, parent); + } + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + }); // Iterate down the trait items, emitting them. We rely on the // assumption that all of the actually implemented trait items @@ -1087,157 +1062,157 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } hir::ItemTrait(_, _, _, ref ms) => { - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'I'); - encode_item_variances(rbml_w, ecx, item.id); - let trait_def = tcx.lookup_trait_def(def_id); - let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(rbml_w, trait_def.unsafety); - encode_paren_sugar(rbml_w, trait_def.paren_sugar); - encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); - encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - self.encode_generics(rbml_w, &trait_def.generics, &trait_predicates); - self.encode_predicates(rbml_w, &tcx.lookup_super_predicates(def_id), tag_item_super_predicates); - encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - self.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - rbml_w.start_tag(tag_item_trait_item); - match method_def_id { - ty::ConstTraitItemId(const_def_id) => { - encode_def_id(rbml_w, const_def_id); - encode_item_sort(rbml_w, 'C'); - } - ty::MethodTraitItemId(method_def_id) => { - encode_def_id(rbml_w, method_def_id); - encode_item_sort(rbml_w, 'r'); - } - ty::TypeTraitItemId(type_def_id) => { - encode_def_id(rbml_w, type_def_id); - encode_item_sort(rbml_w, 't'); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'I'); + encode_item_variances(rbml_w, ecx, item.id); + let trait_def = tcx.lookup_trait_def(def_id); + let trait_predicates = tcx.lookup_predicates(def_id); + encode_unsafety(rbml_w, trait_def.unsafety); + encode_paren_sugar(rbml_w, trait_def.paren_sugar); + encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); + encode_associated_type_names(rbml_w, &trait_def.associated_type_names); + this.encode_generics(rbml_w, &trait_def.generics, &trait_predicates); + this.encode_predicates(rbml_w, + &tcx.lookup_super_predicates(def_id), + tag_item_super_predicates); + encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + this.encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { + rbml_w.start_tag(tag_item_trait_item); + match method_def_id { + ty::ConstTraitItemId(const_def_id) => { + encode_def_id(rbml_w, const_def_id); + encode_item_sort(rbml_w, 'C'); + } + ty::MethodTraitItemId(method_def_id) => { + encode_def_id(rbml_w, method_def_id); + encode_item_sort(rbml_w, 'r'); + } + ty::TypeTraitItemId(type_def_id) => { + encode_def_id(rbml_w, type_def_id); + encode_item_sort(rbml_w, 't'); + } } - } - rbml_w.end_tag(); - - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(method_def_id.def_id())); - } + rbml_w.end_tag(); - // Encode inherent implementations for this trait. - encode_inherent_implementations(ecx, rbml_w, def_id); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); + } - rbml_w.end_tag(); + // Encode inherent implementations for this trait. + encode_inherent_implementations(ecx, rbml_w, def_id); + }); // Now output the trait item info for each trait item. let r = tcx.trait_item_def_ids(def_id); for (i, &item_def_id) in r.iter().enumerate() { assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - let _task = self.record(item_def_id.def_id(), rbml_w); - rbml_w.start_tag(tag_items_data_item); + self.record(item_def_id.def_id(), rbml_w, |this, rbml_w| { + this.encode_parent_item(rbml_w, def_id); - self.encode_parent_item(rbml_w, def_id); + let stab = tcx.lookup_stability(item_def_id.def_id()); + let depr = tcx.lookup_deprecation(item_def_id.def_id()); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); - let stab = tcx.lookup_stability(item_def_id.def_id()); - let depr = tcx.lookup_deprecation(item_def_id.def_id()); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - - let trait_item_type = - tcx.impl_or_trait_item(item_def_id.def_id()); - let is_nonstatic_method; - match trait_item_type { - ty::ConstTraitItem(associated_const) => { - encode_name(rbml_w, associated_const.name); - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - self.encode_visibility(rbml_w, associated_const.vis); - - encode_family(rbml_w, 'C'); + let trait_item_type = + tcx.impl_or_trait_item(item_def_id.def_id()); + let is_nonstatic_method; + match trait_item_type { + ty::ConstTraitItem(associated_const) => { + encode_name(rbml_w, associated_const.name); + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); + this.encode_visibility(rbml_w, associated_const.vis); - self.encode_bounds_and_type_for_item( - rbml_w, - ecx.local_id(associated_const.def_id)); + encode_family(rbml_w, 'C'); - is_nonstatic_method = false; - } - ty::MethodTraitItem(method_ty) => { - let method_def_id = item_def_id.def_id(); - - self.encode_method_ty_fields(rbml_w, &method_ty); + this.encode_bounds_and_type_for_item( + rbml_w, + ecx.local_id(associated_const.def_id)); - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(rbml_w, - STATIC_METHOD_FAMILY); - } - _ => { - encode_family(rbml_w, - METHOD_FAMILY); - } + is_nonstatic_method = false; } - self.encode_bounds_and_type_for_item(rbml_w, - ecx.local_id(method_def_id)); + ty::MethodTraitItem(method_ty) => { + let method_def_id = item_def_id.def_id(); + + this.encode_method_ty_fields(rbml_w, &method_ty); + + match method_ty.explicit_self { + ty::ExplicitSelfCategory::Static => { + encode_family(rbml_w, + STATIC_METHOD_FAMILY); + } + _ => { + encode_family(rbml_w, + METHOD_FAMILY); + } + } + this.encode_bounds_and_type_for_item(rbml_w, + ecx.local_id(method_def_id)); - is_nonstatic_method = method_ty.explicit_self != - ty::ExplicitSelfCategory::Static; - } - ty::TypeTraitItem(associated_type) => { - encode_name(rbml_w, associated_type.name); - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_item_sort(rbml_w, 't'); - encode_family(rbml_w, 'y'); - - if let Some(ty) = associated_type.ty { - self.encode_type(rbml_w, ty); + is_nonstatic_method = method_ty.explicit_self != + ty::ExplicitSelfCategory::Static; } + ty::TypeTraitItem(associated_type) => { + encode_name(rbml_w, associated_type.name); + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); + encode_item_sort(rbml_w, 't'); + encode_family(rbml_w, 'y'); + + if let Some(ty) = associated_type.ty { + this.encode_type(rbml_w, ty); + } - is_nonstatic_method = false; - } - } - - let trait_item = &ms[i]; - encode_attributes(rbml_w, &trait_item.attrs); - match trait_item.node { - hir::ConstTraitItem(_, ref default) => { - if default.is_some() { - encode_item_sort(rbml_w, 'C'); - } else { - encode_item_sort(rbml_w, 'c'); + is_nonstatic_method = false; } - - encode_inlined_item(ecx, rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - self.encode_mir(rbml_w, trait_item.id); } - hir::MethodTraitItem(ref sig, ref body) => { - // If this is a static method, we've already - // encoded this. - if is_nonstatic_method { - self.encode_bounds_and_type_for_item( - rbml_w, - ecx.local_id(item_def_id.def_id())); - } - if body.is_some() { - encode_item_sort(rbml_w, 'p'); + let trait_item = &ms[i]; + encode_attributes(rbml_w, &trait_item.attrs); + match trait_item.node { + hir::ConstTraitItem(_, ref default) => { + if default.is_some() { + encode_item_sort(rbml_w, 'C'); + } else { + encode_item_sort(rbml_w, 'c'); + } + encode_inlined_item(ecx, rbml_w, InlinedItemRef::TraitItem(def_id, trait_item)); - self.encode_mir(rbml_w, trait_item.id); - } else { - encode_item_sort(rbml_w, 'r'); + this.encode_mir(rbml_w, trait_item.id); } - self.encode_method_argument_names(rbml_w, &sig.decl); - } + hir::MethodTraitItem(ref sig, ref body) => { + // If this is a static method, we've already + // encoded this. + if is_nonstatic_method { + this.encode_bounds_and_type_for_item( + rbml_w, + ecx.local_id(item_def_id.def_id())); + } - hir::TypeTraitItem(..) => {} - } + if body.is_some() { + encode_item_sort(rbml_w, 'p'); + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::TraitItem( + def_id, + trait_item)); + this.encode_mir(rbml_w, trait_item.id); + } else { + encode_item_sort(rbml_w, 'r'); + } + this.encode_method_argument_names(rbml_w, &sig.decl); + } - rbml_w.end_tag(); + hir::TypeTraitItem(..) => {} + } + }); } } hir::ItemExternCrate(_) | hir::ItemUse(_) => { @@ -1255,44 +1230,43 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - let parent_id = ecx.tcx.map.get_parent(nitem.id); - self.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - self.encode_visibility(rbml_w, &nitem.vis); - match nitem.node { - hir::ForeignItemFn(ref fndecl, _) => { - encode_family(rbml_w, FN_FAMILY); - self.encode_bounds_and_type_for_item(rbml_w, nitem.id); - encode_name(rbml_w, nitem.name); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem)); - self.encode_mir(rbml_w, nitem.id); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + let parent_id = ecx.tcx.map.get_parent(nitem.id); + this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + this.encode_visibility(rbml_w, &nitem.vis); + match nitem.node { + hir::ForeignItemFn(ref fndecl, _) => { + encode_family(rbml_w, FN_FAMILY); + this.encode_bounds_and_type_for_item(rbml_w, nitem.id); + encode_name(rbml_w, nitem.name); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem)); + this.encode_mir(rbml_w, nitem.id); + } + encode_attributes(rbml_w, &nitem.attrs); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + this.encode_method_argument_names(rbml_w, &fndecl); } - encode_attributes(rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - self.encode_method_argument_names(rbml_w, &fndecl); - } - hir::ForeignItemStatic(_, mutbl) => { - if mutbl { - encode_family(rbml_w, 'b'); - } else { - encode_family(rbml_w, 'c'); + hir::ForeignItemStatic(_, mutbl) => { + if mutbl { + encode_family(rbml_w, 'b'); + } else { + encode_family(rbml_w, 'c'); + } + this.encode_bounds_and_type_for_item(rbml_w, nitem.id); + encode_attributes(rbml_w, &nitem.attrs); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); + encode_name(rbml_w, nitem.name); } - self.encode_bounds_and_type_for_item(rbml_w, nitem.id); - encode_attributes(rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_name(rbml_w, nitem.name); } - } - rbml_w.end_tag(); + }); } } @@ -1316,7 +1290,7 @@ impl<'a, 'data, 'ecx, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'data, 'ecx, 'tc } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { intravisit::walk_ty(self, ty); - encode_info_for_ty(ty, self.rbml_w_for_visit_item, self.index); + self.index.encode_info_for_ty(ty, self.rbml_w); } } @@ -1327,12 +1301,11 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let ecx = self.ecx(); if let hir::TyImplTrait(_) = ty.node { let def_id = ecx.tcx.map.local_def_id(ty.id); - let _task = self.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - self.encode_bounds_and_type_for_item(rbml_w, ecx, ty.id); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'y'); + this.encode_bounds_and_type_for_item(rbml_w, ty.id); + }); } } @@ -1343,24 +1316,21 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); - let _task = self.record(def_id, rbml_w); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_name(rbml_w, syntax::parse::token::intern("")); - - rbml_w.start_tag(tag_items_closure_ty); - write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); - rbml_w.end_tag(); + self.record(def_id, rbml_w, |this, rbml_w| { + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_name(rbml_w, syntax::parse::token::intern("")); - rbml_w.start_tag(tag_items_closure_kind); - ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); - rbml_w.end_tag(); + rbml_w.start_tag(tag_items_closure_ty); + write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); + rbml_w.end_tag(); - assert!(ecx.mir_map.map.contains_key(&def_id)); - self.encode_mir(rbml_w, expr.id); + rbml_w.start_tag(tag_items_closure_kind); + ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); + rbml_w.end_tag(); - rbml_w.end_tag(); + assert!(ecx.mir_map.map.contains_key(&def_id)); + this.encode_mir(rbml_w, expr.id); + }); } _ => { } } @@ -1375,15 +1345,14 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &'a EncodeContext<'a, 'tcx>, let mut index = IndexBuilder::new(ecx); rbml_w.start_tag(tag_items_data); - { - let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); - index.encode_info_for_mod(rbml_w, - &krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public); - } + index.record(DefId::local(CRATE_DEF_INDEX), rbml_w, |this, rbml_w| { + this.encode_info_for_mod(rbml_w, + &krate.module, + &[], + CRATE_NODE_ID, + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public); + }); krate.visit_all_items(&mut EncodeVisitor { index: &mut index, diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 915bf98519c90..2ccd1fd4254d7 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use common::tag_items_data_item; use encoder::EncodeContext; use index::IndexData; use rbml::writer::Encoder; -use rustc::dep_graph::{DepNode, DepTask}; +use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::ty; use rustc_data_structures::fnv::FnvHashMap; @@ -52,10 +53,15 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { /// /// Returns a dep-graph task that you should keep live as long as /// the data for this item is being emitted. - pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> { + pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder, op: OP) + where OP: FnOnce(&mut ItemContentBuilder<'a, 'tcx>, &mut Encoder) + { let position = rbml_w.mark_stable_position(); self.items.record(id, position); - self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)) + let _task = self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)); + rbml_w.start_tag(tag_items_data_item).unwrap(); + op(self, rbml_w); + rbml_w.end_tag().unwrap(); } pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { From 6aca068abae964f4f072528b95404d1409175e83 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 17 Aug 2016 09:55:27 -0400 Subject: [PATCH 082/768] Make version check in gdb_rust_pretty_printing.py more compatible. Some versions of Python don't support the `major` field on the object returned by `sys.version_info`. --- src/etc/gdb_rust_pretty_printing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 554ab66bc563d..cc5f621cb6be0 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -16,7 +16,7 @@ # We want a version of `range` which doesn't allocate an intermediate list, # specifically it should use a lazy iterator. In Python 2 this was `xrange`, but # if we're running with Python 3 then we need to use `range` instead. -if sys.version_info.major >= 3: +if sys.version_info[0] >= 3: xrange = range #=============================================================================== From 12a159abeaaf54eaf85c0d5fd6b41a7787cb3571 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 17 Aug 2016 16:23:11 +0200 Subject: [PATCH 083/768] Add 'make help' for rustbuild It is still advertised by the configure script. --- src/bootstrap/mk/Makefile.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index c657785d78b6e..cc44d45c2cc75 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -22,6 +22,10 @@ BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ all: $(Q)$(BOOTSTRAP) +# Don’t use $(Q) here, always show how to invoke the bootstrap script directly +help: + $(BOOTSTRAP) --help + clean: $(Q)$(BOOTSTRAP) --clean From d49e1a91912788b874bfb5cfc610bc8e3a845d7f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Aug 2016 21:55:22 -0400 Subject: [PATCH 084/768] move rbml_w into the self struct --- src/librustc_metadata/encoder.rs | 788 ++++++++++++------------- src/librustc_metadata/index_builder.rs | 37 +- 2 files changed, 400 insertions(+), 425 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 87c7b36cf87e6..8b76dd62692fb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -132,22 +132,19 @@ fn encode_item_variances(rbml_w: &mut Encoder, rbml_w.end_tag(); } -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_bounds_and_type_for_item(&mut self, - rbml_w: &mut Encoder, id: NodeId) { let ecx = self.ecx(); - self.encode_bounds_and_type(rbml_w, - &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), + self.encode_bounds_and_type(&ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); } fn encode_bounds_and_type(&mut self, - rbml_w: &mut Encoder, scheme: &ty::TypeScheme<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - self.encode_generics(rbml_w, &scheme.generics, &predicates); - self.encode_type(rbml_w, scheme.ty); + self.encode_generics(&scheme.generics, &predicates); + self.encode_type(scheme.ty); } } @@ -164,47 +161,44 @@ fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.mark_stable_position(); } -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_type(&mut self, - rbml_w: &mut Encoder, typ: Ty<'tcx>) { - rbml_w.start_tag(tag_items_data_item_type); - tyencode::enc_ty(rbml_w.writer, &self.ecx().ty_str_ctxt(), typ); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); + let ecx = self.ecx; + self.rbml_w.start_tag(tag_items_data_item_type); + tyencode::enc_ty(self.rbml_w.writer, &ecx.ty_str_ctxt(), typ); + self.rbml_w.mark_stable_position(); + self.rbml_w.end_tag(); } fn encode_disr_val(&mut self, - rbml_w: &mut Encoder, disr_val: ty::Disr) { // convert to u64 so just the number is printed, without any type info - rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); + self.rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); } - fn encode_parent_item(&mut self, rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); + fn encode_parent_item(&mut self, id: DefId) { + self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); } fn encode_struct_fields(&mut self, - rbml_w: &mut Encoder, variant: ty::VariantDef) { for f in &variant.fields { if variant.kind == ty::VariantKind::Tuple { - rbml_w.start_tag(tag_item_unnamed_field); + self.rbml_w.start_tag(tag_item_unnamed_field); } else { - rbml_w.start_tag(tag_item_field); - encode_name(rbml_w, f.name); + self.rbml_w.start_tag(tag_item_field); + encode_name(self.rbml_w, f.name); } - self.encode_struct_field_family(rbml_w, f.vis); - encode_def_id(rbml_w, f.did); - rbml_w.end_tag(); + self.encode_struct_field_family(f.vis); + encode_def_id(self.rbml_w, f.did); + self.rbml_w.end_tag(); } } } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_enum_variant_info(&mut self, - rbml_w: &mut Encoder, did: DefId, vis: &hir::Visibility) { debug!("encode_enum_variant_info(did={:?})", did); @@ -218,37 +212,37 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let variant_node_id = ecx.local_id(vid); for field in &variant.fields { - self.encode_field(rbml_w, field); + self.encode_field(field); } - self.record(vid, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, vid); - encode_family(rbml_w, match variant.kind { + self.record(vid, |this| { + encode_def_id_and_key(ecx, this.rbml_w, vid); + encode_family(this.rbml_w, match variant.kind { ty::VariantKind::Struct => 'V', ty::VariantKind::Tuple => 'v', ty::VariantKind::Unit => 'w', }); - encode_name(rbml_w, variant.name); - this.encode_parent_item(rbml_w, did); - this.encode_visibility(rbml_w, vis); + encode_name(this.rbml_w, variant.name); + this.encode_parent_item(did); + this.encode_visibility(vis); let attrs = ecx.tcx.get_attrs(vid); - encode_attributes(rbml_w, &attrs); - this.encode_repr_attrs(rbml_w, &attrs); + encode_attributes(this.rbml_w, &attrs); + this.encode_repr_attrs(&attrs); let stab = ecx.tcx.lookup_stability(vid); let depr = ecx.tcx.lookup_deprecation(vid); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); - this.encode_struct_fields(rbml_w, variant); + this.encode_struct_fields(variant); let specified_disr_val = variant.disr_val; if specified_disr_val != disr_val { - this.encode_disr_val(rbml_w, specified_disr_val); + this.encode_disr_val(specified_disr_val); disr_val = specified_disr_val; } - this.encode_bounds_and_type_for_item(rbml_w, variant_node_id); + this.encode_bounds_and_type_for_item(variant_node_id); }); disr_val = disr_val.wrap_incr(); @@ -302,9 +296,8 @@ fn encode_reexports(ecx: &EncodeContext, } } -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_mod(&mut self, - rbml_w: &mut Encoder, md: &hir::Mod, attrs: &[ast::Attribute], id: NodeId, @@ -312,47 +305,47 @@ impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { vis: &hir::Visibility) { let ecx = self.ecx(); - encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); - encode_family(rbml_w, 'm'); - encode_name(rbml_w, name); + encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id)); + encode_family(self.rbml_w, 'm'); + encode_name(self.rbml_w, name); debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. for item_id in &md.item_ids { - rbml_w.wr_tagged_u64(tag_mod_child, + self.rbml_w.wr_tagged_u64(tag_mod_child, def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); let item = ecx.tcx.map.expect_item(item_id.id); each_auxiliary_node_id(item, |auxiliary_node_id| { - rbml_w.wr_tagged_u64(tag_mod_child, + self.rbml_w.wr_tagged_u64(tag_mod_child, def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); true }); } - self.encode_visibility(rbml_w, vis); + self.encode_visibility(vis); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id)); let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); // Encode the reexports of this module, if this module is public. if *vis == hir::Public { debug!("(encoding info for module) encoding reexports for {}", id); - encode_reexports(ecx, rbml_w, id); + encode_reexports(ecx, self.rbml_w, id); } - encode_attributes(rbml_w, attrs); + encode_attributes(self.rbml_w, attrs); } - fn encode_struct_field_family(&mut self, rbml_w: &mut Encoder, + fn encode_struct_field_family(&mut self, visibility: ty::Visibility) { - encode_family(rbml_w, if visibility.is_public() { 'g' } else { 'N' }); + encode_family(self.rbml_w, if visibility.is_public() { 'g' } else { 'N' }); } - fn encode_visibility(&mut self, rbml_w: &mut Encoder, visibility: T) { + fn encode_visibility(&mut self, visibility: T) { let ch = if visibility.is_public() { 'y' } else { 'i' }; - rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); + self.rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); } } @@ -424,33 +417,31 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_field(&mut self, - rbml_w: &mut Encoder, field: ty::FieldDef<'tcx>) { let ecx = self.ecx(); let nm = field.name; let id = ecx.local_id(field.did); - self.record(field.did, rbml_w, |this, rbml_w| { + self.record(field.did, |this| { debug!("encode_field: encoding {} {}", nm, id); - this.encode_struct_field_family(rbml_w, field.vis); - encode_name(rbml_w, nm); - this.encode_bounds_and_type_for_item(rbml_w, id); - encode_def_id_and_key(ecx, rbml_w, field.did); + this.encode_struct_field_family(field.vis); + encode_name(this.rbml_w, nm); + this.encode_bounds_and_type_for_item(id); + encode_def_id_and_key(ecx, this.rbml_w, field.did); let stab = ecx.tcx.lookup_stability(field.did); let depr = ecx.tcx.lookup_deprecation(field.did); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); }); } } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_struct_ctor(&mut self, - rbml_w: &mut Encoder, name: Name, struct_def: &hir::VariantData, struct_id: NodeId) { @@ -458,82 +449,78 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let ctor_id = struct_def.id(); let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - self.record(ctor_def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, ctor_def_id); - encode_family(rbml_w, match *struct_def { + self.record(ctor_def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, ctor_def_id); + encode_family(this.rbml_w, match *struct_def { hir::VariantData::Struct(..) => 'S', hir::VariantData::Tuple(..) => 's', hir::VariantData::Unit(..) => 'u', }); - this.encode_bounds_and_type_for_item(rbml_w, ctor_id); - encode_name(rbml_w, name); - this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); + this.encode_bounds_and_type_for_item(ctor_id); + encode_name(this.rbml_w, name); + this.encode_parent_item(ecx.tcx.map.local_def_id(struct_id)); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); // indicate that this is a tuple struct ctor, because // downstream users will normally want the tuple struct // definition, but without this there is no way for them // to tell that they actually have a ctor rather than a // normal function - rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + this.rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); }); } } -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_generics(&mut self, - rbml_w: &mut Encoder, generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { let ecx = self.ecx(); - rbml_w.start_tag(tag_item_generics); - tyencode::enc_generics(rbml_w.writer, &ecx.ty_str_ctxt(), generics); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); - self.encode_predicates(rbml_w, predicates, tag_item_predicates); + self.rbml_w.start_tag(tag_item_generics); + tyencode::enc_generics(self.rbml_w.writer, &ecx.ty_str_ctxt(), generics); + self.rbml_w.mark_stable_position(); + self.rbml_w.end_tag(); + self.encode_predicates(predicates, tag_item_predicates); } fn encode_predicates(&mut self, - rbml_w: &mut Encoder, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { - rbml_w.start_tag(tag); + self.rbml_w.start_tag(tag); if let Some(def_id) = predicates.parent { - rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); + self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); } for predicate in &predicates.predicates { - rbml_w.wr_tagged_u32(tag_predicate, - self.add_xref(XRef::Predicate(predicate.clone()))); + let xref = self.add_xref(XRef::Predicate(predicate.clone())); + self.rbml_w.wr_tagged_u32(tag_predicate, xref); } - rbml_w.end_tag(); + self.rbml_w.end_tag(); } fn encode_method_ty_fields(&mut self, - rbml_w: &mut Encoder, method_ty: &ty::Method<'tcx>) { let ecx = self.ecx(); - encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); - encode_name(rbml_w, method_ty.name); - self.encode_generics(rbml_w, &method_ty.generics, &method_ty.predicates); - self.encode_visibility(rbml_w, method_ty.vis); - encode_explicit_self(rbml_w, &method_ty.explicit_self); + encode_def_id_and_key(ecx, self.rbml_w, method_ty.def_id); + encode_name(self.rbml_w, method_ty.name); + self.encode_generics(&method_ty.generics, &method_ty.predicates); + self.encode_visibility(method_ty.vis); + encode_explicit_self(self.rbml_w, &method_ty.explicit_self); match method_ty.explicit_self { ty::ExplicitSelfCategory::Static => { - encode_family(rbml_w, STATIC_METHOD_FAMILY); + encode_family(self.rbml_w, STATIC_METHOD_FAMILY); } - _ => encode_family(rbml_w, METHOD_FAMILY) + _ => encode_family(self.rbml_w, METHOD_FAMILY) } } } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_associated_const(&mut self, - rbml_w: &mut Encoder, associated_const: &ty::AssociatedConst, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -542,36 +529,35 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { associated_const.def_id, associated_const.name); - self.record(associated_const.def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - encode_name(rbml_w, associated_const.name); - this.encode_visibility(rbml_w, associated_const.vis); - encode_family(rbml_w, 'C'); + self.record(associated_const.def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id); + encode_name(this.rbml_w, associated_const.name); + this.encode_visibility(associated_const.vis); + encode_family(this.rbml_w, 'C'); - this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'C'); + this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(this.rbml_w, 'C'); - this.encode_bounds_and_type_for_item(rbml_w, ecx.local_id(associated_const.def_id)); + this.encode_bounds_and_type_for_item(ecx.local_id(associated_const.def_id)); let stab = ecx.tcx.lookup_stability(associated_const.def_id); let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_defaultness(rbml_w, ii.defaultness); + encode_attributes(this.rbml_w, &ii.attrs); + encode_defaultness(this.rbml_w, ii.defaultness); encode_inlined_item(ecx, - rbml_w, + this.rbml_w, InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), ii)); - this.encode_mir(rbml_w, ii.id); + this.encode_mir(ii.id); } }); } fn encode_info_for_method(&mut self, - rbml_w: &mut Encoder, m: &ty::Method<'tcx>, is_default_impl: bool, parent_id: NodeId, @@ -580,22 +566,22 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); - self.record(m.def_id, rbml_w, |this, rbml_w| { - this.encode_method_ty_fields(rbml_w, m); - this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'r'); + self.record(m.def_id, |this| { + this.encode_method_ty_fields(m); + this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(this.rbml_w, 'r'); let stab = ecx.tcx.lookup_stability(m.def_id); let depr = ecx.tcx.lookup_deprecation(m.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); let m_node_id = ecx.local_id(m.def_id); - this.encode_bounds_and_type_for_item(rbml_w, m_node_id); + this.encode_bounds_and_type_for_item(m_node_id); if let Some(impl_item) = impl_item_opt { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(rbml_w, &impl_item.attrs); + encode_attributes(this.rbml_w, &impl_item.attrs); let generics = ecx.tcx.lookup_generics(m.def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || is_default_impl || @@ -603,21 +589,20 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { if needs_inline || sig.constness == hir::Constness::Const { encode_inlined_item( ecx, - rbml_w, + this.rbml_w, InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), impl_item)); - this.encode_mir(rbml_w, impl_item.id); + this.encode_mir(impl_item.id); } - encode_constness(rbml_w, sig.constness); - encode_defaultness(rbml_w, impl_item.defaultness); - this.encode_method_argument_names(rbml_w, &sig.decl); + encode_constness(this.rbml_w, sig.constness); + encode_defaultness(this.rbml_w, impl_item.defaultness); + this.encode_method_argument_names(&sig.decl); } } }); } fn encode_info_for_associated_type(&mut self, - rbml_w: &mut Encoder, associated_type: &ty::AssociatedType<'tcx>, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -626,55 +611,52 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { associated_type.def_id, associated_type.name); - self.record(associated_type.def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_name(rbml_w, associated_type.name); - this.encode_visibility(rbml_w, associated_type.vis); - encode_family(rbml_w, 'y'); - this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 't'); + self.record(associated_type.def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id); + encode_name(this.rbml_w, associated_type.name); + this.encode_visibility(associated_type.vis); + encode_family(this.rbml_w, 'y'); + this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(this.rbml_w, 't'); let stab = ecx.tcx.lookup_stability(associated_type.def_id); let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_defaultness(rbml_w, ii.defaultness); + encode_attributes(this.rbml_w, &ii.attrs); + encode_defaultness(this.rbml_w, ii.defaultness); } else { // TODO this looks bogus and unnecessary - this.encode_predicates(rbml_w, - &ecx.tcx.lookup_predicates(associated_type.def_id), + this.encode_predicates(&ecx.tcx.lookup_predicates(associated_type.def_id), tag_item_generics); } if let Some(ty) = associated_type.ty { - this.encode_type(rbml_w, ty); + this.encode_type(ty); } }); } } -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_method_argument_names(&mut self, - rbml_w: &mut Encoder, decl: &hir::FnDecl) { - rbml_w.start_tag(tag_method_argument_names); + self.rbml_w.start_tag(tag_method_argument_names); for arg in &decl.inputs { let tag = tag_method_argument_name; if let PatKind::Binding(_, ref path1, _) = arg.pat.node { let name = path1.node.as_str(); - rbml_w.wr_tagged_bytes(tag, name.as_bytes()); + self.rbml_w.wr_tagged_bytes(tag, name.as_bytes()); } else { - rbml_w.wr_tagged_bytes(tag, &[]); + self.rbml_w.wr_tagged_bytes(tag, &[]); } } - rbml_w.end_tag(); + self.rbml_w.end_tag(); } fn encode_repr_attrs(&mut self, - rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { let ecx = self.ecx(); let mut repr_attrs = Vec::new(); @@ -682,22 +664,22 @@ impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(), attr)); } - rbml_w.start_tag(tag_items_data_item_repr); - repr_attrs.encode(rbml_w); - rbml_w.end_tag(); + self.rbml_w.start_tag(tag_items_data_item_repr); + repr_attrs.encode(self.rbml_w); + self.rbml_w.end_tag(); } - fn encode_mir(&mut self, rbml_w: &mut Encoder, node_id: NodeId) { + fn encode_mir(&mut self, node_id: NodeId) { let ecx = self.ecx(); let def_id = ecx.tcx.map.local_def_id(node_id); if let Some(mir) = ecx.mir_map.map.get(&def_id) { - rbml_w.start_tag(tag_mir as usize); - rbml_w.emit_opaque(|opaque_encoder| { + self.rbml_w.start_tag(tag_mir as usize); + self.rbml_w.emit_opaque(|opaque_encoder| { tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| { Encodable::encode(mir, opaque_encoder) }) }).unwrap(); - rbml_w.end_tag(); + self.rbml_w.end_tag(); } } } @@ -766,9 +748,8 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_item(&mut self, - rbml_w: &mut Encoder, item: &hir::Item) { let ecx = self.ecx(); let tcx = ecx.tcx; @@ -786,59 +767,58 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { match item.node { hir::ItemStatic(_, m, _) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); if m == hir::MutMutable { - encode_family(rbml_w, 'b'); + encode_family(this.rbml_w, 'b'); } else { - encode_family(rbml_w, 'c'); + encode_family(this.rbml_w, 'c'); } - this.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_attributes(rbml_w, &item.attrs); + this.encode_bounds_and_type_for_item(item.id); + encode_name(this.rbml_w, item.name); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); + encode_attributes(this.rbml_w, &item.attrs); }); } hir::ItemConst(_, _) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'C'); - this.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(rbml_w, item.id); - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'C'); + this.encode_bounds_and_type_for_item(item.id); + encode_name(this.rbml_w, item.name); + encode_attributes(this.rbml_w, &item.attrs); + encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(item.id); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); }); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, FN_FAMILY); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, FN_FAMILY); let tps_len = generics.ty_params.len(); - this.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); + this.encode_bounds_and_type_for_item(item.id); + encode_name(this.rbml_w, item.name); + encode_attributes(this.rbml_w, &item.attrs); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); if needs_inline || constness == hir::Constness::Const { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(rbml_w, item.id); + encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(item.id); } - encode_constness(rbml_w, constness); - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - this.encode_method_argument_names(rbml_w, &decl); + encode_constness(this.rbml_w, constness); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); + this.encode_method_argument_names(&decl); }); } hir::ItemMod(ref m) => { - self.record(def_id, rbml_w, |this, rbml_w| { - this.encode_info_for_mod(rbml_w, - m, + self.record(def_id, |this| { + this.encode_info_for_mod(m, &item.attrs, item.id, item.name, @@ -846,118 +826,116 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { }); } hir::ItemForeignMod(ref fm) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'n'); - encode_name(rbml_w, item.name); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'n'); + encode_name(this.rbml_w, item.name); // Encode all the items in this module. for foreign_item in &fm.items { - rbml_w.wr_tagged_u64(tag_mod_child, + this.rbml_w.wr_tagged_u64(tag_mod_child, def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); } - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); }); } hir::ItemTy(..) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - this.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'y'); + this.encode_bounds_and_type_for_item(item.id); + encode_name(this.rbml_w, item.name); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); }); } hir::ItemEnum(ref enum_definition, _) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 't'); - encode_item_variances(rbml_w, ecx, item.id); - this.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - this.encode_repr_attrs(rbml_w, &item.attrs); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 't'); + encode_item_variances(this.rbml_w, ecx, item.id); + this.encode_bounds_and_type_for_item(item.id); + encode_name(this.rbml_w, item.name); + encode_attributes(this.rbml_w, &item.attrs); + this.encode_repr_attrs(&item.attrs); for v in &enum_definition.variants { - encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); + encode_variant_id(this.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); } - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(rbml_w, item.id); + encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(item.id); // Encode inherent implementations for this enumeration. - encode_inherent_implementations(ecx, rbml_w, def_id); + encode_inherent_implementations(ecx, this.rbml_w, def_id); - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); }); - self.encode_enum_variant_info(rbml_w, - def_id, - vis); + self.encode_enum_variant_info(def_id, vis); } hir::ItemStruct(ref struct_def, _) => { /* Index the class*/ let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - self.record(def_id, rbml_w, |this, rbml_w| { + self.record(def_id, |this| { /* Now, make an item for the class itself */ - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, match *struct_def { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, match *struct_def { hir::VariantData::Struct(..) => 'S', hir::VariantData::Tuple(..) => 's', hir::VariantData::Unit(..) => 'u', }); - this.encode_bounds_and_type_for_item(rbml_w, item.id); + this.encode_bounds_and_type_for_item(item.id); - encode_item_variances(rbml_w, ecx, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - this.encode_visibility(rbml_w, vis); - this.encode_repr_attrs(rbml_w, &item.attrs); + encode_item_variances(this.rbml_w, ecx, item.id); + encode_name(this.rbml_w, item.name); + encode_attributes(this.rbml_w, &item.attrs); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); + this.encode_visibility(vis); + this.encode_repr_attrs(&item.attrs); /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - this.encode_struct_fields(rbml_w, variant); + this.encode_struct_fields(variant); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(rbml_w, item.id); + encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); + this.encode_mir(item.id); // Encode inherent implementations for this structure. - encode_inherent_implementations(ecx, rbml_w, def_id); + encode_inherent_implementations(ecx, this.rbml_w, def_id); if !struct_def.is_struct() { let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); - rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, + this.rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, def_to_u64(ctor_did)); } }); for field in &variant.fields { - self.encode_field(rbml_w, field); + self.encode_field(field); } // If this is a tuple-like struct, encode the type of the constructor. if !struct_def.is_struct() { - self.encode_info_for_struct_ctor(rbml_w, item.name, struct_def, item.id); + self.encode_info_for_struct_ctor(item.name, struct_def, item.id); } } hir::ItemDefaultImpl(unsafety, _) => { - self.record(def_id, rbml_w, |_this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'd'); - encode_name(rbml_w, item.name); - encode_unsafety(rbml_w, unsafety); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'd'); + encode_name(this.rbml_w, item.name); + encode_unsafety(this.rbml_w, unsafety); let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + encode_trait_ref(this.rbml_w, ecx, trait_ref, tag_item_trait_ref); }); } hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { @@ -966,14 +944,14 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let impl_items = tcx.impl_items.borrow(); let items = &impl_items[&def_id]; - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'i'); - this.encode_bounds_and_type_for_item(rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_unsafety(rbml_w, unsafety); - encode_polarity(rbml_w, polarity); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'i'); + this.encode_bounds_and_type_for_item(item.id); + encode_name(this.rbml_w, item.name); + encode_attributes(this.rbml_w, &item.attrs); + encode_unsafety(this.rbml_w, unsafety); + encode_polarity(this.rbml_w, polarity); match tcx.custom_coerce_unsized_kinds @@ -981,35 +959,35 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { .get(&ecx.tcx.map.local_def_id(item.id)) { Some(&kind) => { - rbml_w.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(rbml_w); - rbml_w.end_tag(); + this.rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(this.rbml_w); + this.rbml_w.end_tag(); } None => {} } for &item_def_id in items { - rbml_w.start_tag(tag_item_impl_item); + this.rbml_w.start_tag(tag_item_impl_item); match item_def_id { ty::ConstTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'C'); + encode_def_id(this.rbml_w, item_def_id); + encode_item_sort(this.rbml_w, 'C'); } ty::MethodTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'r'); + encode_def_id(this.rbml_w, item_def_id); + encode_item_sort(this.rbml_w, 'r'); } ty::TypeTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 't'); + encode_def_id(this.rbml_w, item_def_id); + encode_item_sort(this.rbml_w, 't'); } } - rbml_w.end_tag(); + this.rbml_w.end_tag(); } let did = ecx.tcx.map.local_def_id(item.id); if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + encode_trait_ref(this.rbml_w, ecx, trait_ref, tag_item_trait_ref); let trait_def = tcx.lookup_trait_def(trait_ref.def_id); let parent = trait_def.ancestors(did) @@ -1020,10 +998,10 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { Some(parent), _ => None, }); - encode_parent_impl(rbml_w, parent); + encode_parent_impl(this.rbml_w, parent); } - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); }); // Iterate down the trait items, emitting them. We rely on the @@ -1040,21 +1018,18 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { ty::ConstTraitItem(ref associated_const) => { - self.encode_info_for_associated_const(rbml_w, - &associated_const, - item.id, - ast_item) + self.encode_info_for_associated_const(&associated_const, + item.id, + ast_item) } ty::MethodTraitItem(ref method_type) => { - self.encode_info_for_method(rbml_w, - &method_type, + self.encode_info_for_method(&method_type, false, item.id, ast_item) } ty::TypeTraitItem(ref associated_type) => { - self.encode_info_for_associated_type(rbml_w, - &associated_type, + self.encode_info_for_associated_type(&associated_type, item.id, ast_item) } @@ -1062,50 +1037,49 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } hir::ItemTrait(_, _, _, ref ms) => { - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'I'); - encode_item_variances(rbml_w, ecx, item.id); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'I'); + encode_item_variances(this.rbml_w, ecx, item.id); let trait_def = tcx.lookup_trait_def(def_id); let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(rbml_w, trait_def.unsafety); - encode_paren_sugar(rbml_w, trait_def.paren_sugar); - encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); - encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - this.encode_generics(rbml_w, &trait_def.generics, &trait_predicates); - this.encode_predicates(rbml_w, - &tcx.lookup_super_predicates(def_id), + encode_unsafety(this.rbml_w, trait_def.unsafety); + encode_paren_sugar(this.rbml_w, trait_def.paren_sugar); + encode_defaulted(this.rbml_w, tcx.trait_has_default_impl(def_id)); + encode_associated_type_names(this.rbml_w, &trait_def.associated_type_names); + this.encode_generics(&trait_def.generics, &trait_predicates); + this.encode_predicates(&tcx.lookup_super_predicates(def_id), tag_item_super_predicates); - encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - this.encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_trait_ref(this.rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); + encode_name(this.rbml_w, item.name); + encode_attributes(this.rbml_w, &item.attrs); + this.encode_visibility(vis); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - rbml_w.start_tag(tag_item_trait_item); + this.rbml_w.start_tag(tag_item_trait_item); match method_def_id { ty::ConstTraitItemId(const_def_id) => { - encode_def_id(rbml_w, const_def_id); - encode_item_sort(rbml_w, 'C'); + encode_def_id(this.rbml_w, const_def_id); + encode_item_sort(this.rbml_w, 'C'); } ty::MethodTraitItemId(method_def_id) => { - encode_def_id(rbml_w, method_def_id); - encode_item_sort(rbml_w, 'r'); + encode_def_id(this.rbml_w, method_def_id); + encode_item_sort(this.rbml_w, 'r'); } ty::TypeTraitItemId(type_def_id) => { - encode_def_id(rbml_w, type_def_id); - encode_item_sort(rbml_w, 't'); + encode_def_id(this.rbml_w, type_def_id); + encode_item_sort(this.rbml_w, 't'); } } - rbml_w.end_tag(); + this.rbml_w.end_tag(); - rbml_w.wr_tagged_u64(tag_mod_child, + this.rbml_w.wr_tagged_u64(tag_mod_child, def_to_u64(method_def_id.def_id())); } // Encode inherent implementations for this trait. - encode_inherent_implementations(ecx, rbml_w, def_id); + encode_inherent_implementations(ecx, this.rbml_w, def_id); }); // Now output the trait item info for each trait item. @@ -1113,27 +1087,26 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { for (i, &item_def_id) in r.iter().enumerate() { assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - self.record(item_def_id.def_id(), rbml_w, |this, rbml_w| { - this.encode_parent_item(rbml_w, def_id); + self.record(item_def_id.def_id(), |this| { + this.encode_parent_item(def_id); let stab = tcx.lookup_stability(item_def_id.def_id()); let depr = tcx.lookup_deprecation(item_def_id.def_id()); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); let trait_item_type = tcx.impl_or_trait_item(item_def_id.def_id()); let is_nonstatic_method; match trait_item_type { ty::ConstTraitItem(associated_const) => { - encode_name(rbml_w, associated_const.name); - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - this.encode_visibility(rbml_w, associated_const.vis); + encode_name(this.rbml_w, associated_const.name); + encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id); + this.encode_visibility(associated_const.vis); - encode_family(rbml_w, 'C'); + encode_family(this.rbml_w, 'C'); this.encode_bounds_and_type_for_item( - rbml_w, ecx.local_id(associated_const.def_id)); is_nonstatic_method = false; @@ -1141,32 +1114,31 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { ty::MethodTraitItem(method_ty) => { let method_def_id = item_def_id.def_id(); - this.encode_method_ty_fields(rbml_w, &method_ty); + this.encode_method_ty_fields(&method_ty); match method_ty.explicit_self { ty::ExplicitSelfCategory::Static => { - encode_family(rbml_w, + encode_family(this.rbml_w, STATIC_METHOD_FAMILY); } _ => { - encode_family(rbml_w, + encode_family(this.rbml_w, METHOD_FAMILY); } } - this.encode_bounds_and_type_for_item(rbml_w, - ecx.local_id(method_def_id)); + this.encode_bounds_and_type_for_item(ecx.local_id(method_def_id)); is_nonstatic_method = method_ty.explicit_self != ty::ExplicitSelfCategory::Static; } ty::TypeTraitItem(associated_type) => { - encode_name(rbml_w, associated_type.name); - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_item_sort(rbml_w, 't'); - encode_family(rbml_w, 'y'); + encode_name(this.rbml_w, associated_type.name); + encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id); + encode_item_sort(this.rbml_w, 't'); + encode_family(this.rbml_w, 'y'); if let Some(ty) = associated_type.ty { - this.encode_type(rbml_w, ty); + this.encode_type(ty); } is_nonstatic_method = false; @@ -1174,40 +1146,39 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } let trait_item = &ms[i]; - encode_attributes(rbml_w, &trait_item.attrs); + encode_attributes(this.rbml_w, &trait_item.attrs); match trait_item.node { hir::ConstTraitItem(_, ref default) => { if default.is_some() { - encode_item_sort(rbml_w, 'C'); + encode_item_sort(this.rbml_w, 'C'); } else { - encode_item_sort(rbml_w, 'c'); + encode_item_sort(this.rbml_w, 'c'); } - encode_inlined_item(ecx, rbml_w, + encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::TraitItem(def_id, trait_item)); - this.encode_mir(rbml_w, trait_item.id); + this.encode_mir(trait_item.id); } hir::MethodTraitItem(ref sig, ref body) => { // If this is a static method, we've already // encoded this. if is_nonstatic_method { this.encode_bounds_and_type_for_item( - rbml_w, ecx.local_id(item_def_id.def_id())); } if body.is_some() { - encode_item_sort(rbml_w, 'p'); + encode_item_sort(this.rbml_w, 'p'); encode_inlined_item(ecx, - rbml_w, + this.rbml_w, InlinedItemRef::TraitItem( def_id, trait_item)); - this.encode_mir(rbml_w, trait_item.id); + this.encode_mir(trait_item.id); } else { - encode_item_sort(rbml_w, 'r'); + encode_item_sort(this.rbml_w, 'r'); } - this.encode_method_argument_names(rbml_w, &sig.decl); + this.encode_method_argument_names(&sig.decl); } hir::TypeTraitItem(..) => {} @@ -1222,7 +1193,6 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } fn encode_info_for_foreign_item(&mut self, - rbml_w: &mut Encoder, nitem: &hir::ForeignItem) { let ecx = self.ecx(); @@ -1230,106 +1200,107 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); let parent_id = ecx.tcx.map.get_parent(nitem.id); - this.encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - this.encode_visibility(rbml_w, &nitem.vis); + this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + this.encode_visibility(&nitem.vis); match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { - encode_family(rbml_w, FN_FAMILY); - this.encode_bounds_and_type_for_item(rbml_w, nitem.id); - encode_name(rbml_w, nitem.name); + encode_family(this.rbml_w, FN_FAMILY); + this.encode_bounds_and_type_for_item(nitem.id); + encode_name(this.rbml_w, nitem.name); if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem)); - this.encode_mir(rbml_w, nitem.id); + encode_inlined_item(ecx, + this.rbml_w, + InlinedItemRef::Foreign(def_id, nitem)); + this.encode_mir(nitem.id); } - encode_attributes(rbml_w, &nitem.attrs); + encode_attributes(this.rbml_w, &nitem.attrs); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - this.encode_method_argument_names(rbml_w, &fndecl); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); + this.encode_method_argument_names(&fndecl); } hir::ForeignItemStatic(_, mutbl) => { if mutbl { - encode_family(rbml_w, 'b'); + encode_family(this.rbml_w, 'b'); } else { - encode_family(rbml_w, 'c'); + encode_family(this.rbml_w, 'c'); } - this.encode_bounds_and_type_for_item(rbml_w, nitem.id); - encode_attributes(rbml_w, &nitem.attrs); + this.encode_bounds_and_type_for_item(nitem.id); + encode_attributes(this.rbml_w, &nitem.attrs); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_deprecation(rbml_w, depr); - encode_name(rbml_w, nitem.name); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); + encode_name(this.rbml_w, nitem.name); } } }); } } -struct EncodeVisitor<'a, 'data:'a, 'ecx: 'a, 'tcx: 'ecx> { - rbml_w: &'a mut Encoder<'data>, - index: &'a mut IndexBuilder<'ecx, 'tcx>, +struct EncodeVisitor<'a, 'ecx: 'a, 'tcx: 'ecx, 'encoder: 'ecx> { + index: &'a mut IndexBuilder<'ecx, 'tcx, 'encoder>, } -impl<'a, 'data, 'ecx, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'data, 'ecx, 'tcx> { +impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, 'encoder> { fn visit_expr(&mut self, ex: &'tcx hir::Expr) { intravisit::walk_expr(self, ex); - self.index.encode_info_for_expr(ex, self.rbml_w); + self.index.encode_info_for_expr(ex); } fn visit_item(&mut self, i: &'tcx hir::Item) { intravisit::walk_item(self, i); - self.index.encode_info_for_item(self.rbml_w, i); + self.index.encode_info_for_item(i); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - self.index.encode_info_for_foreign_item(self.rbml_w, ni); + self.index.encode_info_for_foreign_item(ni); } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { intravisit::walk_ty(self, ty); - self.index.encode_info_for_ty(ty, self.rbml_w); + self.index.encode_info_for_ty(ty); } } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { - fn encode_info_for_ty(&mut self, - ty: &hir::Ty, - rbml_w: &mut Encoder) { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { + fn encode_info_for_ty(&mut self, ty: &hir::Ty) { let ecx = self.ecx(); if let hir::TyImplTrait(_) = ty.node { let def_id = ecx.tcx.map.local_def_id(ty.id); - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - this.encode_bounds_and_type_for_item(rbml_w, ty.id); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_family(this.rbml_w, 'y'); + this.encode_bounds_and_type_for_item(ty.id); }); } } - fn encode_info_for_expr(&mut self, expr: &hir::Expr, rbml_w: &mut Encoder) { + fn encode_info_for_expr(&mut self, expr: &hir::Expr) { let ecx = self.ecx(); match expr.node { hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); - self.record(def_id, rbml_w, |this, rbml_w| { - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_name(rbml_w, syntax::parse::token::intern("")); + self.record(def_id, |this| { + encode_def_id_and_key(ecx, this.rbml_w, def_id); + encode_name(this.rbml_w, syntax::parse::token::intern("")); - rbml_w.start_tag(tag_items_closure_ty); - write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); - rbml_w.end_tag(); + this.rbml_w.start_tag(tag_items_closure_ty); + write_closure_type(ecx, + this.rbml_w, + &ecx.tcx.tables.borrow().closure_tys[&def_id]); + this.rbml_w.end_tag(); - rbml_w.start_tag(tag_items_closure_kind); - ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); - rbml_w.end_tag(); + this.rbml_w.start_tag(tag_items_closure_kind); + ecx.tcx.closure_kind(def_id).encode(this.rbml_w).unwrap(); + this.rbml_w.end_tag(); assert!(ecx.mir_map.map.contains_key(&def_id)); - this.encode_mir(rbml_w, expr.id); + this.encode_mir(expr.id); }); } _ => { } @@ -1337,30 +1308,31 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } -fn encode_info_for_items<'a, 'tcx>(ecx: &'a EncodeContext<'a, 'tcx>, +fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder) - -> IndexBuilder<'a, 'tcx> { + -> (IndexData, FnvHashMap, u32>) { let krate = ecx.tcx.map.krate(); - let mut index = IndexBuilder::new(ecx); rbml_w.start_tag(tag_items_data); - index.record(DefId::local(CRATE_DEF_INDEX), rbml_w, |this, rbml_w| { - this.encode_info_for_mod(rbml_w, - &krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public); - }); - - krate.visit_all_items(&mut EncodeVisitor { - index: &mut index, - rbml_w: &mut *rbml_w, - }); + let fields = { + let mut index = IndexBuilder::new(ecx, rbml_w); + index.record(DefId::local(CRATE_DEF_INDEX), |this| { + this.encode_info_for_mod(&krate.module, + &[], + CRATE_NODE_ID, + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public); + }); + krate.visit_all_items(&mut EncodeVisitor { + index: &mut index, + }); + index.into_fields() + }; rbml_w.end_tag(); - index + + fields } fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { @@ -1880,12 +1852,10 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, // Encode and index the items. rbml_w.start_tag(tag_items); i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - let index = encode_info_for_items(&ecx, rbml_w); + let (items, xrefs) = encode_info_for_items(&ecx, rbml_w); stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; rbml_w.end_tag(); - let (items, xrefs) = index.into_fields(); - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); encode_item_index(rbml_w, items); stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 2ccd1fd4254d7..b591e0a92688b 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -20,29 +20,33 @@ use std::ops::{Deref, DerefMut}; /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. -pub struct IndexBuilder<'a, 'tcx: 'a> { +pub struct IndexBuilder<'a, 'tcx: 'a, 'encoder: 'a> { items: IndexData, - builder: ItemContentBuilder<'a, 'tcx>, + builder: ItemContentBuilder<'a, 'tcx, 'encoder>, } /// Builder that can encode the content of items, but can't start a /// new item itself. Most code is attached to here. -pub struct ItemContentBuilder<'a, 'tcx: 'a> { +pub struct ItemContentBuilder<'a, 'tcx: 'a, 'encoder: 'a> { xrefs: FnvHashMap, u32>, // sequentially-assigned - ecx: &'a EncodeContext<'a, 'tcx>, + pub ecx: &'a EncodeContext<'a, 'tcx>, + pub rbml_w: &'a mut Encoder<'encoder>, } /// "interned" entries referenced by id #[derive(PartialEq, Eq, Hash)] pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } -impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { - pub fn new(ecx: &'a EncodeContext<'a, 'tcx>) -> Self { +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { + pub fn new(ecx: &'a EncodeContext<'a, 'tcx>, + rbml_w: &'a mut Encoder<'encoder>) + -> Self { IndexBuilder { items: IndexData::new(ecx.tcx.map.num_local_def_ids()), builder: ItemContentBuilder { ecx: ecx, xrefs: FnvHashMap(), + rbml_w: rbml_w, }, } } @@ -53,15 +57,15 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { /// /// Returns a dep-graph task that you should keep live as long as /// the data for this item is being emitted. - pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder, op: OP) - where OP: FnOnce(&mut ItemContentBuilder<'a, 'tcx>, &mut Encoder) + pub fn record(&mut self, id: DefId, op: OP) + where OP: FnOnce(&mut ItemContentBuilder<'a, 'tcx, 'encoder>) { - let position = rbml_w.mark_stable_position(); + let position = self.rbml_w.mark_stable_position(); self.items.record(id, position); let _task = self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)); - rbml_w.start_tag(tag_items_data_item).unwrap(); - op(self, rbml_w); - rbml_w.end_tag().unwrap(); + self.rbml_w.start_tag(tag_items_data_item).unwrap(); + op(self); + self.rbml_w.end_tag().unwrap(); } pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { @@ -69,21 +73,21 @@ impl<'a, 'tcx> IndexBuilder<'a, 'tcx> { } } -impl<'a, 'tcx> Deref for IndexBuilder<'a, 'tcx> { - type Target = ItemContentBuilder<'a, 'tcx>; +impl<'a, 'tcx, 'encoder> Deref for IndexBuilder<'a, 'tcx, 'encoder> { + type Target = ItemContentBuilder<'a, 'tcx, 'encoder>; fn deref(&self) -> &Self::Target { &self.builder } } -impl<'a, 'tcx> DerefMut for IndexBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> DerefMut for IndexBuilder<'a, 'tcx, 'encoder> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.builder } } -impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { self.ecx } @@ -93,3 +97,4 @@ impl<'a, 'tcx> ItemContentBuilder<'a, 'tcx> { *self.xrefs.entry(xref).or_insert(old_len) } } + From 6277b1fef617610c32b36dba1b06f937488ca5a9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Aug 2016 14:18:59 -0400 Subject: [PATCH 085/768] separate main items from addl items in metadata --- src/librustc_metadata/encoder.rs | 374 ++++++++++++++++++------------- 1 file changed, 220 insertions(+), 154 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 8b76dd62692fb..8611e744bc468 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -443,18 +443,18 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_struct_ctor(&mut self, name: Name, - struct_def: &hir::VariantData, + ctor_id: ast::NodeId, + variant: ty::VariantDef<'tcx>, struct_id: NodeId) { let ecx = self.ecx(); - let ctor_id = struct_def.id(); let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); self.record(ctor_def_id, |this| { encode_def_id_and_key(ecx, this.rbml_w, ctor_def_id); - encode_family(this.rbml_w, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', + encode_family(this.rbml_w, match variant.kind { + ty::VariantKind::Struct => 'S', + ty::VariantKind::Tuple => 's', + ty::VariantKind::Unit => 'u', }); this.encode_bounds_and_type_for_item(ctor_id); encode_name(this.rbml_w, name); @@ -874,15 +874,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { encode_stability(this.rbml_w, stab); encode_deprecation(this.rbml_w, depr); }); - - self.encode_enum_variant_info(def_id, vis); } hir::ItemStruct(ref struct_def, _) => { /* Index the class*/ - let def = ecx.tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); - self.record(def_id, |this| { + let def = ecx.tcx.lookup_adt_def(def_id); + let variant = def.struct_variant(); + /* Now, make an item for the class itself */ encode_def_id_and_key(ecx, this.rbml_w, def_id); encode_family(this.rbml_w, match *struct_def { @@ -917,15 +915,6 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_to_u64(ctor_did)); } }); - - for field in &variant.fields { - self.encode_field(field); - } - - // If this is a tuple-like struct, encode the type of the constructor. - if !struct_def.is_struct() { - self.encode_info_for_struct_ctor(item.name, struct_def, item.id); - } } hir::ItemDefaultImpl(unsafety, _) => { self.record(def_id, |this| { @@ -938,13 +927,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { encode_trait_ref(this.rbml_w, ecx, trait_ref, tag_item_trait_ref); }); } - hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { - // We need to encode information about the default methods we - // have inherited, so we drive this based on the impl structure. - let impl_items = tcx.impl_items.borrow(); - let items = &impl_items[&def_id]; - + hir::ItemImpl(unsafety, polarity, _, _, _, _) => { self.record(def_id, |this| { + // We need to encode information about the default methods we + // have inherited, so we drive this based on the impl structure. + let impl_items = tcx.impl_items.borrow(); + let items = &impl_items[&def_id]; + encode_def_id_and_key(ecx, this.rbml_w, def_id); encode_family(this.rbml_w, 'i'); this.encode_bounds_and_type_for_item(item.id); @@ -1003,40 +992,8 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { encode_stability(this.rbml_w, stab); encode_deprecation(this.rbml_w, depr); }); - - // Iterate down the trait items, emitting them. We rely on the - // assumption that all of the actually implemented trait items - // appear first in the impl structure, in the same order they do - // in the ast. This is a little sketchy. - let num_implemented_methods = ast_items.len(); - for (i, &trait_item_def_id) in items.iter().enumerate() { - let ast_item = if i < num_implemented_methods { - Some(&ast_items[i]) - } else { - None - }; - - match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { - ty::ConstTraitItem(ref associated_const) => { - self.encode_info_for_associated_const(&associated_const, - item.id, - ast_item) - } - ty::MethodTraitItem(ref method_type) => { - self.encode_info_for_method(&method_type, - false, - item.id, - ast_item) - } - ty::TypeTraitItem(ref associated_type) => { - self.encode_info_for_associated_type(&associated_type, - item.id, - ast_item) - } - } - } } - hir::ItemTrait(_, _, _, ref ms) => { + hir::ItemTrait(_, _, _, _) => { self.record(def_id, |this| { encode_def_id_and_key(ecx, this.rbml_w, def_id); encode_family(this.rbml_w, 'I'); @@ -1081,114 +1038,222 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { // Encode inherent implementations for this trait. encode_inherent_implementations(ecx, this.rbml_w, def_id); }); + } + hir::ItemExternCrate(_) | hir::ItemUse(_) => { + // these are encoded separately + } + } + } - // Now output the trait item info for each trait item. - let r = tcx.trait_item_def_ids(def_id); - for (i, &item_def_id) in r.iter().enumerate() { - assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); + /// In some cases, along with the item itself, we also + /// encode some sub-items. Usually we want some info from the item + /// so it's easier to do that here then to wait until we would encounter + /// normally in the visitor walk. + fn encode_addl_info_for_item(&mut self, + item: &hir::Item) { + let def_id = self.ecx.tcx.map.local_def_id(item.id); + match item.node { + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemMod(..) | + hir::ItemForeignMod(..) | + hir::ItemExternCrate(..) | + hir::ItemUse(..) | + hir::ItemDefaultImpl(..) | + hir::ItemTy(..) => { + // no sub-item recording needed in these cases + } + hir::ItemEnum(..) => { + self.encode_enum_variant_info(def_id, &item.vis); + } + hir::ItemStruct(ref struct_def, _) => { + self.encode_addl_struct_info(def_id, struct_def.id(), item); + } + hir::ItemImpl(_, _, _, _, _, ref ast_items) => { + self.encode_addl_impl_info(def_id, item.id, ast_items); + } + hir::ItemTrait(_, _, _, ref trait_items) => { + self.encode_addl_trait_info(def_id, trait_items); + } + } + } - self.record(item_def_id.def_id(), |this| { - this.encode_parent_item(def_id); + fn encode_addl_struct_info(&mut self, + def_id: DefId, + struct_def_id: ast::NodeId, + item: &hir::Item) { + let ecx = self.ecx; + let def = ecx.tcx.lookup_adt_def(def_id); + let variant = def.struct_variant(); - let stab = tcx.lookup_stability(item_def_id.def_id()); - let depr = tcx.lookup_deprecation(item_def_id.def_id()); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); + for field in &variant.fields { + self.encode_field(field); + } - let trait_item_type = - tcx.impl_or_trait_item(item_def_id.def_id()); - let is_nonstatic_method; - match trait_item_type { - ty::ConstTraitItem(associated_const) => { - encode_name(this.rbml_w, associated_const.name); - encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id); - this.encode_visibility(associated_const.vis); + // If this is a tuple-like struct, encode the type of the constructor. + match variant.kind { + ty::VariantKind::Struct => { + // no value for structs like struct Foo { ... } + } + ty::VariantKind::Tuple | ty::VariantKind::Unit => { + // there is a value for structs like `struct + // Foo()` and `struct Foo` + self.encode_info_for_struct_ctor(item.name, + struct_def_id, + variant, + item.id); + } + } + } - encode_family(this.rbml_w, 'C'); + fn encode_addl_impl_info(&mut self, + def_id: DefId, + impl_id: ast::NodeId, + ast_items: &[hir::ImplItem]) { + let ecx = self.ecx; + let impl_items = ecx.tcx.impl_items.borrow(); + let items = &impl_items[&def_id]; + + // Iterate down the trait items, emitting them. We rely on the + // assumption that all of the actually implemented trait items + // appear first in the impl structure, in the same order they do + // in the ast. This is a little sketchy. + let num_implemented_methods = ast_items.len(); + for (i, &trait_item_def_id) in items.iter().enumerate() { + let ast_item = if i < num_implemented_methods { + Some(&ast_items[i]) + } else { + None + }; + + match self.ecx.tcx.impl_or_trait_item(trait_item_def_id.def_id()) { + ty::ConstTraitItem(ref associated_const) => { + self.encode_info_for_associated_const(&associated_const, + impl_id, + ast_item) + } + ty::MethodTraitItem(ref method_type) => { + self.encode_info_for_method(&method_type, + false, + impl_id, + ast_item) + } + ty::TypeTraitItem(ref associated_type) => { + self.encode_info_for_associated_type(&associated_type, + impl_id, + ast_item) + } + } + } + } - this.encode_bounds_and_type_for_item( - ecx.local_id(associated_const.def_id)); + fn encode_addl_trait_info(&mut self, + def_id: DefId, + trait_items: &[hir::TraitItem]) { + // Now output the trait item info for each trait item. + let ecx = self.ecx; + let tcx = self.ecx.tcx; + let r = tcx.trait_item_def_ids(def_id); + for (&item_def_id, trait_item) in r.iter().zip(trait_items) { + assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - is_nonstatic_method = false; + self.record(item_def_id.def_id(), |this| { + this.encode_parent_item(def_id); + + let stab = tcx.lookup_stability(item_def_id.def_id()); + let depr = tcx.lookup_deprecation(item_def_id.def_id()); + encode_stability(this.rbml_w, stab); + encode_deprecation(this.rbml_w, depr); + + let trait_item_type = + tcx.impl_or_trait_item(item_def_id.def_id()); + let is_nonstatic_method; + match trait_item_type { + ty::ConstTraitItem(associated_const) => { + encode_name(this.rbml_w, associated_const.name); + encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id); + this.encode_visibility(associated_const.vis); + + encode_family(this.rbml_w, 'C'); + + this.encode_bounds_and_type_for_item( + ecx.local_id(associated_const.def_id)); + + is_nonstatic_method = false; + } + ty::MethodTraitItem(method_ty) => { + let method_def_id = item_def_id.def_id(); + + this.encode_method_ty_fields(&method_ty); + + match method_ty.explicit_self { + ty::ExplicitSelfCategory::Static => { + encode_family(this.rbml_w, + STATIC_METHOD_FAMILY); } - ty::MethodTraitItem(method_ty) => { - let method_def_id = item_def_id.def_id(); - - this.encode_method_ty_fields(&method_ty); - - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(this.rbml_w, - STATIC_METHOD_FAMILY); - } - _ => { - encode_family(this.rbml_w, - METHOD_FAMILY); - } - } - this.encode_bounds_and_type_for_item(ecx.local_id(method_def_id)); - - is_nonstatic_method = method_ty.explicit_self != - ty::ExplicitSelfCategory::Static; + _ => { + encode_family(this.rbml_w, + METHOD_FAMILY); } - ty::TypeTraitItem(associated_type) => { - encode_name(this.rbml_w, associated_type.name); - encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id); - encode_item_sort(this.rbml_w, 't'); - encode_family(this.rbml_w, 'y'); + } + this.encode_bounds_and_type_for_item(ecx.local_id(method_def_id)); - if let Some(ty) = associated_type.ty { - this.encode_type(ty); - } + is_nonstatic_method = method_ty.explicit_self != + ty::ExplicitSelfCategory::Static; + } + ty::TypeTraitItem(associated_type) => { + encode_name(this.rbml_w, associated_type.name); + encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id); + encode_item_sort(this.rbml_w, 't'); + encode_family(this.rbml_w, 'y'); + + if let Some(ty) = associated_type.ty { + this.encode_type(ty); + } - is_nonstatic_method = false; - } + is_nonstatic_method = false; + } + } + + encode_attributes(this.rbml_w, &trait_item.attrs); + match trait_item.node { + hir::ConstTraitItem(_, ref default) => { + if default.is_some() { + encode_item_sort(this.rbml_w, 'C'); + } else { + encode_item_sort(this.rbml_w, 'c'); } - let trait_item = &ms[i]; - encode_attributes(this.rbml_w, &trait_item.attrs); - match trait_item.node { - hir::ConstTraitItem(_, ref default) => { - if default.is_some() { - encode_item_sort(this.rbml_w, 'C'); - } else { - encode_item_sort(this.rbml_w, 'c'); - } - - encode_inlined_item(ecx, this.rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - this.encode_mir(trait_item.id); - } - hir::MethodTraitItem(ref sig, ref body) => { - // If this is a static method, we've already - // encoded this. - if is_nonstatic_method { - this.encode_bounds_and_type_for_item( - ecx.local_id(item_def_id.def_id())); - } - - if body.is_some() { - encode_item_sort(this.rbml_w, 'p'); - encode_inlined_item(ecx, - this.rbml_w, - InlinedItemRef::TraitItem( - def_id, - trait_item)); - this.encode_mir(trait_item.id); - } else { - encode_item_sort(this.rbml_w, 'r'); - } - this.encode_method_argument_names(&sig.decl); - } + encode_inlined_item(ecx, this.rbml_w, + InlinedItemRef::TraitItem(def_id, trait_item)); + this.encode_mir(trait_item.id); + } + hir::MethodTraitItem(ref sig, ref body) => { + // If this is a static method, we've already + // encoded this. + if is_nonstatic_method { + this.encode_bounds_and_type_for_item( + ecx.local_id(item_def_id.def_id())); + } - hir::TypeTraitItem(..) => {} + if body.is_some() { + encode_item_sort(this.rbml_w, 'p'); + encode_inlined_item(ecx, + this.rbml_w, + InlinedItemRef::TraitItem( + def_id, + trait_item)); + this.encode_mir(trait_item.id); + } else { + encode_item_sort(this.rbml_w, 'r'); } - }); + this.encode_method_argument_names(&sig.decl); + } + + hir::TypeTraitItem(..) => {} } - } - hir::ItemExternCrate(_) | hir::ItemUse(_) => { - // these are encoded separately - } + }); } } @@ -1251,9 +1316,10 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' intravisit::walk_expr(self, ex); self.index.encode_info_for_expr(ex); } - fn visit_item(&mut self, i: &'tcx hir::Item) { - intravisit::walk_item(self, i); - self.index.encode_info_for_item(i); + fn visit_item(&mut self, item: &'tcx hir::Item) { + intravisit::walk_item(self, item); + self.index.encode_info_for_item(item); + self.index.encode_addl_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); From ee1fc38c2a41c96ab3b8d058b7fa1328e93391ef Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 17 Aug 2016 15:34:43 +0100 Subject: [PATCH 086/768] Add a test to check that AtomicBool has the proper representation --- src/test/run-pass/atomic-access-bool.rs | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/run-pass/atomic-access-bool.rs diff --git a/src/test/run-pass/atomic-access-bool.rs b/src/test/run-pass/atomic-access-bool.rs new file mode 100644 index 0000000000000..286c92ce50ee3 --- /dev/null +++ b/src/test/run-pass/atomic-access-bool.rs @@ -0,0 +1,31 @@ +// 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. + +#![feature(atomic_access)] +use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; +use std::sync::atomic::Ordering::*; + +static mut ATOMIC: AtomicBool = ATOMIC_BOOL_INIT; + +fn main() { + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} From 5166682583a95a8e498c27d12154ddc1d9dda406 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Aug 2016 14:54:46 -0400 Subject: [PATCH 087/768] pull out the record call for encode_info_for_item --- src/librustc_metadata/encoder.rs | 468 +++++++++++++++---------------- 1 file changed, 226 insertions(+), 242 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 8611e744bc468..25b705b0d3a77 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -748,8 +748,9 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_item(&mut self, + def_id: DefId, item: &hir::Item) { let ecx = self.ecx(); let tcx = ecx.tcx; @@ -758,7 +759,6 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { tcx.sess.codemap().span_to_string(item.span)); let vis = &item.vis; - let def_id = ecx.tcx.map.local_def_id(item.id); let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)), @@ -767,284 +767,264 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { match item.node { hir::ItemStatic(_, m, _) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - if m == hir::MutMutable { - encode_family(this.rbml_w, 'b'); - } else { - encode_family(this.rbml_w, 'c'); - } - this.encode_bounds_and_type_for_item(item.id); - encode_name(this.rbml_w, item.name); - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - encode_attributes(this.rbml_w, &item.attrs); - }); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + if m == hir::MutMutable { + encode_family(self.rbml_w, 'b'); + } else { + encode_family(self.rbml_w, 'c'); + } + self.encode_bounds_and_type_for_item(item.id); + encode_name(self.rbml_w, item.name); + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + encode_attributes(self.rbml_w, &item.attrs); } hir::ItemConst(_, _) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'C'); - this.encode_bounds_and_type_for_item(item.id); - encode_name(this.rbml_w, item.name); - encode_attributes(this.rbml_w, &item.attrs); - encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(item.id); - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - }); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'C'); + self.encode_bounds_and_type_for_item(item.id); + encode_name(self.rbml_w, item.name); + encode_attributes(self.rbml_w, &item.attrs); + encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(item.id); + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, FN_FAMILY); - let tps_len = generics.ty_params.len(); - this.encode_bounds_and_type_for_item(item.id); - encode_name(this.rbml_w, item.name); - encode_attributes(this.rbml_w, &item.attrs); - let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { - encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(item.id); - } - encode_constness(this.rbml_w, constness); - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - this.encode_method_argument_names(&decl); - }); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, FN_FAMILY); + let tps_len = generics.ty_params.len(); + self.encode_bounds_and_type_for_item(item.id); + encode_name(self.rbml_w, item.name); + encode_attributes(self.rbml_w, &item.attrs); + let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); + if needs_inline || constness == hir::Constness::Const { + encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(item.id); + } + encode_constness(self.rbml_w, constness); + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + self.encode_method_argument_names(&decl); } hir::ItemMod(ref m) => { - self.record(def_id, |this| { - this.encode_info_for_mod(m, - &item.attrs, - item.id, - item.name, - &item.vis); - }); + self.encode_info_for_mod(m, + &item.attrs, + item.id, + item.name, + &item.vis); } hir::ItemForeignMod(ref fm) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'n'); - encode_name(this.rbml_w, item.name); - - // Encode all the items in this module. - for foreign_item in &fm.items { - this.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); - } - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - }); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'n'); + encode_name(self.rbml_w, item.name); + + // Encode all the items in self module. + for foreign_item in &fm.items { + self.rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); + } + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); } hir::ItemTy(..) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'y'); - this.encode_bounds_and_type_for_item(item.id); - encode_name(this.rbml_w, item.name); - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - }); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'y'); + self.encode_bounds_and_type_for_item(item.id); + encode_name(self.rbml_w, item.name); + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); } hir::ItemEnum(ref enum_definition, _) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 't'); - encode_item_variances(this.rbml_w, ecx, item.id); - this.encode_bounds_and_type_for_item(item.id); - encode_name(this.rbml_w, item.name); - encode_attributes(this.rbml_w, &item.attrs); - this.encode_repr_attrs(&item.attrs); - for v in &enum_definition.variants { - encode_variant_id(this.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); - } - encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(item.id); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 't'); + encode_item_variances(self.rbml_w, ecx, item.id); + self.encode_bounds_and_type_for_item(item.id); + encode_name(self.rbml_w, item.name); + encode_attributes(self.rbml_w, &item.attrs); + self.encode_repr_attrs(&item.attrs); + for v in &enum_definition.variants { + encode_variant_id(self.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); + } + encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(item.id); - // Encode inherent implementations for this enumeration. - encode_inherent_implementations(ecx, this.rbml_w, def_id); + // Encode inherent implementations for self enumeration. + encode_inherent_implementations(ecx, self.rbml_w, def_id); - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - }); + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); } hir::ItemStruct(ref struct_def, _) => { /* Index the class*/ - self.record(def_id, |this| { - let def = ecx.tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); - - /* Now, make an item for the class itself */ - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', - }); - this.encode_bounds_and_type_for_item(item.id); - - encode_item_variances(this.rbml_w, ecx, item.id); - encode_name(this.rbml_w, item.name); - encode_attributes(this.rbml_w, &item.attrs); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - this.encode_visibility(vis); - this.encode_repr_attrs(&item.attrs); - - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ - this.encode_struct_fields(variant); - - encode_inlined_item(ecx, this.rbml_w, InlinedItemRef::Item(def_id, item)); - this.encode_mir(item.id); - - // Encode inherent implementations for this structure. - encode_inherent_implementations(ecx, this.rbml_w, def_id); - - if !struct_def.is_struct() { - let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); - this.rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, - def_to_u64(ctor_did)); - } + let def = ecx.tcx.lookup_adt_def(def_id); + let variant = def.struct_variant(); + + /* Now, make an item for the class itself */ + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, match *struct_def { + hir::VariantData::Struct(..) => 'S', + hir::VariantData::Tuple(..) => 's', + hir::VariantData::Unit(..) => 'u', }); + self.encode_bounds_and_type_for_item(item.id); + + encode_item_variances(self.rbml_w, ecx, item.id); + encode_name(self.rbml_w, item.name); + encode_attributes(self.rbml_w, &item.attrs); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + self.encode_visibility(vis); + self.encode_repr_attrs(&item.attrs); + + /* Encode def_ids for each field and method + for methods, write all the stuff get_trait_method + needs to know*/ + self.encode_struct_fields(variant); + + encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); + self.encode_mir(item.id); + + // Encode inherent implementations for self structure. + encode_inherent_implementations(ecx, self.rbml_w, def_id); + + if !struct_def.is_struct() { + let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); + self.rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, + def_to_u64(ctor_did)); + } } hir::ItemDefaultImpl(unsafety, _) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'd'); - encode_name(this.rbml_w, item.name); - encode_unsafety(this.rbml_w, unsafety); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'd'); + encode_name(self.rbml_w, item.name); + encode_unsafety(self.rbml_w, unsafety); - let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(this.rbml_w, ecx, trait_ref, tag_item_trait_ref); - }); + let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); + encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref); } hir::ItemImpl(unsafety, polarity, _, _, _, _) => { - self.record(def_id, |this| { - // We need to encode information about the default methods we - // have inherited, so we drive this based on the impl structure. - let impl_items = tcx.impl_items.borrow(); - let items = &impl_items[&def_id]; - - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'i'); - this.encode_bounds_and_type_for_item(item.id); - encode_name(this.rbml_w, item.name); - encode_attributes(this.rbml_w, &item.attrs); - encode_unsafety(this.rbml_w, unsafety); - encode_polarity(this.rbml_w, polarity); - - match - tcx.custom_coerce_unsized_kinds - .borrow() - .get(&ecx.tcx.map.local_def_id(item.id)) - { - Some(&kind) => { - this.rbml_w.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(this.rbml_w); - this.rbml_w.end_tag(); - } - None => {} + // We need to encode information about the default methods we + // have inherited, so we drive self based on the impl structure. + let impl_items = tcx.impl_items.borrow(); + let items = &impl_items[&def_id]; + + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'i'); + self.encode_bounds_and_type_for_item(item.id); + encode_name(self.rbml_w, item.name); + encode_attributes(self.rbml_w, &item.attrs); + encode_unsafety(self.rbml_w, unsafety); + encode_polarity(self.rbml_w, polarity); + + match + tcx.custom_coerce_unsized_kinds + .borrow() + .get(&ecx.tcx.map.local_def_id(item.id)) + { + Some(&kind) => { + self.rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(self.rbml_w); + self.rbml_w.end_tag(); } + None => {} + } - for &item_def_id in items { - this.rbml_w.start_tag(tag_item_impl_item); - match item_def_id { - ty::ConstTraitItemId(item_def_id) => { - encode_def_id(this.rbml_w, item_def_id); - encode_item_sort(this.rbml_w, 'C'); - } - ty::MethodTraitItemId(item_def_id) => { - encode_def_id(this.rbml_w, item_def_id); - encode_item_sort(this.rbml_w, 'r'); - } - ty::TypeTraitItemId(item_def_id) => { - encode_def_id(this.rbml_w, item_def_id); - encode_item_sort(this.rbml_w, 't'); - } + for &item_def_id in items { + self.rbml_w.start_tag(tag_item_impl_item); + match item_def_id { + ty::ConstTraitItemId(item_def_id) => { + encode_def_id(self.rbml_w, item_def_id); + encode_item_sort(self.rbml_w, 'C'); + } + ty::MethodTraitItemId(item_def_id) => { + encode_def_id(self.rbml_w, item_def_id); + encode_item_sort(self.rbml_w, 'r'); + } + ty::TypeTraitItemId(item_def_id) => { + encode_def_id(self.rbml_w, item_def_id); + encode_item_sort(self.rbml_w, 't'); } - this.rbml_w.end_tag(); } + self.rbml_w.end_tag(); + } - let did = ecx.tcx.map.local_def_id(item.id); - if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(this.rbml_w, ecx, trait_ref, tag_item_trait_ref); - - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); - let parent = trait_def.ancestors(did) - .skip(1) - .next() - .and_then(|node| match node { - specialization_graph::Node::Impl(parent) => - Some(parent), - _ => None, - }); - encode_parent_impl(this.rbml_w, parent); - } - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - }); + let did = ecx.tcx.map.local_def_id(item.id); + if let Some(trait_ref) = tcx.impl_trait_ref(did) { + encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref); + + let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let parent = trait_def.ancestors(did) + .skip(1) + .next() + .and_then(|node| match node { + specialization_graph::Node::Impl(parent) => + Some(parent), + _ => None, + }); + encode_parent_impl(self.rbml_w, parent); + } + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); } hir::ItemTrait(_, _, _, _) => { - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'I'); - encode_item_variances(this.rbml_w, ecx, item.id); - let trait_def = tcx.lookup_trait_def(def_id); - let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(this.rbml_w, trait_def.unsafety); - encode_paren_sugar(this.rbml_w, trait_def.paren_sugar); - encode_defaulted(this.rbml_w, tcx.trait_has_default_impl(def_id)); - encode_associated_type_names(this.rbml_w, &trait_def.associated_type_names); - this.encode_generics(&trait_def.generics, &trait_predicates); - this.encode_predicates(&tcx.lookup_super_predicates(def_id), - tag_item_super_predicates); - encode_trait_ref(this.rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(this.rbml_w, item.name); - encode_attributes(this.rbml_w, &item.attrs); - this.encode_visibility(vis); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - this.rbml_w.start_tag(tag_item_trait_item); - match method_def_id { - ty::ConstTraitItemId(const_def_id) => { - encode_def_id(this.rbml_w, const_def_id); - encode_item_sort(this.rbml_w, 'C'); - } - ty::MethodTraitItemId(method_def_id) => { - encode_def_id(this.rbml_w, method_def_id); - encode_item_sort(this.rbml_w, 'r'); - } - ty::TypeTraitItemId(type_def_id) => { - encode_def_id(this.rbml_w, type_def_id); - encode_item_sort(this.rbml_w, 't'); - } + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'I'); + encode_item_variances(self.rbml_w, ecx, item.id); + let trait_def = tcx.lookup_trait_def(def_id); + let trait_predicates = tcx.lookup_predicates(def_id); + encode_unsafety(self.rbml_w, trait_def.unsafety); + encode_paren_sugar(self.rbml_w, trait_def.paren_sugar); + encode_defaulted(self.rbml_w, tcx.trait_has_default_impl(def_id)); + encode_associated_type_names(self.rbml_w, &trait_def.associated_type_names); + self.encode_generics(&trait_def.generics, &trait_predicates); + self.encode_predicates(&tcx.lookup_super_predicates(def_id), + tag_item_super_predicates); + encode_trait_ref(self.rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); + encode_name(self.rbml_w, item.name); + encode_attributes(self.rbml_w, &item.attrs); + self.encode_visibility(vis); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { + self.rbml_w.start_tag(tag_item_trait_item); + match method_def_id { + ty::ConstTraitItemId(const_def_id) => { + encode_def_id(self.rbml_w, const_def_id); + encode_item_sort(self.rbml_w, 'C'); + } + ty::MethodTraitItemId(method_def_id) => { + encode_def_id(self.rbml_w, method_def_id); + encode_item_sort(self.rbml_w, 'r'); + } + ty::TypeTraitItemId(type_def_id) => { + encode_def_id(self.rbml_w, type_def_id); + encode_item_sort(self.rbml_w, 't'); } - this.rbml_w.end_tag(); - - this.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(method_def_id.def_id())); } + self.rbml_w.end_tag(); - // Encode inherent implementations for this trait. - encode_inherent_implementations(ecx, this.rbml_w, def_id); - }); + self.rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); + } + + // Encode inherent implementations for self trait. + encode_inherent_implementations(ecx, self.rbml_w, def_id); } hir::ItemExternCrate(_) | hir::ItemUse(_) => { - // these are encoded separately + bug!("cannot encode info for item {:?}", item) } } } +} +impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { /// In some cases, along with the item itself, we also /// encode some sub-items. Usually we want some info from the item /// so it's easier to do that here then to wait until we would encounter @@ -1318,7 +1298,11 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_item(&mut self, item: &'tcx hir::Item) { intravisit::walk_item(self, item); - self.index.encode_info_for_item(item); + let def_id = self.index.ecx.tcx.map.local_def_id(item.id); + match item.node { + hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these + _ => self.index.record(def_id, |index| index.encode_info_for_item(def_id, item)), + } self.index.encode_addl_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { From f35196326d09a9a632ad54efb9716f254dea5a3c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Aug 2016 15:59:53 -0400 Subject: [PATCH 088/768] pull out code for encoding enum variants --- src/librustc_metadata/decoder.rs | 18 ++----- src/librustc_metadata/encoder.rs | 83 +++++++++++++++----------------- 2 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5488f114db32f..d63e0866a9d6b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -240,11 +240,10 @@ fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> { reader::tagged_docs(d, tag_items_data_item_reexport) } -fn variant_disr_val(d: rbml::Doc) -> Option { - reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { - reader::with_doc_data(val_doc, |data| { - str::from_utf8(data).ok().and_then(|s| s.parse().ok()) - }) +fn variant_disr_val(d: rbml::Doc) -> u64 { + let val_doc = reader::get_doc(d, tag_disr_val); + reader::with_doc_data(val_doc, |data| { + str::from_utf8(data).unwrap().parse().unwrap() }) } @@ -402,17 +401,10 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, } } fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { - let mut disr_val = 0; reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { let did = translated_def_id(cdata, p); let item = cdata.lookup_item(did.index); - - if let Some(disr) = variant_disr_val(item) { - disr_val = disr; - } - let disr = disr_val; - disr_val = disr_val.wrapping_add(1); - + let disr = variant_disr_val(item); ty::VariantDefData { did: did, name: item_name(item), diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 25b705b0d3a77..8c1e551d030d0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -28,7 +28,6 @@ use middle::dependency_format::Linkage; use rustc::dep_graph::DepNode; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::util::IntTypeExt; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; @@ -198,55 +197,53 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { - fn encode_enum_variant_info(&mut self, - did: DefId, - vis: &hir::Visibility) { - debug!("encode_enum_variant_info(did={:?})", did); + fn encode_enum_variant_infos(&mut self, + enum_did: DefId, + vis: &hir::Visibility) { + debug!("encode_enum_variant_info(enum_did={:?})", enum_did); let ecx = self.ecx(); - let repr_hints = ecx.tcx.lookup_repr_hints(did); - let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0)); - let mut disr_val = repr_type.initial_discriminant(ecx.tcx); - let def = ecx.tcx.lookup_adt_def(did); - for variant in &def.variants { - let vid = variant.did; - let variant_node_id = ecx.local_id(vid); - + let def = ecx.tcx.lookup_adt_def(enum_did); + for (i, variant) in def.variants.iter().enumerate() { for field in &variant.fields { self.encode_field(field); } + self.record(variant.did, |this| this.encode_enum_variant_info(enum_did, i, vis)); + } + } +} - self.record(vid, |this| { - encode_def_id_and_key(ecx, this.rbml_w, vid); - encode_family(this.rbml_w, match variant.kind { - ty::VariantKind::Struct => 'V', - ty::VariantKind::Tuple => 'v', - ty::VariantKind::Unit => 'w', - }); - encode_name(this.rbml_w, variant.name); - this.encode_parent_item(did); - this.encode_visibility(vis); - - let attrs = ecx.tcx.get_attrs(vid); - encode_attributes(this.rbml_w, &attrs); - this.encode_repr_attrs(&attrs); - - let stab = ecx.tcx.lookup_stability(vid); - let depr = ecx.tcx.lookup_deprecation(vid); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + fn encode_enum_variant_info(&mut self, + enum_did: DefId, // enum def-id + index: usize, // variant index + vis: &hir::Visibility) { + let ecx = self.ecx; + let def = ecx.tcx.lookup_adt_def(enum_did); + let variant = &def.variants[index]; + let vid = variant.did; + let variant_node_id = ecx.local_id(vid); + encode_def_id_and_key(ecx, self.rbml_w, vid); + encode_family(self.rbml_w, match variant.kind { + ty::VariantKind::Struct => 'V', + ty::VariantKind::Tuple => 'v', + ty::VariantKind::Unit => 'w', + }); + encode_name(self.rbml_w, variant.name); + self.encode_parent_item(enum_did); + self.encode_visibility(vis); - this.encode_struct_fields(variant); + let attrs = ecx.tcx.get_attrs(vid); + encode_attributes(self.rbml_w, &attrs); + self.encode_repr_attrs(&attrs); - let specified_disr_val = variant.disr_val; - if specified_disr_val != disr_val { - this.encode_disr_val(specified_disr_val); - disr_val = specified_disr_val; - } - this.encode_bounds_and_type_for_item(variant_node_id); - }); + let stab = ecx.tcx.lookup_stability(vid); + let depr = ecx.tcx.lookup_deprecation(vid); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); - disr_val = disr_val.wrap_incr(); - } + self.encode_struct_fields(variant); + self.encode_disr_val(variant.disr_val); + self.encode_bounds_and_type_for_item(variant_node_id); } } @@ -1045,7 +1042,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { // no sub-item recording needed in these cases } hir::ItemEnum(..) => { - self.encode_enum_variant_info(def_id, &item.vis); + self.encode_enum_variant_infos(def_id, &item.vis); } hir::ItemStruct(ref struct_def, _) => { self.encode_addl_struct_info(def_id, struct_def.id(), item); From c716ad8af5cb78595cc410536f0e03e03a216b2d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Aug 2016 16:18:22 -0400 Subject: [PATCH 089/768] pull out encode_field --- src/librustc_metadata/encoder.rs | 49 ++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 8c1e551d030d0..f17613cddefdb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -203,10 +203,8 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { debug!("encode_enum_variant_info(enum_did={:?})", enum_did); let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(enum_did); + self.encode_fields(enum_did); for (i, variant) in def.variants.iter().enumerate() { - for field in &variant.fields { - self.encode_field(field); - } self.record(variant.did, |this| this.encode_enum_variant_info(enum_did, i, vis)); } } @@ -415,25 +413,42 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { } impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { + fn encode_fields(&mut self, + adt_def_id: DefId) { + let def = self.ecx.tcx.lookup_adt_def(adt_def_id); + for (variant_index, variant) in def.variants.iter().enumerate() { + for (field_index, field) in variant.fields.iter().enumerate() { + self.record(field.did, |this| this.encode_field(adt_def_id, + variant_index, + field_index)); + } + } + } +} + +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_field(&mut self, - field: ty::FieldDef<'tcx>) { + adt_def_id: DefId, + variant_index: usize, + field_index: usize) { let ecx = self.ecx(); + let def = ecx.tcx.lookup_adt_def(adt_def_id); + let variant = &def.variants[variant_index]; + let field = &variant.fields[field_index]; let nm = field.name; let id = ecx.local_id(field.did); + debug!("encode_field: encoding {} {}", nm, id); - self.record(field.did, |this| { - debug!("encode_field: encoding {} {}", nm, id); - this.encode_struct_field_family(field.vis); - encode_name(this.rbml_w, nm); - this.encode_bounds_and_type_for_item(id); - encode_def_id_and_key(ecx, this.rbml_w, field.did); + self.encode_struct_field_family(field.vis); + encode_name(self.rbml_w, nm); + self.encode_bounds_and_type_for_item(id); + encode_def_id_and_key(ecx, self.rbml_w, field.did); - let stab = ecx.tcx.lookup_stability(field.did); - let depr = ecx.tcx.lookup_deprecation(field.did); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - }); + let stab = ecx.tcx.lookup_stability(field.did); + let depr = ecx.tcx.lookup_deprecation(field.did); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); } } @@ -1064,9 +1079,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - for field in &variant.fields { - self.encode_field(field); - } + self.encode_fields(def_id); // If this is a tuple-like struct, encode the type of the constructor. match variant.kind { From 9afcd7724694e2078ffc9b6c6b73b178ebf3e379 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 18:10:13 -0400 Subject: [PATCH 090/768] don't pass extra state fo encode_struct_ctor --- src/librustc_metadata/encoder.rs | 67 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f17613cddefdb..4848eb8fb4ce4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -452,38 +452,37 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { - fn encode_info_for_struct_ctor(&mut self, - name: Name, - ctor_id: ast::NodeId, - variant: ty::VariantDef<'tcx>, - struct_id: NodeId) { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + fn encode_struct_ctor(&mut self, + struct_def_id: DefId, + struct_node_id: ast::NodeId, + ctor_node_id: ast::NodeId) { let ecx = self.ecx(); - let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - - self.record(ctor_def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, ctor_def_id); - encode_family(this.rbml_w, match variant.kind { - ty::VariantKind::Struct => 'S', - ty::VariantKind::Tuple => 's', - ty::VariantKind::Unit => 'u', - }); - this.encode_bounds_and_type_for_item(ctor_id); - encode_name(this.rbml_w, name); - this.encode_parent_item(ecx.tcx.map.local_def_id(struct_id)); + let def = ecx.tcx.lookup_adt_def(struct_def_id); + let variant = def.struct_variant(); + let item = ecx.tcx.map.expect_item(struct_node_id); + let ctor_def_id = ecx.tcx.map.local_def_id(ctor_node_id); + encode_def_id_and_key(ecx, self.rbml_w, ctor_def_id); + encode_family(self.rbml_w, match variant.kind { + ty::VariantKind::Struct => 'S', + ty::VariantKind::Tuple => 's', + ty::VariantKind::Unit => 'u', + }); + self.encode_bounds_and_type_for_item(ctor_node_id); + encode_name(self.rbml_w, item.name); + self.encode_parent_item(struct_def_id); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); + let stab = ecx.tcx.lookup_stability(ctor_def_id); + let depr = ecx.tcx.lookup_deprecation(ctor_def_id); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); - // indicate that this is a tuple struct ctor, because - // downstream users will normally want the tuple struct - // definition, but without this there is no way for them - // to tell that they actually have a ctor rather than a - // normal function - this.rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); - }); + // indicate that this is a tuple struct ctor, because + // downstream users will normally want the tuple struct + // definition, but without this there is no way for them + // to tell that they actually have a ctor rather than a + // normal function + self.rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); } } @@ -1073,7 +1072,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_addl_struct_info(&mut self, def_id: DefId, - struct_def_id: ast::NodeId, + struct_node_id: ast::NodeId, item: &hir::Item) { let ecx = self.ecx; let def = ecx.tcx.lookup_adt_def(def_id); @@ -1089,10 +1088,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { ty::VariantKind::Tuple | ty::VariantKind::Unit => { // there is a value for structs like `struct // Foo()` and `struct Foo` - self.encode_info_for_struct_ctor(item.name, - struct_def_id, - variant, - item.id); + let ctor_def_id = ecx.tcx.map.local_def_id(struct_node_id); + self.record(ctor_def_id, |this| this.encode_struct_ctor(def_id, + item.id, + struct_node_id)); } } } From feeed0b51bb4af89c300ee9c15bd3dfbf86778b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Aug 2016 15:59:27 +0200 Subject: [PATCH 091/768] Fixes issue #11004 --- src/librustc_typeck/check/mod.rs | 4 +++ src/test/compile-fail/issue-11004.rs | 39 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/test/compile-fail/issue-11004.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e573655b8c984..ff0b86aa59540 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3000,6 +3000,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { but no field with that name was found", field.node, actual) }, expr_t); + if let ty::TyRawPtr(..) = expr_t.sty { + err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ + `(*{0}).{1}`", pprust::expr_to_string(base), field.node)); + } if let ty::TyStruct(def, _) = expr_t.sty { Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } diff --git a/src/test/compile-fail/issue-11004.rs b/src/test/compile-fail/issue-11004.rs new file mode 100644 index 0000000000000..308be46271531 --- /dev/null +++ b/src/test/compile-fail/issue-11004.rs @@ -0,0 +1,39 @@ +// 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. + +use std::mem; + +struct A { x: i32, y: f64 } + +#[cfg(not(works))] +unsafe fn access(n:*mut A) -> (i32, f64) { + let x : i32 = n.x; //~ ERROR attempted access of field `x` + //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).x` + let y : f64 = n.y; //~ ERROR attempted access of field `y` + //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).y` + (x, y) +} + +#[cfg(works)] +unsafe fn access(n:*mut A) -> (i32, f64) { + let x : i32 = (*n).x; + let y : f64 = (*n).y; + (x, y) +} + +fn main() { + let a : A = A { x: 3, y: 3.14 }; + let p : &A = &a; + let (x,y) = unsafe { + let n : *mut A = mem::transmute(p); + access(n) + }; + println!("x: {}, y: {}", x, y); +} From d01bfb122e195696e72178e967191999c8745df4 Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 17 Aug 2016 10:21:15 -0700 Subject: [PATCH 092/768] Remove trailing white space --- src/test/compile-fail/E0009.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/E0009.rs b/src/test/compile-fail/E0009.rs index 4ce3b72e449df..767fc0cc5dc07 100644 --- a/src/test/compile-fail/E0009.rs +++ b/src/test/compile-fail/E0009.rs @@ -12,7 +12,7 @@ fn main() { struct X { x: (), } let x = Some((X { x: () }, X { x: () })); match x { - Some((y, ref z)) => {}, + Some((y, ref z)) => {}, //~^ ERROR E0009 //~| NOTE by-move pattern here //~| NOTE both by-ref and by-move used From 2179defa0425b88644de283f672cda6695ded942 Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Wed, 17 Aug 2016 00:03:53 +0200 Subject: [PATCH 093/768] New output for E0407 Issue #35697 as a part of #35233. r? @jonathandturner --- src/librustc_resolve/lib.rs | 14 ++++++++------ src/test/compile-fail/E0407.rs | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 65e14eee4bc2b..0d37d0f9384fc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -237,12 +237,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::MethodNotMemberOfTrait(method, trait_) => { - struct_span_err!(resolver.session, - span, - E0407, - "method `{}` is not a member of trait `{}`", - method, - trait_) + let mut err = struct_span_err!(resolver.session, + span, + E0407, + "method `{}` is not a member of trait `{}`", + method, + trait_); + err.span_label(span, &format!("not a member of `{}`", trait_)); + err } ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { struct_span_err!(resolver.session, diff --git a/src/test/compile-fail/E0407.rs b/src/test/compile-fail/E0407.rs index b861cf1b37817..2a150b7451210 100644 --- a/src/test/compile-fail/E0407.rs +++ b/src/test/compile-fail/E0407.rs @@ -16,7 +16,9 @@ struct Bar; impl Foo for Bar { fn a() {} - fn b() {} //~ ERROR E0407 + fn b() {} + //~^ ERROR E0407 + //~| NOTE not a member of `Foo` } fn main() { From 2d366428cc50d1f20c139ffc854a603de1c1470c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 17 Aug 2016 04:13:43 +0300 Subject: [PATCH 094/768] Properly invalidate the early exit cache Fixes #35737 --- src/librustc_mir/build/scope.rs | 43 +++++++++++---------- src/test/run-pass/mir_early_return_scope.rs | 37 ++++++++++++++++++ 2 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 src/test/run-pass/mir_early_return_scope.rs diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index cae9e8379897c..ca9e108bb415a 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -198,8 +198,11 @@ impl<'tcx> Scope<'tcx> { /// /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a /// larger extent of code. - fn invalidate_cache(&mut self) { - self.cached_exits = FnvHashMap(); + /// + /// `unwind` controls whether caches for the unwind branch are also invalidated. + fn invalidate_cache(&mut self, unwind: bool) { + self.cached_exits.clear(); + if !unwind { return; } for dropdata in &mut self.drops { if let DropKind::Value { ref mut cached_block } = dropdata.kind { *cached_block = None; @@ -455,25 +458,29 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; for scope in self.scopes.iter_mut().rev() { - if scope.extent == extent { + let this_scope = scope.extent == extent; + // We must invalidate all the caches leading up to the scope we’re looking for, because + // the cached blocks will branch into build of scope not containing the new drop. If we + // add stuff to the currently inspected scope, then in some cases the non-unwind caches + // may become invalid, therefore we should invalidate these as well. The unwind caches + // will stay correct, because the already generated unwind blocks cannot be influenced + // by just added drop. + // + // If we’re scheduling cleanup for non-droppable type (i.e. DropKind::Storage), then we + // do not need to invalidate unwind branch, because DropKind::Storage does not end up + // built in the unwind branch currently. + let invalidate_unwind = needs_drop && !this_scope; + scope.invalidate_cache(invalidate_unwind); + if this_scope { if let DropKind::Value { .. } = drop_kind { scope.needs_cleanup = true; } - - // No need to invalidate any caches here. The just-scheduled drop will branch into - // the drop that comes before it in the vector. scope.drops.push(DropData { span: span, location: lvalue.clone(), kind: drop_kind }); return; - } else { - // We must invalidate all the cached_blocks leading up to the scope we’re - // looking for, because all of the blocks in the chain will become incorrect. - if let DropKind::Value { .. } = drop_kind { - scope.invalidate_cache() - } } } span_bug!(span, "extent {:?} not in scope to drop {:?}", extent, lvalue); @@ -490,11 +497,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: &Lvalue<'tcx>, item_ty: Ty<'tcx>) { for scope in self.scopes.iter_mut().rev() { + // We must invalidate all the caches leading up to and including the scope we’re + // looking for, because otherwise some of the blocks in the chain will become + // incorrect and must be rebuilt. + scope.invalidate_cache(true); if scope.extent == extent { assert!(scope.free.is_none(), "scope already has a scheduled free!"); - // We also must invalidate the caches in the scope for which the free is scheduled - // because the drops must branch into the free we schedule here. - scope.invalidate_cache(); scope.needs_cleanup = true; scope.free = Some(FreeData { span: span, @@ -503,11 +511,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { cached_block: None }); return; - } else { - // We must invalidate all the cached_blocks leading up to the scope we’re looking - // for, because otherwise some/most of the blocks in the chain will become - // incorrect. - scope.invalidate_cache(); } } span_bug!(span, "extent {:?} not in scope to free {:?}", extent, value); diff --git a/src/test/run-pass/mir_early_return_scope.rs b/src/test/run-pass/mir_early_return_scope.rs new file mode 100644 index 0000000000000..c27e57358b09b --- /dev/null +++ b/src/test/run-pass/mir_early_return_scope.rs @@ -0,0 +1,37 @@ +// 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. + +static mut DROP: bool = false; + +struct ConnWrap(Conn); +impl ::std::ops::Deref for ConnWrap { + type Target=Conn; + fn deref(&self) -> &Conn { &self.0 } +} + +struct Conn; +impl Drop for Conn { + fn drop(&mut self) { unsafe { DROP = true; } } +} + +fn inner() { + let conn = &*match Some(ConnWrap(Conn)) { + Some(val) => val, + None => return, + }; + return; +} + +fn main() { + inner(); + unsafe { + assert_eq!(DROP, true); + } +} From 8dc8151b495b3237f06821a0b6fd6f0c89b5d438 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 18:27:57 -0400 Subject: [PATCH 095/768] pull out call to `record` for impl items --- src/librustc_metadata/encoder.rs | 202 ++++++++++++++++--------------- 1 file changed, 103 insertions(+), 99 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4848eb8fb4ce4..e662c444413e7 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -530,7 +530,31 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + fn encode_info_for_impl_item(&mut self, + impl_id: NodeId, + impl_item_def_id: DefId, + ast_item: Option<&hir::ImplItem>) { + match self.ecx.tcx.impl_or_trait_item(impl_item_def_id) { + ty::ConstTraitItem(ref associated_const) => { + self.encode_info_for_associated_const(&associated_const, + impl_id, + ast_item) + } + ty::MethodTraitItem(ref method_type) => { + self.encode_info_for_method(&method_type, + false, + impl_id, + ast_item) + } + ty::TypeTraitItem(ref associated_type) => { + self.encode_info_for_associated_type(&associated_type, + impl_id, + ast_item) + } + } + } + fn encode_info_for_associated_const(&mut self, associated_const: &ty::AssociatedConst, parent_id: NodeId, @@ -540,32 +564,30 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { associated_const.def_id, associated_const.name); - self.record(associated_const.def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id); - encode_name(this.rbml_w, associated_const.name); - this.encode_visibility(associated_const.vis); - encode_family(this.rbml_w, 'C'); + encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id); + encode_name(self.rbml_w, associated_const.name); + self.encode_visibility(associated_const.vis); + encode_family(self.rbml_w, 'C'); - this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(this.rbml_w, 'C'); - - this.encode_bounds_and_type_for_item(ecx.local_id(associated_const.def_id)); - - let stab = ecx.tcx.lookup_stability(associated_const.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - - if let Some(ii) = impl_item_opt { - encode_attributes(this.rbml_w, &ii.attrs); - encode_defaultness(this.rbml_w, ii.defaultness); - encode_inlined_item(ecx, - this.rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - ii)); - this.encode_mir(ii.id); - } - }); + self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(self.rbml_w, 'C'); + + self.encode_bounds_and_type_for_item(ecx.local_id(associated_const.def_id)); + + let stab = ecx.tcx.lookup_stability(associated_const.def_id); + let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + + if let Some(ii) = impl_item_opt { + encode_attributes(self.rbml_w, &ii.attrs); + encode_defaultness(self.rbml_w, ii.defaultness); + encode_inlined_item(ecx, + self.rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + ii)); + self.encode_mir(ii.id); + } } fn encode_info_for_method(&mut self, @@ -577,40 +599,38 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); - self.record(m.def_id, |this| { - this.encode_method_ty_fields(m); - this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(this.rbml_w, 'r'); - - let stab = ecx.tcx.lookup_stability(m.def_id); - let depr = ecx.tcx.lookup_deprecation(m.def_id); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - - let m_node_id = ecx.local_id(m.def_id); - this.encode_bounds_and_type_for_item(m_node_id); - - if let Some(impl_item) = impl_item_opt { - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(this.rbml_w, &impl_item.attrs); - let generics = ecx.tcx.lookup_generics(m.def_id); - let types = generics.parent_types as usize + generics.types.len(); - let needs_inline = types > 0 || is_default_impl || - attr::requests_inline(&impl_item.attrs); - if needs_inline || sig.constness == hir::Constness::Const { - encode_inlined_item( - ecx, - this.rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - impl_item)); - this.encode_mir(impl_item.id); - } - encode_constness(this.rbml_w, sig.constness); - encode_defaultness(this.rbml_w, impl_item.defaultness); - this.encode_method_argument_names(&sig.decl); + self.encode_method_ty_fields(m); + self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(self.rbml_w, 'r'); + + let stab = ecx.tcx.lookup_stability(m.def_id); + let depr = ecx.tcx.lookup_deprecation(m.def_id); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + + let m_node_id = ecx.local_id(m.def_id); + self.encode_bounds_and_type_for_item(m_node_id); + + if let Some(impl_item) = impl_item_opt { + if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { + encode_attributes(self.rbml_w, &impl_item.attrs); + let generics = ecx.tcx.lookup_generics(m.def_id); + let types = generics.parent_types as usize + generics.types.len(); + let needs_inline = types > 0 || is_default_impl || + attr::requests_inline(&impl_item.attrs); + if needs_inline || sig.constness == hir::Constness::Const { + encode_inlined_item( + ecx, + self.rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + impl_item)); + self.encode_mir(impl_item.id); } + encode_constness(self.rbml_w, sig.constness); + encode_defaultness(self.rbml_w, impl_item.defaultness); + self.encode_method_argument_names(&sig.decl); } - }); + } } fn encode_info_for_associated_type(&mut self, @@ -622,32 +642,30 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { associated_type.def_id, associated_type.name); - self.record(associated_type.def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id); - encode_name(this.rbml_w, associated_type.name); - this.encode_visibility(associated_type.vis); - encode_family(this.rbml_w, 'y'); - this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(this.rbml_w, 't'); + encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id); + encode_name(self.rbml_w, associated_type.name); + self.encode_visibility(associated_type.vis); + encode_family(self.rbml_w, 'y'); + self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(self.rbml_w, 't'); - let stab = ecx.tcx.lookup_stability(associated_type.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); + let stab = ecx.tcx.lookup_stability(associated_type.def_id); + let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); - if let Some(ii) = impl_item_opt { - encode_attributes(this.rbml_w, &ii.attrs); - encode_defaultness(this.rbml_w, ii.defaultness); - } else { - // TODO this looks bogus and unnecessary - this.encode_predicates(&ecx.tcx.lookup_predicates(associated_type.def_id), - tag_item_generics); - } + if let Some(ii) = impl_item_opt { + encode_attributes(self.rbml_w, &ii.attrs); + encode_defaultness(self.rbml_w, ii.defaultness); + } else { + // TODO this looks bogus and unnecessary + self.encode_predicates(&ecx.tcx.lookup_predicates(associated_type.def_id), + tag_item_generics); + } - if let Some(ty) = associated_type.ty { - this.encode_type(ty); - } - }); + if let Some(ty) = associated_type.ty { + self.encode_type(ty); + } } } @@ -1116,24 +1134,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { None }; - match self.ecx.tcx.impl_or_trait_item(trait_item_def_id.def_id()) { - ty::ConstTraitItem(ref associated_const) => { - self.encode_info_for_associated_const(&associated_const, - impl_id, - ast_item) - } - ty::MethodTraitItem(ref method_type) => { - self.encode_info_for_method(&method_type, - false, - impl_id, - ast_item) - } - ty::TypeTraitItem(ref associated_type) => { - self.encode_info_for_associated_type(&associated_type, - impl_id, - ast_item) - } - } + let trait_item_def_id = trait_item_def_id.def_id(); + self.record(trait_item_def_id, |this| { + this.encode_info_for_impl_item(impl_id, trait_item_def_id, ast_item) + }); } } From 8c4a2245898af11c7e4484370e42ff8d6f9214f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 18:38:42 -0400 Subject: [PATCH 096/768] extract encode_info_for_trait_item into method --- src/librustc_metadata/encoder.rs | 209 ++++++++++++++++--------------- 1 file changed, 109 insertions(+), 100 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e662c444413e7..cc9b2e213b9f4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -21,7 +21,7 @@ use def_key; use tyencode; use index::{self, IndexData}; -use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls}; +use middle::cstore::{InlinedItemRef, LinkMeta, tls}; use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; @@ -531,6 +531,109 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + fn encode_info_for_trait_item(&mut self, + trait_def_id: DefId, + item_def_id: DefId, + trait_item: &hir::TraitItem) { + let ecx = self.ecx; + let tcx = ecx.tcx; + + self.encode_parent_item(trait_def_id); + + let stab = tcx.lookup_stability(item_def_id); + let depr = tcx.lookup_deprecation(item_def_id); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + + let trait_item_type = + tcx.impl_or_trait_item(item_def_id); + let is_nonstatic_method; + match trait_item_type { + ty::ConstTraitItem(associated_const) => { + encode_name(self.rbml_w, associated_const.name); + encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id); + self.encode_visibility(associated_const.vis); + + encode_family(self.rbml_w, 'C'); + + self.encode_bounds_and_type_for_item( + ecx.local_id(associated_const.def_id)); + + is_nonstatic_method = false; + } + ty::MethodTraitItem(method_ty) => { + let method_def_id = item_def_id; + + self.encode_method_ty_fields(&method_ty); + + match method_ty.explicit_self { + ty::ExplicitSelfCategory::Static => { + encode_family(self.rbml_w, + STATIC_METHOD_FAMILY); + } + _ => { + encode_family(self.rbml_w, + METHOD_FAMILY); + } + } + self.encode_bounds_and_type_for_item(ecx.local_id(method_def_id)); + + is_nonstatic_method = method_ty.explicit_self != + ty::ExplicitSelfCategory::Static; + } + ty::TypeTraitItem(associated_type) => { + encode_name(self.rbml_w, associated_type.name); + encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id); + encode_item_sort(self.rbml_w, 't'); + encode_family(self.rbml_w, 'y'); + + if let Some(ty) = associated_type.ty { + self.encode_type(ty); + } + + is_nonstatic_method = false; + } + } + + encode_attributes(self.rbml_w, &trait_item.attrs); + match trait_item.node { + hir::ConstTraitItem(_, ref default) => { + if default.is_some() { + encode_item_sort(self.rbml_w, 'C'); + } else { + encode_item_sort(self.rbml_w, 'c'); + } + + encode_inlined_item(ecx, self.rbml_w, + InlinedItemRef::TraitItem(trait_def_id, trait_item)); + self.encode_mir(trait_item.id); + } + hir::MethodTraitItem(ref sig, ref body) => { + // If this is a static method, we've already + // encoded self. + if is_nonstatic_method { + self.encode_bounds_and_type_for_item( + ecx.local_id(item_def_id)); + } + + if body.is_some() { + encode_item_sort(self.rbml_w, 'p'); + encode_inlined_item(ecx, + self.rbml_w, + InlinedItemRef::TraitItem( + trait_def_id, + trait_item)); + self.encode_mir(trait_item.id); + } else { + encode_item_sort(self.rbml_w, 'r'); + } + self.encode_method_argument_names(&sig.decl); + } + + hir::TypeTraitItem(..) => {} + } + } + fn encode_info_for_impl_item(&mut self, impl_id: NodeId, impl_item_def_id: DefId, @@ -1145,107 +1248,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, trait_items: &[hir::TraitItem]) { // Now output the trait item info for each trait item. - let ecx = self.ecx; let tcx = self.ecx.tcx; let r = tcx.trait_item_def_ids(def_id); - for (&item_def_id, trait_item) in r.iter().zip(trait_items) { - assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - - self.record(item_def_id.def_id(), |this| { - this.encode_parent_item(def_id); - - let stab = tcx.lookup_stability(item_def_id.def_id()); - let depr = tcx.lookup_deprecation(item_def_id.def_id()); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - - let trait_item_type = - tcx.impl_or_trait_item(item_def_id.def_id()); - let is_nonstatic_method; - match trait_item_type { - ty::ConstTraitItem(associated_const) => { - encode_name(this.rbml_w, associated_const.name); - encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id); - this.encode_visibility(associated_const.vis); - - encode_family(this.rbml_w, 'C'); - - this.encode_bounds_and_type_for_item( - ecx.local_id(associated_const.def_id)); - - is_nonstatic_method = false; - } - ty::MethodTraitItem(method_ty) => { - let method_def_id = item_def_id.def_id(); - - this.encode_method_ty_fields(&method_ty); - - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(this.rbml_w, - STATIC_METHOD_FAMILY); - } - _ => { - encode_family(this.rbml_w, - METHOD_FAMILY); - } - } - this.encode_bounds_and_type_for_item(ecx.local_id(method_def_id)); - - is_nonstatic_method = method_ty.explicit_self != - ty::ExplicitSelfCategory::Static; - } - ty::TypeTraitItem(associated_type) => { - encode_name(this.rbml_w, associated_type.name); - encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id); - encode_item_sort(this.rbml_w, 't'); - encode_family(this.rbml_w, 'y'); - - if let Some(ty) = associated_type.ty { - this.encode_type(ty); - } - - is_nonstatic_method = false; - } - } - - encode_attributes(this.rbml_w, &trait_item.attrs); - match trait_item.node { - hir::ConstTraitItem(_, ref default) => { - if default.is_some() { - encode_item_sort(this.rbml_w, 'C'); - } else { - encode_item_sort(this.rbml_w, 'c'); - } - - encode_inlined_item(ecx, this.rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - this.encode_mir(trait_item.id); - } - hir::MethodTraitItem(ref sig, ref body) => { - // If this is a static method, we've already - // encoded this. - if is_nonstatic_method { - this.encode_bounds_and_type_for_item( - ecx.local_id(item_def_id.def_id())); - } - - if body.is_some() { - encode_item_sort(this.rbml_w, 'p'); - encode_inlined_item(ecx, - this.rbml_w, - InlinedItemRef::TraitItem( - def_id, - trait_item)); - this.encode_mir(trait_item.id); - } else { - encode_item_sort(this.rbml_w, 'r'); - } - this.encode_method_argument_names(&sig.decl); - } - - hir::TypeTraitItem(..) => {} - } + for (item_def_id, trait_item) in r.iter().zip(trait_items) { + let item_def_id = item_def_id.def_id(); + assert!(item_def_id.is_local()); + self.record(item_def_id, |this| { + this.encode_info_for_trait_item(def_id, item_def_id, trait_item) }); } } From c0c8ab9cd2728de9789ea76d8520b2be92bc1eb2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 18:50:53 -0400 Subject: [PATCH 097/768] extract two more record calls --- src/librustc_metadata/encoder.rs | 116 ++++++++++++++++--------------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index cc9b2e213b9f4..9855eeeb97070 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1258,54 +1258,54 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { }); } } +} +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_foreign_item(&mut self, + def_id: DefId, nitem: &hir::ForeignItem) { let ecx = self.ecx(); debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); - let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - let parent_id = ecx.tcx.map.get_parent(nitem.id); - this.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - this.encode_visibility(&nitem.vis); - match nitem.node { - hir::ForeignItemFn(ref fndecl, _) => { - encode_family(this.rbml_w, FN_FAMILY); - this.encode_bounds_and_type_for_item(nitem.id); - encode_name(this.rbml_w, nitem.name); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - encode_inlined_item(ecx, - this.rbml_w, - InlinedItemRef::Foreign(def_id, nitem)); - this.encode_mir(nitem.id); - } - encode_attributes(this.rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - this.encode_method_argument_names(&fndecl); + encode_def_id_and_key(ecx, self.rbml_w, def_id); + let parent_id = ecx.tcx.map.get_parent(nitem.id); + self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + self.encode_visibility(&nitem.vis); + match nitem.node { + hir::ForeignItemFn(ref fndecl, _) => { + encode_family(self.rbml_w, FN_FAMILY); + self.encode_bounds_and_type_for_item(nitem.id); + encode_name(self.rbml_w, nitem.name); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + encode_inlined_item(ecx, + self.rbml_w, + InlinedItemRef::Foreign(def_id, nitem)); + self.encode_mir(nitem.id); } - hir::ForeignItemStatic(_, mutbl) => { - if mutbl { - encode_family(this.rbml_w, 'b'); - } else { - encode_family(this.rbml_w, 'c'); - } - this.encode_bounds_and_type_for_item(nitem.id); - encode_attributes(this.rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(this.rbml_w, stab); - encode_deprecation(this.rbml_w, depr); - encode_name(this.rbml_w, nitem.name); + encode_attributes(self.rbml_w, &nitem.attrs); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + self.encode_method_argument_names(&fndecl); + } + hir::ForeignItemStatic(_, mutbl) => { + if mutbl { + encode_family(self.rbml_w, 'b'); + } else { + encode_family(self.rbml_w, 'c'); } + self.encode_bounds_and_type_for_item(nitem.id); + encode_attributes(self.rbml_w, &nitem.attrs); + let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); + let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(self.rbml_w, stab); + encode_deprecation(self.rbml_w, depr); + encode_name(self.rbml_w, nitem.name); } - }); + } } } @@ -1329,7 +1329,8 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - self.index.encode_info_for_foreign_item(ni); + let def_id = self.index.ecx.tcx.map.local_def_id(ni.id); + self.index.record(def_id, |index| index.encode_info_for_foreign_item(def_id, ni)); } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { intravisit::walk_ty(self, ty); @@ -1357,29 +1358,34 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_name(this.rbml_w, syntax::parse::token::intern("")); - - this.rbml_w.start_tag(tag_items_closure_ty); - write_closure_type(ecx, - this.rbml_w, - &ecx.tcx.tables.borrow().closure_tys[&def_id]); - this.rbml_w.end_tag(); - - this.rbml_w.start_tag(tag_items_closure_kind); - ecx.tcx.closure_kind(def_id).encode(this.rbml_w).unwrap(); - this.rbml_w.end_tag(); - - assert!(ecx.mir_map.map.contains_key(&def_id)); - this.encode_mir(expr.id); - }); + self.record(def_id, |this| this.encode_info_for_closure(def_id, expr.id)); } _ => { } } } } +impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + fn encode_info_for_closure(&mut self, def_id: DefId, expr_id: NodeId) { + let ecx = self.ecx; + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_name(self.rbml_w, syntax::parse::token::intern("")); + + self.rbml_w.start_tag(tag_items_closure_ty); + write_closure_type(ecx, + self.rbml_w, + &ecx.tcx.tables.borrow().closure_tys[&def_id]); + self.rbml_w.end_tag(); + + self.rbml_w.start_tag(tag_items_closure_kind); + ecx.tcx.closure_kind(def_id).encode(self.rbml_w).unwrap(); + self.rbml_w.end_tag(); + + assert!(ecx.mir_map.map.contains_key(&def_id)); + self.encode_mir(expr_id); + } +} + fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder) -> (IndexData, FnvHashMap, u32>) { From 00e699faf3ec39715477b8386fba9deab2e2c925 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 20:25:00 -0400 Subject: [PATCH 098/768] change callback for expr/type to a fn pointer The idea is that, this way, we can cleanly isolate ALL state that is being passed, since it goes as an argument to the fn pointer. --- src/librustc_metadata/encoder.rs | 116 ++++++++++++------------- src/librustc_metadata/index_builder.rs | 8 +- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 9855eeeb97070..309347a5e5a7a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -205,16 +205,17 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { let def = ecx.tcx.lookup_adt_def(enum_did); self.encode_fields(enum_did); for (i, variant) in def.variants.iter().enumerate() { - self.record(variant.did, |this| this.encode_enum_variant_info(enum_did, i, vis)); + self.record(variant.did, + ItemContentBuilder::encode_enum_variant_info, + (enum_did, i, vis)); } } } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_enum_variant_info(&mut self, - enum_did: DefId, // enum def-id - index: usize, // variant index - vis: &hir::Visibility) { + (enum_did, index, vis): + (DefId, usize, &hir::Visibility)) { let ecx = self.ecx; let def = ecx.tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; @@ -293,11 +294,8 @@ fn encode_reexports(ecx: &EncodeContext, impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_mod(&mut self, - md: &hir::Mod, - attrs: &[ast::Attribute], - id: NodeId, - name: Name, - vis: &hir::Visibility) { + (md, attrs, id, name, vis): + (&hir::Mod, &[ast::Attribute], NodeId, Name, &hir::Visibility)) { let ecx = self.ecx(); encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id)); @@ -418,9 +416,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { let def = self.ecx.tcx.lookup_adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { - self.record(field.did, |this| this.encode_field(adt_def_id, - variant_index, - field_index)); + self.record(field.did, + ItemContentBuilder::encode_field, + (adt_def_id, variant_index, field_index)); } } } @@ -428,9 +426,8 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_field(&mut self, - adt_def_id: DefId, - variant_index: usize, - field_index: usize) { + (adt_def_id, variant_index, field_index): + (DefId, usize, usize)) { let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(adt_def_id); let variant = &def.variants[variant_index]; @@ -454,9 +451,8 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_struct_ctor(&mut self, - struct_def_id: DefId, - struct_node_id: ast::NodeId, - ctor_node_id: ast::NodeId) { + (struct_def_id, struct_node_id, ctor_node_id): + (DefId, ast::NodeId, ast::NodeId)) { let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(struct_def_id); let variant = def.struct_variant(); @@ -532,9 +528,8 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_trait_item(&mut self, - trait_def_id: DefId, - item_def_id: DefId, - trait_item: &hir::TraitItem) { + (trait_def_id, item_def_id, trait_item): + (DefId, DefId, &hir::TraitItem)) { let ecx = self.ecx; let tcx = ecx.tcx; @@ -635,9 +630,8 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } fn encode_info_for_impl_item(&mut self, - impl_id: NodeId, - impl_item_def_id: DefId, - ast_item: Option<&hir::ImplItem>) { + (impl_id, impl_item_def_id, ast_item): + (NodeId, DefId, Option<&hir::ImplItem>)) { match self.ecx.tcx.impl_or_trait_item(impl_item_def_id) { ty::ConstTraitItem(ref associated_const) => { self.encode_info_for_associated_const(&associated_const, @@ -882,8 +876,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_item(&mut self, - def_id: DefId, - item: &hir::Item) { + (def_id, item): (DefId, &hir::Item)) { let ecx = self.ecx(); let tcx = ecx.tcx; @@ -943,11 +936,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { self.encode_method_argument_names(&decl); } hir::ItemMod(ref m) => { - self.encode_info_for_mod(m, - &item.attrs, - item.id, - item.name, - &item.vis); + self.encode_info_for_mod((m, &item.attrs, item.id, item.name, &item.vis)); } hir::ItemForeignMod(ref fm) => { encode_def_id_and_key(ecx, self.rbml_w, def_id); @@ -1210,9 +1199,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { // there is a value for structs like `struct // Foo()` and `struct Foo` let ctor_def_id = ecx.tcx.map.local_def_id(struct_node_id); - self.record(ctor_def_id, |this| this.encode_struct_ctor(def_id, - item.id, - struct_node_id)); + self.record(ctor_def_id, + ItemContentBuilder::encode_struct_ctor, + (def_id, item.id, struct_node_id)); } } } @@ -1238,9 +1227,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { }; let trait_item_def_id = trait_item_def_id.def_id(); - self.record(trait_item_def_id, |this| { - this.encode_info_for_impl_item(impl_id, trait_item_def_id, ast_item) - }); + self.record(trait_item_def_id, + ItemContentBuilder::encode_info_for_impl_item, + (impl_id, trait_item_def_id, ast_item)); } } @@ -1253,17 +1242,16 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { for (item_def_id, trait_item) in r.iter().zip(trait_items) { let item_def_id = item_def_id.def_id(); assert!(item_def_id.is_local()); - self.record(item_def_id, |this| { - this.encode_info_for_trait_item(def_id, item_def_id, trait_item) - }); + self.record(item_def_id, + ItemContentBuilder::encode_info_for_trait_item, + (def_id, item_def_id, trait_item)); } } } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_foreign_item(&mut self, - def_id: DefId, - nitem: &hir::ForeignItem) { + (def_id, nitem): (DefId, &hir::ForeignItem)) { let ecx = self.ecx(); debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); @@ -1323,14 +1311,18 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' let def_id = self.index.ecx.tcx.map.local_def_id(item.id); match item.node { hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these - _ => self.index.record(def_id, |index| index.encode_info_for_item(def_id, item)), + _ => self.index.record(def_id, + ItemContentBuilder::encode_info_for_item, + (def_id, item)), } self.index.encode_addl_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); let def_id = self.index.ecx.tcx.map.local_def_id(ni.id); - self.index.record(def_id, |index| index.encode_info_for_foreign_item(def_id, ni)); + self.index.record(def_id, + ItemContentBuilder::encode_info_for_foreign_item, + (def_id, ni)); } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { intravisit::walk_ty(self, ty); @@ -1343,11 +1335,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { let ecx = self.ecx(); if let hir::TyImplTrait(_) = ty.node { let def_id = ecx.tcx.map.local_def_id(ty.id); - self.record(def_id, |this| { - encode_def_id_and_key(ecx, this.rbml_w, def_id); - encode_family(this.rbml_w, 'y'); - this.encode_bounds_and_type_for_item(ty.id); - }); + self.record(def_id, + ItemContentBuilder::encode_info_for_anon_ty, + (def_id, ty.id)); } } @@ -1357,8 +1347,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { match expr.node { hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); - - self.record(def_id, |this| this.encode_info_for_closure(def_id, expr.id)); + self.record(def_id, + ItemContentBuilder::encode_info_for_closure, + (def_id, expr.id)); } _ => { } } @@ -1366,7 +1357,14 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { - fn encode_info_for_closure(&mut self, def_id: DefId, expr_id: NodeId) { + fn encode_info_for_anon_ty(&mut self, (def_id, ty_id): (DefId, NodeId)) { + let ecx = self.ecx; + encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_family(self.rbml_w, 'y'); + self.encode_bounds_and_type_for_item(ty_id); + } + + fn encode_info_for_closure(&mut self, (def_id, expr_id): (DefId, NodeId)) { let ecx = self.ecx; encode_def_id_and_key(ecx, self.rbml_w, def_id); encode_name(self.rbml_w, syntax::parse::token::intern("")); @@ -1395,13 +1393,13 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let fields = { let mut index = IndexBuilder::new(ecx, rbml_w); - index.record(DefId::local(CRATE_DEF_INDEX), |this| { - this.encode_info_for_mod(&krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public); - }); + index.record(DefId::local(CRATE_DEF_INDEX), + ItemContentBuilder::encode_info_for_mod, + (&krate.module, + &[], + CRATE_NODE_ID, + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public)); krate.visit_all_items(&mut EncodeVisitor { index: &mut index, }); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index b591e0a92688b..a971c618a2120 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -57,14 +57,16 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { /// /// Returns a dep-graph task that you should keep live as long as /// the data for this item is being emitted. - pub fn record(&mut self, id: DefId, op: OP) - where OP: FnOnce(&mut ItemContentBuilder<'a, 'tcx, 'encoder>) + pub fn record(&mut self, + id: DefId, + op: fn(&mut ItemContentBuilder<'a, 'tcx, 'encoder>, DATA), + data: DATA) { let position = self.rbml_w.mark_stable_position(); self.items.record(id, position); let _task = self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)); self.rbml_w.start_tag(tag_items_data_item).unwrap(); - op(self); + op(self, data); self.rbml_w.end_tag().unwrap(); } From f3990feb2e411d0826dfb83aa7078468da5d1907 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 21:16:16 -0400 Subject: [PATCH 099/768] create a trait to ensure that data is tracked Also write a comment explaining the system. --- src/librustc_metadata/encoder.rs | 33 ++++---- src/librustc_metadata/index_builder.rs | 106 +++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 22 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 309347a5e5a7a..494699af7ba1a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -53,7 +53,7 @@ use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; -use super::index_builder::{IndexBuilder, ItemContentBuilder, XRef}; +use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, @@ -198,8 +198,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_enum_variant_infos(&mut self, - enum_did: DefId, - vis: &hir::Visibility) { + enum_did: DefId) { debug!("encode_enum_variant_info(enum_did={:?})", enum_did); let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(enum_did); @@ -207,15 +206,15 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, ItemContentBuilder::encode_enum_variant_info, - (enum_did, i, vis)); + (enum_did, i)); } } } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_enum_variant_info(&mut self, - (enum_did, index, vis): - (DefId, usize, &hir::Visibility)) { + (enum_did, index): + (DefId, usize)) { let ecx = self.ecx; let def = ecx.tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; @@ -229,7 +228,10 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { }); encode_name(self.rbml_w, variant.name); self.encode_parent_item(enum_did); - self.encode_visibility(vis); + + let enum_id = ecx.tcx.map.as_local_node_id(enum_did).unwrap(); + let enum_vis = &ecx.tcx.map.expect_item(enum_id).vis; + self.encode_visibility(enum_vis); let attrs = ecx.tcx.get_attrs(vid); encode_attributes(self.rbml_w, &attrs); @@ -294,8 +296,8 @@ fn encode_reexports(ecx: &EncodeContext, impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_mod(&mut self, - (md, attrs, id, name, vis): - (&hir::Mod, &[ast::Attribute], NodeId, Name, &hir::Visibility)) { + FromId(id, (md, attrs, name, vis)): + FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) { let ecx = self.ecx(); encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id)); @@ -936,7 +938,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { self.encode_method_argument_names(&decl); } hir::ItemMod(ref m) => { - self.encode_info_for_mod((m, &item.attrs, item.id, item.name, &item.vis)); + self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis))); } hir::ItemForeignMod(ref fm) => { encode_def_id_and_key(ecx, self.rbml_w, def_id); @@ -1166,7 +1168,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { // no sub-item recording needed in these cases } hir::ItemEnum(..) => { - self.encode_enum_variant_infos(def_id, &item.vis); + self.encode_enum_variant_infos(def_id); } hir::ItemStruct(ref struct_def, _) => { self.encode_addl_struct_info(def_id, struct_def.id(), item); @@ -1395,11 +1397,10 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let mut index = IndexBuilder::new(ecx, rbml_w); index.record(DefId::local(CRATE_DEF_INDEX), ItemContentBuilder::encode_info_for_mod, - (&krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public)); + FromId(CRATE_NODE_ID, (&krate.module, + &[], + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public))); krate.visit_all_items(&mut EncodeVisitor { index: &mut index, }); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index a971c618a2120..c7ee3efaa81d3 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -13,9 +13,11 @@ use encoder::EncodeContext; use index::IndexData; use rbml::writer::Encoder; use rustc::dep_graph::DepNode; +use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::ty; +use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fnv::FnvHashMap; +use syntax::ast; use std::ops::{Deref, DerefMut}; /// Builder that can encode new items, adding them into the index. @@ -51,21 +53,34 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } - /// Records that `id` is being emitted at the current offset. - /// This data is later used to construct the item index in the - /// metadata so we can quickly find the data for a given item. + /// Emit the data for a def-id to the metadata. The function to + /// emit the data is `op`, and it will be given `data` as + /// arguments. This `record` function will start/end an RBML tag + /// and record the current offset for use in the index, calling + /// `op` to generate the data in the RBML tag. /// - /// Returns a dep-graph task that you should keep live as long as - /// the data for this item is being emitted. + /// In addition, it will setup a dep-graph task to track what data + /// `op` accesses to generate the metadata, which is later used by + /// incremental compilation to compute a hash for the metadata and + /// track changes. + /// + /// The reason that `op` is a function pointer, and not a closure, + /// is that we want to be able to completely track all data it has + /// access to, so that we can be sure that `DATA: DepGraphRead` + /// holds, and that it is therefore not gaining "secret" access to + /// bits of HIR or other state that would not be trackd by the + /// content system. pub fn record(&mut self, id: DefId, op: fn(&mut ItemContentBuilder<'a, 'tcx, 'encoder>, DATA), data: DATA) + where DATA: DepGraphRead { let position = self.rbml_w.mark_stable_position(); self.items.record(id, position); let _task = self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)); self.rbml_w.start_tag(tag_items_data_item).unwrap(); + data.read(self.ecx.tcx); op(self, data); self.rbml_w.end_tag().unwrap(); } @@ -100,3 +115,82 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } +/// Trait that registers reads for types that are tracked in the +/// dep-graph. Mostly it is implemented for indices like DefId etc +/// which do not need to register a read. +pub trait DepGraphRead { + fn read(&self, tcx: TyCtxt); +} + +impl DepGraphRead for usize { + fn read(&self, _tcx: TyCtxt) { } +} + +impl DepGraphRead for DefId { + fn read(&self, _tcx: TyCtxt) { } +} + +impl DepGraphRead for ast::NodeId { + fn read(&self, _tcx: TyCtxt) { } +} + +impl DepGraphRead for Option + where T: DepGraphRead +{ + fn read(&self, tcx: TyCtxt) { + match *self { + Some(ref v) => v.read(tcx), + None => (), + } + } +} + +impl DepGraphRead for [T] + where T: DepGraphRead +{ + fn read(&self, tcx: TyCtxt) { + for i in self { + i.read(tcx); + } + } +} + +macro_rules! read_tuple { + ($($name:ident),*) => { + impl<$($name),*> DepGraphRead for ($($name),*) + where $($name: DepGraphRead),* + { + #[allow(non_snake_case)] + fn read(&self, tcx: TyCtxt) { + let &($(ref $name),*) = self; + $($name.read(tcx);)* + } + } + } +} +read_tuple!(A,B); +read_tuple!(A,B,C); + +macro_rules! read_hir { + ($t:ty) => { + impl<'tcx> DepGraphRead for &'tcx $t { + fn read(&self, tcx: TyCtxt) { + tcx.map.read(self.id); + } + } + } +} +read_hir!(hir::Item); +read_hir!(hir::ImplItem); +read_hir!(hir::TraitItem); +read_hir!(hir::ForeignItem); + +/// You can use `FromId(X, ...)` to indicate that `...` came from node +/// `X`; so we will add a read from the suitable `Hir` node. +pub struct FromId(pub ast::NodeId, pub T); + +impl DepGraphRead for FromId { + fn read(&self, tcx: TyCtxt) { + tcx.map.read(self.0); + } +} From 1a91e67614b7f4a93bb128ca4f25889b25e22b99 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Aug 2016 10:19:58 -0400 Subject: [PATCH 100/768] pacify the mercilous tidy --- src/librustc_metadata/encoder.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 494699af7ba1a..11a1aab7b5b95 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -947,8 +947,9 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { // Encode all the items in self module. for foreign_item in &fm.items { - self.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); + self.rbml_w.wr_tagged_u64( + tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); } self.encode_visibility(vis); encode_stability(self.rbml_w, stab); From 9daea5b6393af6706dd50a48d4bf8e6eeaff9860 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Aug 2016 11:04:21 -0400 Subject: [PATCH 101/768] Add a comment, remove Deref/DerefMut The comment explains the `index-builder` pattern. We no longer need the `Deref/DerefMut` relationship, and it seems nicer without it. --- src/librustc_metadata/encoder.rs | 14 ++-- src/librustc_metadata/index_builder.rs | 98 +++++++++++++++++++------- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 11a1aab7b5b95..7f7b87fb880b4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -415,7 +415,7 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_fields(&mut self, adt_def_id: DefId) { - let def = self.ecx.tcx.lookup_adt_def(adt_def_id); + let def = self.ecx().tcx.lookup_adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, @@ -1155,7 +1155,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { /// normally in the visitor walk. fn encode_addl_info_for_item(&mut self, item: &hir::Item) { - let def_id = self.ecx.tcx.map.local_def_id(item.id); + let def_id = self.ecx().tcx.map.local_def_id(item.id); match item.node { hir::ItemStatic(..) | hir::ItemConst(..) | @@ -1187,7 +1187,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, struct_node_id: ast::NodeId, item: &hir::Item) { - let ecx = self.ecx; + let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); @@ -1213,7 +1213,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, impl_id: ast::NodeId, ast_items: &[hir::ImplItem]) { - let ecx = self.ecx; + let ecx = self.ecx(); let impl_items = ecx.tcx.impl_items.borrow(); let items = &impl_items[&def_id]; @@ -1240,7 +1240,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, trait_items: &[hir::TraitItem]) { // Now output the trait item info for each trait item. - let tcx = self.ecx.tcx; + let tcx = self.ecx().tcx; let r = tcx.trait_item_def_ids(def_id); for (item_def_id, trait_item) in r.iter().zip(trait_items) { let item_def_id = item_def_id.def_id(); @@ -1311,7 +1311,7 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_item(&mut self, item: &'tcx hir::Item) { intravisit::walk_item(self, item); - let def_id = self.index.ecx.tcx.map.local_def_id(item.id); + let def_id = self.index.ecx().tcx.map.local_def_id(item.id); match item.node { hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these _ => self.index.record(def_id, @@ -1322,7 +1322,7 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - let def_id = self.index.ecx.tcx.map.local_def_id(ni.id); + let def_id = self.index.ecx().tcx.map.local_def_id(ni.id); self.index.record(def_id, ItemContentBuilder::encode_info_for_foreign_item, (def_id, ni)); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index c7ee3efaa81d3..37f29696808ef 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -8,6 +8,60 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Builder types for generating the "item data" section of the +//! metadata. This section winds up looking like this: +//! +//! ``` +//! // big list of item-like things... +//! // ...for most def-ids, there is an entry. +//! +//! +//! ``` +//! +//! As we generate this listing, we collect the offset of each +//! `data_item` entry and store it in an index. Then, when we load the +//! metadata, we can skip right to the metadata for a particular item. +//! +//! In addition to the offset, we need to track the data that was used +//! to generate the contents of each `data_item`. This is so that we +//! can figure out which HIR nodes contributors to that data for +//! incremental compilation purposes. +//! +//! The `IndexBuilder` facilitates with both of these. It is created +//! with an RBML encoder isntance (`rbml_w`) along with an +//! `EncodingContext` (`ecx`), which it encapsulates. It has one main +//! method, `record()`. You invoke `record` like so to create a new +//! `data_item` element in the list: +//! +//! ``` +//! index.record(some_def_id, callback_fn, data) +//! ``` +//! +//! What record will do is to (a) record the current offset, (b) emit +//! the `common::data_item` tag, and then call `callback_fn` with the +//! given data as well as an `ItemContentBuilder`. Once `callback_fn` +//! returns, the `common::data_item` tag will be closed. +//! +//! The `ItemContentBuilder` is another type that just offers access +//! to the `ecx` and `rbml_w` that were given in, as well as +//! maintaining a list of `xref` instances, which are used to extract +//! common data so it is not re-serialized. +//! +//! `ItemContentBuilder` is a distinct type which does not offer the +//! `record` method, so that we can ensure that `common::data_item` elements +//! are never nested. +//! +//! In addition, while the `callback_fn` is executing, we will push a +//! task `MetaData(some_def_id)`, which can then observe the +//! reads/writes that occur in the task. For this reason, the `data` +//! argument that is given to the `callback_fn` must implement the +//! trait `DepGraphRead`, which indicates how to register reads on the +//! data in this new task (note that many types of data, such as +//! `DefId`, do not currently require any reads to be registered, +//! since they are not derived from a HIR node). This is also why we +//! give a callback fn, rather than taking a closure: it allows us to +//! easily control precisely what data is given to that fn. + use common::tag_items_data_item; use encoder::EncodeContext; use index::IndexData; @@ -18,7 +72,6 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fnv::FnvHashMap; use syntax::ast; -use std::ops::{Deref, DerefMut}; /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. @@ -53,6 +106,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } + pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { + self.builder.ecx() + } + /// Emit the data for a def-id to the metadata. The function to /// emit the data is `op`, and it will be given `data` as /// arguments. This `record` function will start/end an RBML tag @@ -76,13 +133,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { data: DATA) where DATA: DepGraphRead { - let position = self.rbml_w.mark_stable_position(); + let position = self.builder.rbml_w.mark_stable_position(); self.items.record(id, position); - let _task = self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id)); - self.rbml_w.start_tag(tag_items_data_item).unwrap(); - data.read(self.ecx.tcx); - op(self, data); - self.rbml_w.end_tag().unwrap(); + let _task = self.ecx().tcx.dep_graph.in_task(DepNode::MetaData(id)); + self.builder.rbml_w.start_tag(tag_items_data_item).unwrap(); + data.read(self.ecx().tcx); + op(&mut self.builder, data); + self.builder.rbml_w.end_tag().unwrap(); } pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { @@ -90,20 +147,6 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> Deref for IndexBuilder<'a, 'tcx, 'encoder> { - type Target = ItemContentBuilder<'a, 'tcx, 'encoder>; - - fn deref(&self) -> &Self::Target { - &self.builder - } -} - -impl<'a, 'tcx, 'encoder> DerefMut for IndexBuilder<'a, 'tcx, 'encoder> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.builder - } -} - impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { self.ecx @@ -115,9 +158,10 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -/// Trait that registers reads for types that are tracked in the -/// dep-graph. Mostly it is implemented for indices like DefId etc -/// which do not need to register a read. +/// Trait used for data that can be passed from outside a dep-graph +/// task. The data must either be of some safe type, such as a +/// `DefId` index, or implement the `read` method so that it can add +/// a read of whatever dep-graph nodes are appropriate. pub trait DepGraphRead { fn read(&self, tcx: TyCtxt); } @@ -185,8 +229,10 @@ read_hir!(hir::ImplItem); read_hir!(hir::TraitItem); read_hir!(hir::ForeignItem); -/// You can use `FromId(X, ...)` to indicate that `...` came from node -/// `X`; so we will add a read from the suitable `Hir` node. +/// Newtype that can be used to package up misc data extracted from a +/// HIR node that doesn't carry its own id. This will allow an +/// arbitrary `T` to be passed in, but register a read on the given +/// node-id. pub struct FromId(pub ast::NodeId, pub T); impl DepGraphRead for FromId { From 6b33f47514f47267d9e07bebbf4c97b2404fa58c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 16 Aug 2016 11:42:30 -0400 Subject: [PATCH 102/768] remove `usize: DepGraphRead` and add `Untracked` The idea is that a `usize` is sort of ambiguous: in this case, it represents indices that do not need tracking, but it could as easily be some data read out from a tracked location, and hence represent tracked data. Therefore, we add an `Untracked` type that lets user assert that value is not tracked. Also correct various typos. --- src/librustc_metadata/encoder.rs | 25 ++++++++++++++++++------- src/librustc_metadata/index_builder.rs | 23 +++++++++++++++++------ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7f7b87fb880b4..791d090273ffc 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -53,7 +53,7 @@ use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; -use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, XRef}; +use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, @@ -206,15 +206,20 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, ItemContentBuilder::encode_enum_variant_info, - (enum_did, i)); + (enum_did, Untracked(i))); } } } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + /// Encode data for the given variant of the given ADT. The + /// index of the variant is untracked: this is ok because we + /// will have to lookup the adt-def by its id, and that gives us + /// the right to access any information in the adt-def (including, + /// e.g., the length of the various vectors). fn encode_enum_variant_info(&mut self, - (enum_did, index): - (DefId, usize)) { + (enum_did, Untracked(index)): + (DefId, Untracked)) { let ecx = self.ecx; let def = ecx.tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; @@ -420,16 +425,22 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, ItemContentBuilder::encode_field, - (adt_def_id, variant_index, field_index)); + (adt_def_id, Untracked((variant_index, field_index)))); } } } } impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { + /// Encode data for the given field of the given variant of the + /// given ADT. The indices of the variant/field are untracked: + /// this is ok because we will have to lookup the adt-def by its + /// id, and that gives us the right to access any information in + /// the adt-def (including, e.g., the length of the various + /// vectors). fn encode_field(&mut self, - (adt_def_id, variant_index, field_index): - (DefId, usize, usize)) { + (adt_def_id, Untracked((variant_index, field_index))): + (DefId, Untracked<(usize, usize)>)) { let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(adt_def_id); let variant = &def.variants[variant_index]; diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 37f29696808ef..1d3d09d6bc2d7 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -24,10 +24,10 @@ //! //! In addition to the offset, we need to track the data that was used //! to generate the contents of each `data_item`. This is so that we -//! can figure out which HIR nodes contributors to that data for +//! can figure out which HIR nodes contributed to that data for //! incremental compilation purposes. //! -//! The `IndexBuilder` facilitates with both of these. It is created +//! The `IndexBuilder` facilitates both of these. It is created //! with an RBML encoder isntance (`rbml_w`) along with an //! `EncodingContext` (`ecx`), which it encapsulates. It has one main //! method, `record()`. You invoke `record` like so to create a new @@ -166,10 +166,6 @@ pub trait DepGraphRead { fn read(&self, tcx: TyCtxt); } -impl DepGraphRead for usize { - fn read(&self, _tcx: TyCtxt) { } -} - impl DepGraphRead for DefId { fn read(&self, _tcx: TyCtxt) { } } @@ -229,6 +225,21 @@ read_hir!(hir::ImplItem); read_hir!(hir::TraitItem); read_hir!(hir::ForeignItem); +/// Leaks access to a value of type T without any tracking. This is +/// suitable for ambiguous types like `usize`, which *could* represent +/// tracked data (e.g., if you read it out of a HIR node) or might not +/// (e.g., if it's an index). Adding in an `Untracked` is an +/// assertion, essentially, that the data does not need to be tracked +/// (or that read edges will be added by some other way). +/// +/// A good idea is to add to each use of `Untracked` an explanation of +/// why this value is ok. +pub struct Untracked(pub T); + +impl DepGraphRead for Untracked { + fn read(&self, _tcx: TyCtxt) { } +} + /// Newtype that can be used to package up misc data extracted from a /// HIR node that doesn't carry its own id. This will allow an /// arbitrary `T` to be passed in, but register a read on the given From 37d974f35327516e337f83be4f38579217660313 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Aug 2016 15:14:08 -0400 Subject: [PATCH 103/768] remove seemingly unnecessary call to encode_predicates --- src/librustc_metadata/encoder.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 791d090273ffc..420dfbc58bf19 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -767,10 +767,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { if let Some(ii) = impl_item_opt { encode_attributes(self.rbml_w, &ii.attrs); encode_defaultness(self.rbml_w, ii.defaultness); - } else { - // TODO this looks bogus and unnecessary - self.encode_predicates(&ecx.tcx.lookup_predicates(associated_type.def_id), - tag_item_generics); } if let Some(ty) = associated_type.ty { From 0384722357d4a6dcc2a1e79b41cf9f0df50cb577 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 17 Aug 2016 11:49:28 -0500 Subject: [PATCH 104/768] Add `must_use` to the Reference --- src/doc/reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index f0ab1488d4015..d14322a0655ca 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2070,6 +2070,9 @@ macro scope. trait of the same name. `{Self}` will be replaced with the type that is supposed to implement the trait but doesn't. To use this, the `on_unimplemented` feature gate must be enabled. +- `must_use` - on structs and enums, will warn if a value of this type isn't used or + assigned to a variable. You may also include an optional message by using + `#[must_use = "message"]` which will be given alongside the warning. ### Conditional compilation From ab6ca7e98fb0261185e5566cd77008434a900003 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 17 Aug 2016 13:50:36 -0700 Subject: [PATCH 105/768] Upgrade bootstrap compiler to 1.12 --- src/stage0.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stage0.txt b/src/stage0.txt index aaf88a67d2749..8c7961cc8497b 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,6 +12,6 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: beta-2016-07-06 -rustc_key: 411fd48b -cargo: nightly-2016-07-05 +rustc: beta-2016-08-17 +rustc_key: 195e6261 +cargo: nightly-2016-08-16 From d0a272b797fd538c4b4230bdefea534af8c1ffde Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 17 Aug 2016 14:26:05 -0700 Subject: [PATCH 106/768] Fix merge conflict --- src/test/ui/mismatched_types/issue-26480.stderr | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 13f23a5d01ac1..19caea27cff86 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -3,14 +3,18 @@ error[E0308]: mismatched types | 26 | $arr.len() * size_of($arr[0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize -$DIR/issue-26480.rs:37:5: 37:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) +... +38 | write!(hello); + | -------------- in this macro invocation error: non-scalar cast: `{integer}` as `()` --> $DIR/issue-26480.rs:32:19 | 32 | ($x:expr) => ($x as ()) | ^^^^^^^^ -$DIR/issue-26480.rs:38:5: 38:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs) +... +39 | cast!(2); + | --------- in this macro invocation error: aborting due to 2 previous errors From 61865384b8fa6d79d2b36cbd7c899eaf15f4aeea Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 17 Aug 2016 07:20:04 -0700 Subject: [PATCH 107/768] Replace local backtrace with def-use, repair std macro spans --- src/librustc_errors/emitter.rs | 144 +++++++++++++----- src/libsyntax_pos/lib.rs | 19 +++ src/test/run-fail-fulldeps/qquote.rs | 2 + .../codemap_tests}/bad-format-args.rs | 7 - .../ui/codemap_tests/bad-format-args.stderr | 26 ++++ .../codemap_tests}/issue-28308.rs | 4 - src/test/ui/codemap_tests/issue-28308.stderr | 10 ++ .../codemap_tests/repair_span_std_macros.rs | 13 ++ .../repair_span_std_macros.stderr | 11 ++ .../auxiliary/extern_macro_crate.rs | 23 +++ .../ui/cross-crate-macro-backtrace/main.rs | 17 +++ .../cross-crate-macro-backtrace/main.stderr | 10 ++ src/test/ui/macros/bad_hello.rs | 13 ++ src/test/ui/macros/bad_hello.stderr | 8 + .../macro-backtrace-invalid-internals.rs | 24 +-- .../macro-backtrace-invalid-internals.stderr | 56 +++++++ .../macros}/macro-backtrace-nested.rs | 11 +- .../ui/macros/macro-backtrace-nested.stderr | 20 +++ .../macros}/macro-backtrace-println.rs | 8 +- .../ui/macros/macro-backtrace-println.stderr | 11 ++ 20 files changed, 362 insertions(+), 75 deletions(-) rename src/test/{compile-fail => ui/codemap_tests}/bad-format-args.rs (71%) create mode 100644 src/test/ui/codemap_tests/bad-format-args.stderr rename src/test/{compile-fail => ui/codemap_tests}/issue-28308.rs (75%) create mode 100644 src/test/ui/codemap_tests/issue-28308.stderr create mode 100644 src/test/ui/codemap_tests/repair_span_std_macros.rs create mode 100644 src/test/ui/codemap_tests/repair_span_std_macros.stderr create mode 100644 src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs create mode 100644 src/test/ui/cross-crate-macro-backtrace/main.rs create mode 100644 src/test/ui/cross-crate-macro-backtrace/main.stderr create mode 100644 src/test/ui/macros/bad_hello.rs create mode 100644 src/test/ui/macros/bad_hello.stderr rename src/test/{compile-fail => ui/macros}/macro-backtrace-invalid-internals.rs (57%) create mode 100644 src/test/ui/macros/macro-backtrace-invalid-internals.stderr rename src/test/{compile-fail => ui/macros}/macro-backtrace-nested.rs (66%) create mode 100644 src/test/ui/macros/macro-backtrace-nested.stderr rename src/test/{compile-fail => ui/macros}/macro-backtrace-println.rs (66%) create mode 100644 src/test/ui/macros/macro-backtrace-println.stderr diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 981729ddb8395..11c9c5b1d9c8d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -12,7 +12,7 @@ use self::Destination::*; use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; -use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper}; +use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; use snippet::{StyledString, Style, Annotation, Line}; use styled_buffer::StyledBuffer; @@ -30,7 +30,10 @@ pub trait Emitter { impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { - self.emit_messages_default(db); + let mut primary_span = db.span.clone(); + let mut children = db.children.clone(); + self.fix_multispans_in_std_macros(&mut primary_span, &mut children); + self.emit_messages_default(&db.level, &db.message, &db.code, &primary_span, &children); } } @@ -381,19 +384,100 @@ impl EmitterWriter { max } - fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize { + fn get_max_line_num(&mut self, span: &MultiSpan, children: &Vec) -> usize { let mut max = 0; - let primary = self.get_multispan_max_line_num(&db.span); + let primary = self.get_multispan_max_line_num(span); max = if primary > max { primary } else { max }; - for sub in &db.children { + for sub in children { let sub_result = self.get_multispan_max_line_num(&sub.span); max = if sub_result > max { primary } else { max }; } max } + // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of + // <*macros>. Since these locations are often difficult to read, we move these Spans from + // <*macros> to their corresponding use site. + fn fix_multispan_in_std_macros(&mut self, span: &mut MultiSpan) -> bool { + let mut spans_updated = false; + + if let Some(ref cm) = self.cm { + let mut before_after: Vec<(Span, Span)> = vec![]; + let mut new_labels: Vec<(Span, String)> = vec![]; + + // First, find all the spans in <*macros> and point instead at their use site + for sp in span.primary_spans() { + if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) { + continue; + } + if cm.span_to_filename(sp.clone()).contains("macros>") { + let v = cm.macro_backtrace(sp.clone()); + if let Some(use_site) = v.last() { + before_after.push((sp.clone(), use_site.call_site.clone())); + } + } + for trace in cm.macro_backtrace(sp.clone()).iter().rev() { + // Only show macro locations that are local + // and display them like a span_note + if let Some(def_site) = trace.def_site_span { + if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) { + continue; + } + // Check to make sure we're not in any <*macros> + if !cm.span_to_filename(def_site).contains("macros>") { + new_labels.push((trace.call_site, + "in this macro invocation".to_string())); + break; + } + } + } + } + for (label_span, label_text) in new_labels { + span.push_span_label(label_span, label_text); + } + for sp_label in span.span_labels() { + if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) { + continue; + } + if cm.span_to_filename(sp_label.span.clone()).contains("macros>") { + let v = cm.macro_backtrace(sp_label.span.clone()); + if let Some(use_site) = v.last() { + before_after.push((sp_label.span.clone(), use_site.call_site.clone())); + } + } + } + // After we have them, make sure we replace these 'bad' def sites with their use sites + for (before, after) in before_after { + span.replace(before, after); + spans_updated = true; + } + } + + spans_updated + } + + // This does a small "fix" for multispans by looking to see if it can find any that + // point directly at <*macros>. Since these are often difficult to read, this + // will change the span to point at the use site. + fn fix_multispans_in_std_macros(&mut self, + span: &mut MultiSpan, + children: &mut Vec) { + let mut spans_updated = self.fix_multispan_in_std_macros(span); + for child in &mut children.iter_mut() { + spans_updated |= self.fix_multispan_in_std_macros(&mut child.span); + } + if spans_updated { + children.push(SubDiagnostic { + level: Level::Note, + message: "this error originates in a macro from the standard library".to_string(), + span: MultiSpan::new(), + render_span: None + }); + } + } + fn emit_message_default(&mut self, msp: &MultiSpan, msg: &str, @@ -528,10 +612,6 @@ impl EmitterWriter { } } - if let Some(ref primary_span) = msp.primary_span().as_ref() { - self.render_macro_backtrace_old_school(primary_span, &mut buffer)?; - } - // final step: take our styled buffer, render it, then output it emit_to_destination(&buffer.render(), level, &mut self.dst)?; @@ -578,26 +658,31 @@ impl EmitterWriter { } Ok(()) } - fn emit_messages_default(&mut self, db: &DiagnosticBuilder) { - let max_line_num = self.get_max_line_num(db); + fn emit_messages_default(&mut self, + level: &Level, + message: &String, + code: &Option, + span: &MultiSpan, + children: &Vec) { + let max_line_num = self.get_max_line_num(span, children); let max_line_num_len = max_line_num.to_string().len(); - match self.emit_message_default(&db.span, - &db.message, - &db.code, - &db.level, + match self.emit_message_default(span, + message, + code, + level, max_line_num_len, false) { Ok(()) => { - if !db.children.is_empty() { + if !children.is_empty() { let mut buffer = StyledBuffer::new(); draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1); - match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) { + match emit_to_destination(&buffer.render(), level, &mut self.dst) { Ok(()) => (), Err(e) => panic!("failed to emit error: {}", e) } } - for child in &db.children { + for child in children { match child.render_span { Some(FullSpan(ref msp)) => { match self.emit_message_default(msp, @@ -640,29 +725,6 @@ impl EmitterWriter { _ => () } } - fn render_macro_backtrace_old_school(&mut self, - sp: &Span, - buffer: &mut StyledBuffer) -> io::Result<()> { - if let Some(ref cm) = self.cm { - for trace in cm.macro_backtrace(sp.clone()) { - let line_offset = buffer.num_lines(); - - let mut diag_string = - format!("in this expansion of {}", trace.macro_decl_name); - if let Some(def_site_span) = trace.def_site_span { - diag_string.push_str( - &format!(" (defined in {})", - cm.span_to_filename(def_site_span))); - } - let snippet = cm.span_to_string(trace.call_site); - buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle); - buffer.append(line_offset, "note", Style::Level(Level::Note)); - buffer.append(line_offset, ": ", Style::NoStyle); - buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText); - } - } - Ok(()) - } } fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 0f171805bb0a9..b11bbea84abce 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -221,6 +221,25 @@ impl MultiSpan { &self.primary_spans } + /// Replaces all occurances of one Span with another. Used to move Spans in areas that don't + /// display well (like std macros). Returns true if replacements occurred. + pub fn replace(&mut self, before: Span, after: Span) -> bool { + let mut replacements_occurred = false; + for primary_span in &mut self.primary_spans { + if *primary_span == before { + *primary_span = after; + replacements_occurred = true; + } + } + for span_label in &mut self.span_labels { + if span_label.0 == before { + span_label.0 = after; + replacements_occurred = true; + } + } + replacements_occurred + } + /// Returns the strings to highlight. We always ensure that there /// is an entry for each of the primary spans -- for each primary /// span P, if there is at least one label with span P, we return diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index e1461c7847e4c..47e97abbbaa47 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -40,8 +40,10 @@ fn main() { }); let cx = &mut cx; + println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23))); assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23"); let expr = quote_expr!(&cx, let x isize = 20;); + println!("{}", pprust::expr_to_string(&*expr)); assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;"); } diff --git a/src/test/compile-fail/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs similarity index 71% rename from src/test/compile-fail/bad-format-args.rs rename to src/test/ui/codemap_tests/bad-format-args.rs index 8c58c8c60627d..de7bc88f9ba9c 100644 --- a/src/test/compile-fail/bad-format-args.rs +++ b/src/test/ui/codemap_tests/bad-format-args.rs @@ -8,13 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: requires at least a format string argument -// error-pattern: in this expansion - -// error-pattern: expected token: `,` -// error-pattern: in this expansion -// error-pattern: in this expansion - fn main() { format!(); format!("" 1); diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr new file mode 100644 index 0000000000000..fab8e2c8ce136 --- /dev/null +++ b/src/test/ui/codemap_tests/bad-format-args.stderr @@ -0,0 +1,26 @@ +error: requires at least a format string argument + --> $DIR/bad-format-args.rs:12:5 + | +12 | format!(); + | ^^^^^^^^^^ + | + = note: this error originates in a macro from the standard library + +error: expected token: `,` + --> $DIR/bad-format-args.rs:13:5 + | +13 | format!("" 1); + | ^^^^^^^^^^^^^^ + | + = note: this error originates in a macro from the standard library + +error: expected token: `,` + --> $DIR/bad-format-args.rs:14:5 + | +14 | format!("", 1 1); + | ^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro from the standard library + +error: aborting due to 3 previous errors + diff --git a/src/test/compile-fail/issue-28308.rs b/src/test/ui/codemap_tests/issue-28308.rs similarity index 75% rename from src/test/compile-fail/issue-28308.rs rename to src/test/ui/codemap_tests/issue-28308.rs index b0c44b5f33af1..e3a4920d951fd 100644 --- a/src/test/compile-fail/issue-28308.rs +++ b/src/test/ui/codemap_tests/issue-28308.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// this error is dispayed in `` -// error-pattern:cannot apply unary operator `!` to type `&'static str` -// error-pattern:in this expansion of assert! - fn main() { assert!("foo"); } diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr new file mode 100644 index 0000000000000..0d51a3f36e923 --- /dev/null +++ b/src/test/ui/codemap_tests/issue-28308.stderr @@ -0,0 +1,10 @@ +error: cannot apply unary operator `!` to type `&'static str` + --> $DIR/issue-28308.rs:12:5 + | +12 | assert!("foo"); + | ^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro from the standard library + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.rs b/src/test/ui/codemap_tests/repair_span_std_macros.rs new file mode 100644 index 0000000000000..3abc91d4f5ff1 --- /dev/null +++ b/src/test/ui/codemap_tests/repair_span_std_macros.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = vec![]; +} diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.stderr b/src/test/ui/codemap_tests/repair_span_std_macros.stderr new file mode 100644 index 0000000000000..1c9cbd63c3388 --- /dev/null +++ b/src/test/ui/codemap_tests/repair_span_std_macros.stderr @@ -0,0 +1,11 @@ +error[E0282]: unable to infer enough type information about `_` + --> $DIR/repair_span_std_macros.rs:12:13 + | +12 | let x = vec![]; + | ^^^^^^ cannot infer type for `_` + | + = note: type annotations or generic parameter binding required + = note: this error originates in a macro from the standard library + +error: aborting due to previous error + diff --git a/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs b/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs new file mode 100644 index 0000000000000..598e9f0f53aee --- /dev/null +++ b/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.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. + +#![crate_type = "dylib"] + +pub fn print(_args: std::fmt::Arguments) {} + +#[macro_export] +macro_rules! myprint { + ($($arg:tt)*) => (print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! myprintln { + ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); +} diff --git a/src/test/ui/cross-crate-macro-backtrace/main.rs b/src/test/ui/cross-crate-macro-backtrace/main.rs new file mode 100644 index 0000000000000..f8bb84abcd419 --- /dev/null +++ b/src/test/ui/cross-crate-macro-backtrace/main.rs @@ -0,0 +1,17 @@ +// 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. + +// aux-build:extern_macro_crate.rs +#[macro_use(myprintln, myprint)] +extern crate extern_macro_crate; + +fn main() { + myprintln!("{}"); //~ ERROR in this macro +} diff --git a/src/test/ui/cross-crate-macro-backtrace/main.stderr b/src/test/ui/cross-crate-macro-backtrace/main.stderr new file mode 100644 index 0000000000000..fceaa70288cf3 --- /dev/null +++ b/src/test/ui/cross-crate-macro-backtrace/main.stderr @@ -0,0 +1,10 @@ +error: invalid reference to argument `0` (no arguments given) + --> $DIR/main.rs:16:5 + | +16 | myprintln!("{}"); //~ ERROR in this macro + | ^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro from the standard library + +error: aborting due to previous error + diff --git a/src/test/ui/macros/bad_hello.rs b/src/test/ui/macros/bad_hello.rs new file mode 100644 index 0000000000000..a18771deacee7 --- /dev/null +++ b/src/test/ui/macros/bad_hello.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!(3 + 4); +} diff --git a/src/test/ui/macros/bad_hello.stderr b/src/test/ui/macros/bad_hello.stderr new file mode 100644 index 0000000000000..bffb33f468fc8 --- /dev/null +++ b/src/test/ui/macros/bad_hello.stderr @@ -0,0 +1,8 @@ +error: expected a literal + --> $DIR/bad_hello.rs:12:14 + | +12 | println!(3 + 4); + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs similarity index 57% rename from src/test/compile-fail/macro-backtrace-invalid-internals.rs rename to src/test/ui/macros/macro-backtrace-invalid-internals.rs index ebec204184d73..546e06b6c79f3 100644 --- a/src/test/compile-fail/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -12,46 +12,46 @@ macro_rules! fake_method_stmt { () => { - 1.fake() //~ ERROR no method named `fake` found + 1.fake() } } macro_rules! fake_field_stmt { () => { - 1.fake //~ ERROR no field with that name + 1.fake } } macro_rules! fake_anon_field_stmt { () => { - (1).0 //~ ERROR type was not a tuple + (1).0 } } macro_rules! fake_method_expr { () => { - 1.fake() //~ ERROR no method named `fake` found + 1.fake() } } macro_rules! fake_field_expr { () => { - 1.fake //~ ERROR no field with that name + 1.fake } } macro_rules! fake_anon_field_expr { () => { - (1).0 //~ ERROR type was not a tuple + (1).0 } } fn main() { - fake_method_stmt!(); //~ NOTE in this expansion of - fake_field_stmt!(); //~ NOTE in this expansion of - fake_anon_field_stmt!(); //~ NOTE in this expansion of + fake_method_stmt!(); + fake_field_stmt!(); + fake_anon_field_stmt!(); - let _ = fake_method_expr!(); //~ NOTE in this expansion of - let _ = fake_field_expr!(); //~ NOTE in this expansion of - let _ = fake_anon_field_expr!(); //~ NOTE in this expansion of + let _ = fake_method_expr!(); + let _ = fake_field_expr!(); + let _ = fake_anon_field_expr!(); } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr new file mode 100644 index 0000000000000..82000a59bfb17 --- /dev/null +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -0,0 +1,56 @@ +error: no method named `fake` found for type `{integer}` in the current scope + --> $DIR/macro-backtrace-invalid-internals.rs:15:13 + | +15 | 1.fake() + | ^^^^ +... +50 | fake_method_stmt!(); + | -------------------- in this macro invocation + +error: attempted access of field `fake` on type `{integer}`, but no field with that name was found + --> $DIR/macro-backtrace-invalid-internals.rs:21:11 + | +21 | 1.fake + | ^^^^^^ +... +51 | fake_field_stmt!(); + | ------------------- in this macro invocation + +error: attempted tuple index `0` on type `{integer}`, but the type was not a tuple or tuple struct + --> $DIR/macro-backtrace-invalid-internals.rs:27:11 + | +27 | (1).0 + | ^^^^^ +... +52 | fake_anon_field_stmt!(); + | ------------------------ in this macro invocation + +error: no method named `fake` found for type `{integer}` in the current scope + --> $DIR/macro-backtrace-invalid-internals.rs:33:13 + | +33 | 1.fake() + | ^^^^ +... +54 | let _ = fake_method_expr!(); + | ------------------- in this macro invocation + +error: attempted access of field `fake` on type `{integer}`, but no field with that name was found + --> $DIR/macro-backtrace-invalid-internals.rs:39:11 + | +39 | 1.fake + | ^^^^^^ +... +55 | let _ = fake_field_expr!(); + | ------------------ in this macro invocation + +error: attempted tuple index `0` on type `{integer}`, but the type was not a tuple or tuple struct + --> $DIR/macro-backtrace-invalid-internals.rs:45:11 + | +45 | (1).0 + | ^^^^^ +... +56 | let _ = fake_anon_field_expr!(); + | ----------------------- in this macro invocation + +error: aborting due to 6 previous errors + diff --git a/src/test/compile-fail/macro-backtrace-nested.rs b/src/test/ui/macros/macro-backtrace-nested.rs similarity index 66% rename from src/test/compile-fail/macro-backtrace-nested.rs rename to src/test/ui/macros/macro-backtrace-nested.rs index c2a270ea9f5c0..d8bf6222c1c2c 100644 --- a/src/test/compile-fail/macro-backtrace-nested.rs +++ b/src/test/ui/macros/macro-backtrace-nested.rs @@ -12,19 +12,18 @@ // we replace the span of the expanded expression with that of the call site. macro_rules! nested_expr { - () => (fake) //~ ERROR unresolved name - //~^ ERROR unresolved name + () => (fake) } macro_rules! call_nested_expr { - () => (nested_expr!()) //~ NOTE in this expansion of nested_expr! + () => (nested_expr!()) } macro_rules! call_nested_expr_sum { - () => { 1 + nested_expr!(); } //~ NOTE in this expansion of nested_expr! + () => { 1 + nested_expr!(); } } fn main() { - 1 + call_nested_expr!(); //~ NOTE in this expansion of call_nested_expr! - call_nested_expr_sum!(); //~ NOTE in this expansion of + 1 + call_nested_expr!(); + call_nested_expr_sum!(); } diff --git a/src/test/ui/macros/macro-backtrace-nested.stderr b/src/test/ui/macros/macro-backtrace-nested.stderr new file mode 100644 index 0000000000000..e452e8d69bdad --- /dev/null +++ b/src/test/ui/macros/macro-backtrace-nested.stderr @@ -0,0 +1,20 @@ +error[E0425]: unresolved name `fake` + --> $DIR/macro-backtrace-nested.rs:15:12 + | +15 | () => (fake) + | ^^^^ +... +27 | 1 + call_nested_expr!(); + | ------------------- in this macro invocation + +error[E0425]: unresolved name `fake` + --> $DIR/macro-backtrace-nested.rs:15:12 + | +15 | () => (fake) + | ^^^^ +... +28 | call_nested_expr_sum!(); + | ------------------------ in this macro invocation + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/ui/macros/macro-backtrace-println.rs similarity index 66% rename from src/test/compile-fail/macro-backtrace-println.rs rename to src/test/ui/macros/macro-backtrace-println.rs index 9d6da2a53a222..baf276919a5e8 100644 --- a/src/test/compile-fail/macro-backtrace-println.rs +++ b/src/test/ui/macros/macro-backtrace-println.rs @@ -17,15 +17,13 @@ fn print(_args: std::fmt::Arguments) {} macro_rules! myprint { - ($($arg:tt)*) => (print(format_args!($($arg)*))); //~ NOTE in this expansion of + ($($arg:tt)*) => (print(format_args!($($arg)*))); } macro_rules! myprintln { - ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0` - //~| NOTE in this expansion of concat! - //~| NOTE in this expansion of myprint! + ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); } fn main() { - myprintln!("{}"); //~ NOTE in this expansion of + myprintln!("{}"); } diff --git a/src/test/ui/macros/macro-backtrace-println.stderr b/src/test/ui/macros/macro-backtrace-println.stderr new file mode 100644 index 0000000000000..f21253bb67fb0 --- /dev/null +++ b/src/test/ui/macros/macro-backtrace-println.stderr @@ -0,0 +1,11 @@ +error: invalid reference to argument `0` (no arguments given) + --> $DIR/macro-backtrace-println.rs:24:30 + | +24 | ($fmt:expr) => (myprint!(concat!($fmt, "/n"))); + | ^^^^^^^^^^^^^^^^^^^ +... +28 | myprintln!("{}"); + | ----------------- in this macro invocation + +error: aborting due to previous error + From 2c3250adfa4676467f9ab31201a26187a66cbe0b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 18 Aug 2016 00:38:30 +0300 Subject: [PATCH 108/768] Nice graphs --- src/librustc_mir/build/scope.rs | 60 ++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index ca9e108bb415a..dc1d63a291118 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -459,16 +459,52 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for scope in self.scopes.iter_mut().rev() { let this_scope = scope.extent == extent; - // We must invalidate all the caches leading up to the scope we’re looking for, because - // the cached blocks will branch into build of scope not containing the new drop. If we - // add stuff to the currently inspected scope, then in some cases the non-unwind caches - // may become invalid, therefore we should invalidate these as well. The unwind caches - // will stay correct, because the already generated unwind blocks cannot be influenced - // by just added drop. + // When building drops, we try to cache chains of drops in such a way so these drops + // could be reused by the drops which would branch into the cached (already built) + // blocks. This, however, means that whenever we add a drop into a scope which already + // had some blocks built (and thus, cached) for it, we must invalidate all caches which + // might branch into the scope which had a drop just added to it. This is necessary, + // because otherwise some other code might use the cache to branch into already built + // chain of drops, essentially ignoring the newly added drop. // - // If we’re scheduling cleanup for non-droppable type (i.e. DropKind::Storage), then we - // do not need to invalidate unwind branch, because DropKind::Storage does not end up - // built in the unwind branch currently. + // For example consider there’s two scopes with a drop in each. These are built and + // thus the caches are filled: + // + // +--------------------------------------------------------+ + // | +---------------------------------+ | + // | | +--------+ +-------------+ | +---------------+ | + // | | | return | <-+ | drop(outer) | <-+ | drop(middle) | | + // | | +--------+ +-------------+ | +---------------+ | + // | +------------|outer_scope cache|--+ | + // +------------------------------|middle_scope cache|------+ + // + // Now, a new, inner-most scope is added along with a new drop into both inner-most and + // outer-most scopes: + // + // +------------------------------------------------------------+ + // | +----------------------------------+ | + // | | +--------+ +-------------+ | +---------------+ | +-------------+ + // | | | return | <+ | drop(new) | <-+ | drop(middle) | <--+| drop(inner) | + // | | +--------+ | | drop(outer) | | +---------------+ | +-------------+ + // | | +-+ +-------------+ | | + // | +---|invalid outer_scope cache|----+ | + // +----=----------------|invalid middle_scope cache|-----------+ + // + // If, when adding `drop(new)` we do not invalidate the cached blocks for both + // outer_scope and middle_scope, then, when building drops for the inner (right-most) + // scope, the old, cached blocks, without `drop(new)` will get used, producing the + // wrong results. + // + // The cache and its invalidation for unwind branch is somewhat special. The cache is + // per-drop, rather than per scope, which has a several different implications. Adding + // a new drop into a scope will not invalidate cached blocks of the prior drops in the + // scope. That is true, because none of the already existing drops will have an edge + // into a block with the newly added drop. + // + // Note that this code iterates scopes from the inner-most to the outer-most, + // invalidating caches of each scope visited. This way bare minimum of the + // caches gets invalidated. i.e. if a new drop is added into the middle scope, the + // cache of outer scpoe stays intact. let invalidate_unwind = needs_drop && !this_scope; scope.invalidate_cache(invalidate_unwind); if this_scope { @@ -497,9 +533,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: &Lvalue<'tcx>, item_ty: Ty<'tcx>) { for scope in self.scopes.iter_mut().rev() { - // We must invalidate all the caches leading up to and including the scope we’re - // looking for, because otherwise some of the blocks in the chain will become - // incorrect and must be rebuilt. + // See the comment in schedule_drop above. The primary difference is that we invalidate + // the unwind blocks unconditionally. That’s because the box free may be considered + // outer-most cleanup within the scope. scope.invalidate_cache(true); if scope.extent == extent { assert!(scope.free.is_none(), "scope already has a scheduled free!"); From 8d78237701f9646cd0ddc4645512e7cde3c58e5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Aug 2016 23:45:10 +0200 Subject: [PATCH 109/768] Add new error code tests --- src/librustc_resolve/diagnostics.rs | 2 +- src/test/compile-fail/E0423.rs | 15 +++++++++++++++ src/test/compile-fail/E0424.rs | 22 ++++++++++++++++++++++ src/test/compile-fail/E0425.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0426.rs | 15 +++++++++++++++ src/test/compile-fail/E0428.rs | 16 ++++++++++++++++ src/test/compile-fail/E0429.rs | 15 +++++++++++++++ src/test/compile-fail/E0430.rs | 15 +++++++++++++++ src/test/compile-fail/E0431.rs | 14 ++++++++++++++ src/test/compile-fail/E0432.rs | 14 ++++++++++++++ src/test/compile-fail/E0433.rs | 13 +++++++++++++ src/test/compile-fail/E0434.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0435.rs | 14 ++++++++++++++ src/test/compile-fail/E0437.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0438.rs | 20 ++++++++++++++++++++ src/test/compile-fail/E0439.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0440.rs | 22 ++++++++++++++++++++++ 17 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/E0423.rs create mode 100644 src/test/compile-fail/E0424.rs create mode 100644 src/test/compile-fail/E0425.rs create mode 100644 src/test/compile-fail/E0426.rs create mode 100644 src/test/compile-fail/E0428.rs create mode 100644 src/test/compile-fail/E0429.rs create mode 100644 src/test/compile-fail/E0430.rs create mode 100644 src/test/compile-fail/E0431.rs create mode 100644 src/test/compile-fail/E0432.rs create mode 100644 src/test/compile-fail/E0433.rs create mode 100644 src/test/compile-fail/E0434.rs create mode 100644 src/test/compile-fail/E0435.rs create mode 100644 src/test/compile-fail/E0437.rs create mode 100644 src/test/compile-fail/E0438.rs create mode 100644 src/test/compile-fail/E0439.rs create mode 100644 src/test/compile-fail/E0440.rs diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 11ef75ee6a8fc..5183d68065c7d 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -891,7 +891,7 @@ A `struct` variant name was used like a function name. Erroneous code example: ```compile_fail,E0423 -struct Foo { a: bool}; +struct Foo { a: bool }; let f = Foo(); // error: `Foo` is a struct variant name, but this expression uses diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs new file mode 100644 index 0000000000000..f5fea77cf9639 --- /dev/null +++ b/src/test/compile-fail/E0423.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + struct Foo { a: bool }; + + let f = Foo(); //~ ERROR E0423 +} diff --git a/src/test/compile-fail/E0424.rs b/src/test/compile-fail/E0424.rs new file mode 100644 index 0000000000000..445d0c5f3edc0 --- /dev/null +++ b/src/test/compile-fail/E0424.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. + +struct Foo; + +impl Foo { + fn bar(self) {} + + fn foo() { + self.bar(); //~ ERROR E0424 + } +} + +fn main () { +} diff --git a/src/test/compile-fail/E0425.rs b/src/test/compile-fail/E0425.rs new file mode 100644 index 0000000000000..70f4b1107ad4d --- /dev/null +++ b/src/test/compile-fail/E0425.rs @@ -0,0 +1,18 @@ +// 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. + +trait Foo { + fn bar() { + Self; //~ ERROR E0425 + } +} + +fn main () { +} diff --git a/src/test/compile-fail/E0426.rs b/src/test/compile-fail/E0426.rs new file mode 100644 index 0000000000000..2eb4c2d3b5e04 --- /dev/null +++ b/src/test/compile-fail/E0426.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + loop { + break 'a; //~ ERROR E0426 + } +} diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs new file mode 100644 index 0000000000000..42e237d31cbee --- /dev/null +++ b/src/test/compile-fail/E0428.rs @@ -0,0 +1,16 @@ +// 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. + +struct Bar; +struct Bar; //~ ERROR E0428 + //~^ ERROR E0428 + +fn main () { +} diff --git a/src/test/compile-fail/E0429.rs b/src/test/compile-fail/E0429.rs new file mode 100644 index 0000000000000..a7d19744f3fc7 --- /dev/null +++ b/src/test/compile-fail/E0429.rs @@ -0,0 +1,15 @@ +// 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. + +use std::fmt::self; //~ ERROR E0429 + //~^ ERROR E0432 + +fn main () { +} diff --git a/src/test/compile-fail/E0430.rs b/src/test/compile-fail/E0430.rs new file mode 100644 index 0000000000000..992876dd29443 --- /dev/null +++ b/src/test/compile-fail/E0430.rs @@ -0,0 +1,15 @@ +// 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. + +use std::fmt::{self, self}; //~ ERROR E0430 + //~^ ERROR E0252 + +fn main () { +} diff --git a/src/test/compile-fail/E0431.rs b/src/test/compile-fail/E0431.rs new file mode 100644 index 0000000000000..09ddc1efaf47c --- /dev/null +++ b/src/test/compile-fail/E0431.rs @@ -0,0 +1,14 @@ +// 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. + +use {self}; //~ ERROR E0431 + +fn main () { +} diff --git a/src/test/compile-fail/E0432.rs b/src/test/compile-fail/E0432.rs new file mode 100644 index 0000000000000..08d699ee4ca59 --- /dev/null +++ b/src/test/compile-fail/E0432.rs @@ -0,0 +1,14 @@ +// 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. + +use something::Foo; //~ ERROR E0432 + +fn main () { +} diff --git a/src/test/compile-fail/E0433.rs b/src/test/compile-fail/E0433.rs new file mode 100644 index 0000000000000..916d6220eb919 --- /dev/null +++ b/src/test/compile-fail/E0433.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + let map = HashMap::new(); //~ ERROR E0433 +} diff --git a/src/test/compile-fail/E0434.rs b/src/test/compile-fail/E0434.rs new file mode 100644 index 0000000000000..747d9f72c421b --- /dev/null +++ b/src/test/compile-fail/E0434.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { + let y = 5; + fn bar() -> u32 { + y //~ ERROR E0434 + } +} + +fn main () { +} diff --git a/src/test/compile-fail/E0435.rs b/src/test/compile-fail/E0435.rs new file mode 100644 index 0000000000000..f6cba15a0bff8 --- /dev/null +++ b/src/test/compile-fail/E0435.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + let foo = 42u32; + const FOO : u32 = foo; //~ ERROR E0435 +} diff --git a/src/test/compile-fail/E0437.rs b/src/test/compile-fail/E0437.rs new file mode 100644 index 0000000000000..7440a82773e7a --- /dev/null +++ b/src/test/compile-fail/E0437.rs @@ -0,0 +1,18 @@ +// 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. + +trait Foo {} + +impl Foo for i32 { + type Bar = bool; //~ ERROR E0437 +} + +fn main () { +} diff --git a/src/test/compile-fail/E0438.rs b/src/test/compile-fail/E0438.rs new file mode 100644 index 0000000000000..b3d453072049e --- /dev/null +++ b/src/test/compile-fail/E0438.rs @@ -0,0 +1,20 @@ +// 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. + +#![feature(associated_consts)] + +trait Foo {} + +impl Foo for i32 { + const BAR: bool = true; //~ ERROR E0438 +} + +fn main () { +} diff --git a/src/test/compile-fail/E0439.rs b/src/test/compile-fail/E0439.rs new file mode 100644 index 0000000000000..52443432021b2 --- /dev/null +++ b/src/test/compile-fail/E0439.rs @@ -0,0 +1,18 @@ +// 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. + +#![feature(platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439 +} + +fn main () { +} diff --git a/src/test/compile-fail/E0440.rs b/src/test/compile-fail/E0440.rs new file mode 100644 index 0000000000000..04e7584008df9 --- /dev/null +++ b/src/test/compile-fail/E0440.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. + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +struct f64x2(f64, f64); + +extern "platform-intrinsic" { + fn x86_mm_movemask_pd(x: f64x2) -> i32; //~ ERROR E0440 +} + +fn main () { +} From de5aaee0c5ee48a3ebaffa922846ed19321a8d2a Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Thu, 18 Aug 2016 00:07:24 +0200 Subject: [PATCH 110/768] Updated test for E0221 As a part of issue #35233 ?r @GuillaumeGomez --- src/test/compile-fail/E0221.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs index 213ec5a048880..c67bfb822c068 100644 --- a/src/test/compile-fail/E0221.rs +++ b/src/test/compile-fail/E0221.rs @@ -18,7 +18,11 @@ trait Foo { trait Bar : Foo { type A: T2; fn do_something() { - let _: Self::A; //~ ERROR E0221 + let _: Self::A; + //~^ ERROR E0221 + //~| NOTE ambiguous associated type `A` + //~| NOTE associated type `Self` could derive from `Foo` + //~| NOTE associated type `Self` could derive from `Bar` } } From 28ed8b159237a2704f2308a404b3bd81b676ce17 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Aug 2016 21:28:17 +0300 Subject: [PATCH 111/768] Fix #[derive] for empty tuple structs/variants --- src/libsyntax/ext/build.rs | 2 +- src/libsyntax_ext/deriving/decodable.rs | 6 ++--- src/libsyntax_ext/deriving/default.rs | 4 ++-- src/libsyntax_ext/deriving/generic/mod.rs | 6 ++--- .../empty-struct-braces-derive.rs | 24 ++++++++++++++++++- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..7600bff96952d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -844,7 +844,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec>) -> P { let pat = if subpats.is_empty() { - PatKind::Path(None, path) + PatKind::Struct(path, Vec::new(), false) } else { PatKind::TupleStruct(path, subpats, None) }; diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 9a332227053c7..f395f7bd0c4c4 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -110,7 +110,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, return match *substr.fields { StaticStruct(_, ref summary) => { let nfields = match *summary { - Unnamed(ref fields) => fields.len(), + Unnamed(ref fields, _) => fields.len(), Named(ref fields) => fields.len(), }; let read_struct_field = cx.ident_of("read_struct_field"); @@ -193,9 +193,9 @@ fn decode_static_fields(cx: &mut ExtCtxt, where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P { match *fields { - Unnamed(ref fields) => { + Unnamed(ref fields, is_tuple) => { let path_expr = cx.expr_path(outer_pat_path); - if fields.is_empty() { + if !is_tuple { path_expr } else { let fields = fields.iter() diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 9df3db938b1f9..449c1ff066b3b 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -57,8 +57,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur return match *substr.fields { StaticStruct(_, ref summary) => { match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { + Unnamed(ref fields, is_tuple) => { + if !is_tuple { cx.expr_ident(trait_span, substr.type_ident) } else { let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..22e98fb213f95 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -294,8 +294,8 @@ pub struct FieldInfo<'a> { /// Fields for a static method pub enum StaticFields { - /// Tuple structs/enum variants like this. - Unnamed(Vec), + /// Tuple and unit structs/enum variants like this. + Unnamed(Vec, bool /*is tuple*/), /// Normal structs/struct variants. Named(Vec<(Ident, Span)>), } @@ -1470,7 +1470,7 @@ impl<'a> TraitDef<'a> { (_, false) => Named(named_idents), // empty structs _ if struct_def.is_struct() => Named(named_idents), - _ => Unnamed(just_spans), + _ => Unnamed(just_spans, struct_def.is_tuple()), } } diff --git a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs index 8d19209208dc4..66ffff94333e9 100644 --- a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs +++ b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// `#[derive(Trait)]` works for empty structs/variants with braces +// `#[derive(Trait)]` works for empty structs/variants with braces or parens. +#![feature(relaxed_adts)] #![feature(rustc_private)] extern crate serialize as rustc_serialize; @@ -18,11 +19,16 @@ extern crate serialize as rustc_serialize; Default, Debug, RustcEncodable, RustcDecodable)] struct S {} +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + Default, Debug, RustcEncodable, RustcDecodable)] +struct Z(); + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] enum E { V {}, U, + W(), } fn main() { @@ -34,6 +40,14 @@ fn main() { assert!(!(s < s1)); assert_eq!(format!("{:?}", s), "S"); + let z = Z(); + let z1 = z; + let z2 = z.clone(); + assert_eq!(z, z1); + assert_eq!(z, z2); + assert!(!(z < z1)); + assert_eq!(format!("{:?}", z), "Z"); + let e = E::V {}; let e1 = e; let e2 = e.clone(); @@ -41,4 +55,12 @@ fn main() { assert_eq!(e, e2); assert!(!(e < e1)); assert_eq!(format!("{:?}", e), "V"); + + let e = E::W(); + let e1 = e; + let e2 = e.clone(); + assert_eq!(e, e1); + assert_eq!(e, e2); + assert!(!(e < e1)); + assert_eq!(format!("{:?}", e), "W"); } From 54d42cc912d1510e561a4d4274e4f821becd1736 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 17 Aug 2016 15:11:18 -0700 Subject: [PATCH 112/768] Rebase. Fix mutable iteration nit. --- src/librustc_errors/emitter.rs | 2 +- src/test/ui/mismatched_types/issue-26480.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 11c9c5b1d9c8d..5fd9226aba9d4 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -465,7 +465,7 @@ impl EmitterWriter { span: &mut MultiSpan, children: &mut Vec) { let mut spans_updated = self.fix_multispan_in_std_macros(span); - for child in &mut children.iter_mut() { + for child in children.iter_mut() { spans_updated |= self.fix_multispan_in_std_macros(&mut child.span); } if spans_updated { diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 19caea27cff86..5d07ee1648a3e 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types 26 | $arr.len() * size_of($arr[0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize ... -38 | write!(hello); +37 | write!(hello); | -------------- in this macro invocation error: non-scalar cast: `{integer}` as `()` @@ -13,7 +13,7 @@ error: non-scalar cast: `{integer}` as `()` 32 | ($x:expr) => ($x as ()) | ^^^^^^^^ ... -39 | cast!(2); +38 | cast!(2); | --------- in this macro invocation error: aborting due to 2 previous errors From 3c4ecc9e7ce47667e05dcea001bbe91453c3ca22 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 10 Aug 2016 01:43:12 -0700 Subject: [PATCH 113/768] Display secondary span for E0053 for Sort TypeErrors --- src/librustc/hir/map/mod.rs | 7 ++ src/librustc/infer/error_reporting.rs | 6 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc_typeck/check/compare_method.rs | 78 +++++++++++++++------ 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 7e82a4a05a764..04031fabc5866 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -569,6 +569,13 @@ impl<'ast> Map<'ast> { } } + pub fn expect_impl_item(&self, id: NodeId) -> &'ast ImplItem { + match self.find(id) { + Some(NodeImplItem(item)) => item, + _ => bug!("expected impl item, found {}", self.node_to_string(id)) + } + } + pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem { match self.find(id) { Some(NodeTraitItem(item)) => item, diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9a6375719c1bc..1e053d6bfdab2 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -523,6 +523,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, origin: TypeOrigin, + secondary_span: Option<(Span, String)>, values: Option>, terr: &TypeError<'tcx>) { @@ -553,6 +554,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } diag.span_label(span, &terr); + if let Some((sp, msg)) = secondary_span { + diag.span_label(sp, &msg); + } self.note_error_origin(diag, &origin); self.check_and_note_conflicting_crates(diag, terr, span); @@ -569,7 +573,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.sess, trace.origin.span(), E0308, "{}", trace.origin.as_failure_str() ); - self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr); + self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr); diag } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 33db0053cda13..d6f263fcebeb0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -161,7 +161,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.sess, origin.span(), E0271, "type mismatch resolving `{}`", predicate ); - self.note_type_err(&mut diag, origin, values, err); + self.note_type_err(&mut diag, origin, None, values, err); self.note_obligation_cause(&mut diag, obligation); diag.emit(); }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6bcf21563cb98..93badd9813006 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -12,10 +12,9 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, Reveal}; -use rustc::ty::error::ExpectedFound; +use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; -use rustc::hir::map::Node; -use rustc::hir::{ImplItemKind, TraitItem_}; +use rustc::hir::{ImplItemKind, TraitItem_, Ty_}; use syntax::ast; use syntax_pos::Span; @@ -300,6 +299,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span, impl_m_body_id, &impl_sig); + let impl_args = impl_sig.inputs.clone(); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety, abi: impl_m.fty.abi, @@ -318,6 +318,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span, impl_m_body_id, &trait_sig); + let trait_args = trait_sig.inputs.clone(); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety, abi: trait_m.fty.abi, @@ -331,16 +332,54 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_fty, trait_fty); + let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a method", impl_m) + }; + + let (impl_err_span, trait_err_span) = match terr { + TypeError::Sorts(ExpectedFound { expected, found }) => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => + trait_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a MethodTraitItem", trait_m) + }; + let impl_iter = impl_args.iter(); + let trait_iter = trait_args.iter(); + let arg_idx = impl_iter.zip(trait_iter) + .position(|(impl_arg_ty, trait_arg_ty)| { + *impl_arg_ty == found && *trait_arg_ty == expected + }).unwrap(); + impl_m_iter.zip(trait_m_iter) + .nth(arg_idx) + .map(|(impl_arg, trait_arg)| + (impl_arg.ty.span, Some(trait_arg.ty.span))) + .unwrap_or( + (origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + }; + + let origin = TypeOrigin::MethodCompatCheck(impl_err_span); + let mut diag = struct_span_err!( tcx.sess, origin.span(), E0053, "method `{}` has an incompatible type for trait", trait_m.name ); + infcx.note_type_err( - &mut diag, origin, + &mut diag, + origin, + trait_err_span.map(|sp| (sp, format!("original trait requirement"))), Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_fty, - found: impl_fty - })), &terr + expected: trait_fty, + found: impl_fty + })), + &terr ); diag.emit(); return @@ -487,12 +526,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_ty); // Locate the Span containing just the type of the offending impl - if let Some(impl_trait_node) = tcx.map.get_if_local(impl_c.def_id) { - if let Node::NodeImplItem(impl_trait_item) = impl_trait_node { - if let ImplItemKind::Const(ref ty, _) = impl_trait_item.node { - origin = TypeOrigin::Misc(ty.span); - } - } + match tcx.map.expect_impl_item(impl_c_node_id).node { + ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span), + _ => bug!("{:?} is not a impl const", impl_c) } let mut diag = struct_span_err!( @@ -502,16 +538,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ); // Add a label to the Span containing just the type of the item - if let Some(orig_trait_node) = tcx.map.get_if_local(trait_c.def_id) { - if let Node::NodeTraitItem(orig_trait_item) = orig_trait_node { - if let TraitItem_::ConstTraitItem(ref ty, _) = orig_trait_item.node { - diag.span_label(ty.span, &format!("original trait requirement")); - } - } - } + let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap(); + let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node { + TraitItem_::ConstTraitItem(ref ty, _) => ty.span, + _ => bug!("{:?} is not a trait const", trait_c) + }; infcx.note_type_err( - &mut diag, origin, + &mut diag, + origin, + Some((trait_c_span, format!("original trait requirement"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_ty, found: impl_ty From 34bc3c94f2639c16d3c009026e4b0e1d1a83d9a2 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 17 Aug 2016 04:04:14 -0700 Subject: [PATCH 114/768] Display secondary span for E0053 for Mutability TypeErrors --- src/librustc_typeck/check/compare_method.rs | 28 +++++++++++++++++++++ src/test/compile-fail/E0053.rs | 14 ++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 93badd9813006..043883df035d0 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -338,6 +338,34 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let (impl_err_span, trait_err_span) = match terr { + TypeError::Mutability => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => + trait_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a MethodTraitItem", trait_m) + }; + + impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| { + match (&impl_arg.ty.node, &trait_arg.ty.node) { + (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | + (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => + impl_mt.mutbl != trait_mt.mutbl, + _ => false + } + }).map(|(ref impl_arg, ref trait_arg)| { + match (impl_arg.to_self(), trait_arg.to_self()) { + (Some(impl_self), Some(trait_self)) => + (impl_self.span, Some(trait_self.span)), + (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), + _ => bug!("impl and trait fns have different first args, \ + impl: {:?}, trait: {:?}", impl_arg, trait_arg) + } + }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } TypeError::Sorts(ExpectedFound { expected, found }) => { if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { diff --git a/src/test/compile-fail/E0053.rs b/src/test/compile-fail/E0053.rs index 4effda3c49e8e..7022010714aa7 100644 --- a/src/test/compile-fail/E0053.rs +++ b/src/test/compile-fail/E0053.rs @@ -9,15 +9,21 @@ // except according to those terms. trait Foo { - fn foo(x: u16); - fn bar(&self); + fn foo(x: u16); //~ NOTE original trait requirement + fn bar(&self); //~ NOTE original trait requirement } struct Bar; impl Foo for Bar { - fn foo(x: i16) { } //~ ERROR E0053 - fn bar(&mut self) { } //~ ERROR E0053 + fn foo(x: i16) { } + //~^ ERROR method `foo` has an incompatible type for trait + //~| NOTE expected u16 + fn bar(&mut self) { } + //~^ ERROR method `bar` has an incompatible type for trait + //~| NOTE values differ in mutability + //~| NOTE expected type `fn(&Bar)` + //~| NOTE found type `fn(&mut Bar)` } fn main() { From 9863afe029092d421c9a3daafd6b7a718d53f1cf Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 16 Aug 2016 16:11:03 -0700 Subject: [PATCH 115/768] 1.11 changelog --- RELEASES.md | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index c798c56cd6d03..8817d7f88a738 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,180 @@ +Version 1.11.0 (2016-08-18) +=========================== + +Language +-------- + +* [`cfg_attr` works on `path` attributes] + (https://github.com/rust-lang/rust/pull/34546) +* [Support nested `cfg_attr` attributes] + (https://github.com/rust-lang/rust/pull/34216) +* [Allow statement-generating braced macro invocations at the end of blocks] + (https://github.com/rust-lang/rust/pull/34436) +* [Macros can be expanded inside of trait definitions] + (https://github.com/rust-lang/rust/pull/34213) +* [`#[macro_use]` works properly when it is itself expanded from a macro] + (https://github.com/rust-lang/rust/pull/34032) + +Stabilized APIs +--------------- + +* [`BinaryHeap::append`] + (https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.append) +* [`BTreeMap::append`] + (https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.append) +* [`BTreeMap::split_off`] + (https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.split_off) +* [`BTreeSet::append`] + (https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.append) +* [`BTreeSet::split_off`] + (https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.split_off) +* [`f32::to_degrees`] + (https://doc.rust-lang.org/std/primitive.f32.html#method.to_degrees) + (in libcore - previously stabilized in libstd) +* [`f32::to_radians`] + (https://doc.rust-lang.org/std/primitive.f32.html#method.to_radians) + (in libcore - previously stabilized in libstd) +* [`f64::to_degrees`] + (https://doc.rust-lang.org/std/primitive.f64.html#method.to_degrees) + (in libcore - previously stabilized in libstd) +* [`f64::to_radians`] + (https://doc.rust-lang.org/std/primitive.f64.html#method.to_radians) + (in libcore - previously stabilized in libstd) +* [`Iterator::sum`] + (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) +* [`Iterator::product`] + (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) +* [`Cell::get_mut`] + (https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut) +* [`RefCell::get_mut`] + (https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.get_mut) + +Libraries +--------- + +* [The `thread_local!` macro supports multiple definitions in a single + invocation, and can apply attributes] + (https://github.com/rust-lang/rust/pull/34077) +* [`Cow` implements `Default`] + (https://github.com/rust-lang/rust/pull/34305) +* [`Wrapping` implements binary, octal, lower-hex and upper-hex + `Display` formatting] + (https://github.com/rust-lang/rust/pull/34190) +* [The range types implement `Hash`] + (https://github.com/rust-lang/rust/pull/34180) +* [`lookup_host` ignores unknown address types] + (https://github.com/rust-lang/rust/pull/34067) +* [`assert_eq!` accepts a custom error message, like `assert!` does] + (https://github.com/rust-lang/rust/pull/33976) +* [The main thread is now called "main" instead of "<main>"] + (https://github.com/rust-lang/rust/pull/33803) + +Cargo +----- + +* [Disallow specifying features of transitive deps] + (https://github.com/rust-lang/cargo/pull/2821) +* [Add color support for Windows consoles] + (https://github.com/rust-lang/cargo/pull/2804) +* [Fix `harness = false` on `[lib]` sections] + (https://github.com/rust-lang/cargo/pull/2795) +* [Don't panic when `links` contains a '.'] + (https://github.com/rust-lang/cargo/pull/2787) +* [Build scripts can emit warnings] + (https://github.com/rust-lang/cargo/pull/2630), + and `-vv` prints warnings for all crates. +* [Ignore file locks on OS X NFS mounts] + (https://github.com/rust-lang/cargo/pull/2720) +* [Don't warn about `package.metadata` keys] + (https://github.com/rust-lang/cargo/pull/2668). + This provides room for expansion by arbitrary tools. +* [Add support for cdylib crate types] + (https://github.com/rust-lang/cargo/pull/2741) +* [Prevent publishing crates when files are dirty] + (https://github.com/rust-lang/cargo/pull/2781) +* [Don't fetch all crates on clean] + (https://github.com/rust-lang/cargo/pull/2704) +* [Propagate --color option to rustc] + (https://github.com/rust-lang/cargo/pull/2779) +* [Fix `cargo doc --open` on Windows] + (https://github.com/rust-lang/cargo/pull/2780) +* [Improve autocompletion] + (https://github.com/rust-lang/cargo/pull/2772) +* [Configure colors of stderr as well as stdout] + (https://github.com/rust-lang/cargo/pull/2739) + +Performance +----------- + +* [Caching projections speeds up type check dramatically for some + workloads] + (https://github.com/rust-lang/rust/pull/33816) +* [The default `HashMap` hasher is SipHash 1-3 instead of SipHash 2-4] + (https://github.com/rust-lang/rust/pull/33940) + This hasher is faster, but is believed to provide sufficient + protection from collision attacks. +* [Comparison of `Ipv4Addr` is 10x faster] + (https://github.com/rust-lang/rust/pull/33891) + +Rustdoc +------- + +* [Fix empty implementation section on some module pages] + (https://github.com/rust-lang/rust/pull/34536) +* [Fix inlined renamed reexports in import lists] + (https://github.com/rust-lang/rust/pull/34479) +* [Fix search result layout for enum variants and struct fields] + (https://github.com/rust-lang/rust/pull/34477) +* [Fix issues with source links to external crates] + (https://github.com/rust-lang/rust/pull/34387) +* [Fix redirect pages for renamed reexports] + (https://github.com/rust-lang/rust/pull/34245) + +Tooling +------- + +* [rustc is better at finding the MSVC toolchain] + (https://github.com/rust-lang/rust/pull/34492) +* [When emitting debug info, rustc emits frame pointers for closures, + shims and glue, as it does for all other functions] + (https://github.com/rust-lang/rust/pull/33909) +* [rust-lldb warns about unsupported versions of LLDB] + (https://github.com/rust-lang/rust/pull/34646) +* Many more errors have been given error codes and extended + explanations +* API documentation continues to be improved, with many new examples + +Misc +---- + +* [rustc no longer hangs when dependencies recursively re-export + submodules] + (https://github.com/rust-lang/rust/pull/34542) +* [rustc requires LLVM 3.7+] + (https://github.com/rust-lang/rust/pull/34104) +* [The 'How Safe and Unsafe Interact' chapter of The Rustonomicon was + rewritten] + (https://github.com/rust-lang/rust/pull/33895) +* [rustc support 16-bit pointer sizes] + (https://github.com/rust-lang/rust/pull/33460). + No targets use this yet, but it works toward AVR support. + +Compatibility Notes +------------------- + +* [`const`s and `static`s may not have unsized types] + (https://github.com/rust-lang/rust/pull/34443) +* [The new follow-set rules that place restrictions on `macro_rules!` + in order to ensure syntax forward-compatibility have been enabled] + (https://github.com/rust-lang/rust/pull/33982) + This was an [ammendment to RFC 550] + (https://github.com/rust-lang/rfcs/pull/1384), + and has been a warning since 1.10. +* [`cfg` attribute process has been refactored to fix various bugs] + (https://github.com/rust-lang/rust/pull/33706). + This causes breakage in some corner cases. + + Version 1.10.0 (2016-07-07) =========================== From 70ce90c320aa4d6ae7646497a0cd17f775b94e43 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 16 Aug 2016 15:02:20 -0700 Subject: [PATCH 116/768] Move 'doesn't live long enough' errors to labels --- .../borrowck/gather_loans/lifetime.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 92 +++++++++++++++---- .../borrowck-let-suggestion-suffixes.rs | 23 ++--- .../borrowck/borrowck-let-suggestion.rs | 6 +- .../compile-fail/impl-trait/loan-extend.rs | 6 +- .../region-borrow-params-issue-29793-small.rs | 24 +++-- .../send-is-not-static-ensures-scoping.rs | 2 +- .../unboxed-closures-failed-recursive-fn-1.rs | 2 +- .../{compile-fail => ui/span}/issue-11925.rs | 2 +- src/test/ui/span/issue-11925.stderr | 14 +++ 10 files changed, 128 insertions(+), 45 deletions(-) rename src/test/{compile-fail => ui/span}/issue-11925.rs (89%) create mode 100644 src/test/ui/span/issue-11925.stderr diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index e34c6e567bd8e..667bf16874ec4 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { //! Reports an error if `loan_region` is larger than `max_scope` if !self.bccx.is_subregion_of(self.loan_region, max_scope) { - Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) + Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause))) } else { Ok(()) } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e0cbd972bd37f..7e3466c1ad84a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -43,7 +43,7 @@ use std::mem; use std::rc::Rc; use syntax::ast; use syntax::attr::AttrMetaMethods; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span, BytePos}; use errors::DiagnosticBuilder; use rustc::hir; @@ -566,7 +566,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { #[derive(PartialEq)] pub enum bckerr_code { err_mutbl, - err_out_of_scope(ty::Region, ty::Region), // superscope, subscope + err_out_of_scope(ty::Region, ty::Region, euv::LoanCause), // superscope, subscope, loan cause err_borrowed_pointer_too_short(ty::Region, ty::Region), // loan, ptr } @@ -614,9 +614,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn report(&self, err: BckError<'tcx>) { // Catch and handle some particular cases. match (&err.code, &err.cause) { - (&err_out_of_scope(ty::ReScope(_), ty::ReStatic), + (&err_out_of_scope(ty::ReScope(_), ty::ReStatic, _), &BorrowViolation(euv::ClosureCapture(span))) | - (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), + (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..), _), &BorrowViolation(euv::ClosureCapture(span))) => { return self.report_out_of_scope_escaping_closure_capture(&err, span); } @@ -963,6 +963,24 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .emit(); } + fn convert_region_to_span(&self, region: ty::Region) -> Option { + match region { + ty::ReScope(scope) => { + match scope.span(&self.tcx.region_maps, &self.tcx.map) { + Some(s) => { + let mut last_span = s; + last_span.lo = BytePos(last_span.hi.0 - 1); + Some(last_span) + } + None => { + None + } + } + } + _ => None + } + } + pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>, error_span: Span) { let code = err.code; @@ -1003,19 +1021,61 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - err_out_of_scope(super_scope, sub_scope) => { - self.tcx.note_and_explain_region( - db, - "reference must be valid for ", - sub_scope, - "..."); - self.tcx.note_and_explain_region( - db, - "...but borrowed value is only valid for ", - super_scope, - ""); + err_out_of_scope(super_scope, sub_scope, cause) => { + match cause { + euv::ClosureCapture(s) => { + match db.span.primary_span() { + Some(primary) => { + db.span = MultiSpan::from_span(s); + db.span_label(primary, &format!("capture occurs here")); + db.span_label(s, &format!("does not live long enough")); + } + None => () + } + } + _ => { + db.span_label(error_span, &format!("does not live long enough")); + } + } + + let sub_span = self.convert_region_to_span(sub_scope); + let super_span = self.convert_region_to_span(super_scope); + + match (sub_span, super_span) { + (Some(s1), Some(s2)) if s1 == s2 => { + db.span_label(s1, &"borrowed value dropped before borrower"); + db.note("values in a scope are dropped in the opposite order \ + they are created"); + } + _ => { + match sub_span { + Some(s) => { + db.span_label(s, &"borrowed value must be valid until here"); + } + None => { + self.tcx.note_and_explain_region( + db, + "borrowed value must be valid for ", + sub_scope, + "..."); + } + } + match super_span { + Some(s) => { + db.span_label(s, &"borrowed value only valid until here"); + } + None => { + self.tcx.note_and_explain_region( + db, + "...but borrowed value is only valid for ", + super_scope, + ""); + } + } + } + } + if let Some(span) = statement_scope_span(self.tcx, super_scope) { - db.span_label(error_span, &format!("does not live long enough")); db.span_help(span, "consider using a `let` binding to increase its lifetime"); } diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs index 02aa771c78789..6c9f67b2b33d4 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs +++ b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs @@ -13,47 +13,48 @@ fn f() { let mut v1 = Vec::new(); // statement 1 let mut v2 = Vec::new(); // statement 2 - //~^ NOTE reference must be valid for the block suffix following statement 2 let young = ['y']; // statement 3 - //~^ NOTE ...but borrowed value is only valid for the block suffix following statement 3 v2.push(&young[0]); // statement 4 //~^ ERROR `young[..]` does not live long enough + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created let mut v3 = Vec::new(); // statement 5 - //~^ NOTE reference must be valid for the block suffix following statement 5 v3.push(&'x'); // statement 6 //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE ...but borrowed value is only valid for the statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime { let mut v4 = Vec::new(); // (sub) statement 0 - //~^ NOTE reference must be valid for the block suffix following statement 0 v4.push(&'y'); //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE ...but borrowed value is only valid for the statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime } // (statement 7) + //~^ NOTE borrowed value must be valid until here let mut v5 = Vec::new(); // statement 8 - //~^ NOTE reference must be valid for the block suffix following statement 8 v5.push(&'z'); //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE ...but borrowed value is only valid for the statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime v1.push(&old[0]); } +//~^ NOTE borrowed value dropped before borrower +//~| NOTE borrowed value must be valid until here +//~| NOTE borrowed value must be valid until here fn main() { f(); diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs index 866e72f1a5258..ef8f44c1df789 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs +++ b/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs @@ -11,11 +11,11 @@ fn f() { let x = [1].iter(); //~^ ERROR borrowed value does not live long enough - //~|does not live long enough - //~| NOTE reference must be valid for the block suffix following statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime - //~| NOTE ...but borrowed value is only valid for the statement at 12:4 } +//~^ borrowed value must be valid until here fn main() { f(); diff --git a/src/test/compile-fail/impl-trait/loan-extend.rs b/src/test/compile-fail/impl-trait/loan-extend.rs index ceaa8f4eed723..8dfcb08cff339 100644 --- a/src/test/compile-fail/impl-trait/loan-extend.rs +++ b/src/test/compile-fail/impl-trait/loan-extend.rs @@ -14,10 +14,10 @@ fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () } fn main() { - //~^ NOTE reference must be valid for the block let long; let mut short = 0; - //~^ NOTE but borrowed value is only valid for the block suffix following statement 1 long = borrow(&mut short); //~^ ERROR `short` does not live long enough -} + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created +} //~ borrowed value dropped before borrower diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs index 6be2adbe2a0d1..196c233a0b5c3 100644 --- a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs +++ b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs @@ -16,15 +16,19 @@ fn escaping_borrow_of_closure_params_1() { let g = |x: usize, y:usize| { - //~^ NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body - //~| NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR `x` does not live long enough //~| ERROR `y` does not live long enough + //~| NOTE capture occurs here + //~| NOTE capture occurs here + //~| NOTE does not live long enough + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created + //~| NOTE values in a scope are dropped in the opposite order they are created return f; }; + //~^ NOTE borrowed value dropped before borrower + //~| NOTE borrowed value dropped before borrower // We delberately do not call `g`; this small version of the test, // after adding such a call, was (properly) rejected even when the @@ -35,15 +39,19 @@ fn escaping_borrow_of_closure_params_1() { fn escaping_borrow_of_closure_params_2() { let g = |x: usize, y:usize| { - //~^ NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body - //~| NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR `x` does not live long enough //~| ERROR `y` does not live long enough + //~| NOTE capture occurs here + //~| NOTE capture occurs here + //~| NOTE does not live long enough + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created + //~| NOTE values in a scope are dropped in the opposite order they are created f }; + //~^ NOTE borrowed value dropped before borrower + //~| NOTE borrowed value dropped before borrower // (we don't call `g`; see above) } diff --git a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs index 2e401ba6e9085..1b7718d2283a7 100644 --- a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs +++ b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs @@ -26,8 +26,8 @@ fn main() { let y = &x; //~ ERROR `x` does not live long enough scoped(|| { - //~^ ERROR `y` does not live long enough let _z = y; + //~^ ERROR `y` does not live long enough }) }; diff --git a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs index f73b06653012a..ce60521034ee7 100644 --- a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs +++ b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs @@ -22,8 +22,8 @@ fn a() { let mut factorial: Option u32>> = None; let f = |x: u32| -> u32 { - //~^ ERROR `factorial` does not live long enough let g = factorial.as_ref().unwrap(); + //~^ ERROR `factorial` does not live long enough if x == 0 {1} else {x * g(x-1)} }; diff --git a/src/test/compile-fail/issue-11925.rs b/src/test/ui/span/issue-11925.rs similarity index 89% rename from src/test/compile-fail/issue-11925.rs rename to src/test/ui/span/issue-11925.rs index 7bd072c6268cd..7bea8642cce14 100644 --- a/src/test/compile-fail/issue-11925.rs +++ b/src/test/ui/span/issue-11925.rs @@ -15,7 +15,7 @@ fn to_fn_once>(f: F) -> F { f } fn main() { let r = { let x: Box<_> = box 42; - let f = to_fn_once(move|| &x); //~ ERROR: `x` does not live long enough + let f = to_fn_once(move|| &x); f() }; diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr new file mode 100644 index 0000000000000..d379cfc3d68a7 --- /dev/null +++ b/src/test/ui/span/issue-11925.stderr @@ -0,0 +1,14 @@ +error: `x` does not live long enough + --> $DIR/issue-11925.rs:18:36 + | +18 | let f = to_fn_once(move|| &x); + | ^ + | | + | does not live long enough + | borrowed value only valid until here +... +23 | } + | - borrowed value must be valid until here + +error: aborting due to previous error + From f6e06a8a365b118937079e3f9c4dfa8f221e7db5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Aug 2016 21:28:17 +0300 Subject: [PATCH 117/768] Split `AstBuilder::pat_enum` into `pat_tuple_struct` and `pat_path` --- src/libsyntax/ext/build.rs | 40 ++++++++-------- src/libsyntax_ext/deriving/cmp/ord.rs | 2 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 46 +++++++++++-------- 4 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7600bff96952d..507e46ea59e9e 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -171,9 +171,11 @@ pub trait AstBuilder { span: Span, ident: ast::Ident, bm: ast::BindingMode) -> P; - fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec> ) -> P; - fn pat_struct(&self, span: Span, - path: ast::Path, field_pats: Vec> ) -> P; + fn pat_path(&self, span: Span, path: ast::Path) -> P; + fn pat_tuple_struct(&self, span: Span, path: ast::Path, + subpats: Vec>) -> P; + fn pat_struct(&self, span: Span, path: ast::Path, + field_pats: Vec>) -> P; fn pat_tuple(&self, span: Span, pats: Vec>) -> P; fn pat_some(&self, span: Span, pat: P) -> P; @@ -802,10 +804,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let binding_expr = self.expr_ident(sp, binding_variable); // Ok(__try_var) pattern - let ok_pat = self.pat_enum(sp, ok_path, vec!(binding_pat.clone())); + let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]); // Err(__try_var) (pattern and expression resp.) - let err_pat = self.pat_enum(sp, err_path.clone(), vec!(binding_pat)); + let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]); let err_inner_expr = self.expr_call(sp, self.expr_path(err_path), vec!(binding_expr.clone())); // return Err(__try_var) @@ -842,18 +844,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let pat = PatKind::Ident(bm, Spanned{span: span, node: ident}, None); self.pat(span, pat) } - fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec>) -> P { - let pat = if subpats.is_empty() { - PatKind::Struct(path, Vec::new(), false) - } else { - PatKind::TupleStruct(path, subpats, None) - }; - self.pat(span, pat) + fn pat_path(&self, span: Span, path: ast::Path) -> P { + self.pat(span, PatKind::Path(None, path)) } - fn pat_struct(&self, span: Span, - path: ast::Path, field_pats: Vec>) -> P { - let pat = PatKind::Struct(path, field_pats, false); - self.pat(span, pat) + fn pat_tuple_struct(&self, span: Span, path: ast::Path, + subpats: Vec>) -> P { + self.pat(span, PatKind::TupleStruct(path, subpats, None)) + } + fn pat_struct(&self, span: Span, path: ast::Path, + field_pats: Vec>) -> P { + self.pat(span, PatKind::Struct(path, field_pats, false)) } fn pat_tuple(&self, span: Span, pats: Vec>) -> P { self.pat(span, PatKind::Tuple(pats, None)) @@ -862,25 +862,25 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_some(&self, span: Span, pat: P) -> P { let some = self.std_path(&["option", "Option", "Some"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!(pat)) + self.pat_tuple_struct(span, path, vec![pat]) } fn pat_none(&self, span: Span) -> P { let some = self.std_path(&["option", "Option", "None"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!()) + self.pat_path(span, path) } fn pat_ok(&self, span: Span, pat: P) -> P { let some = self.std_path(&["result", "Result", "Ok"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!(pat)) + self.pat_tuple_struct(span, path, vec![pat]) } fn pat_err(&self, span: Span, pat: P) -> P { let some = self.std_path(&["result", "Result", "Err"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!(pat)) + self.pat_tuple_struct(span, path, vec![pat]) } fn arm(&self, _span: Span, pats: Vec>, expr: P) -> ast::Arm { diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 8ae77e79310b2..31194b04fa6e4 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -104,7 +104,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { }; let eq_arm = cx.arm(span, - vec![cx.pat_enum(span, equals_path.clone(), vec![])], + vec![cx.pat_path(span, equals_path.clone())], old); let neq_arm = cx.arm(span, vec![cx.pat_ident(span, test_id)], diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 10a9738742e44..9e9b2f020622f 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -165,7 +165,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< }; let eq_arm = cx.arm(span, - vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))], + vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))], old); let neq_arm = cx.arm(span, vec![cx.pat_ident(span, test_id)], diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 22e98fb213f95..b2b887c7ef2d4 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1510,26 +1510,32 @@ impl<'a> TraitDef<'a> { } let subpats = self.create_subpatterns(cx, paths, mutbl); - let pattern = if struct_def.is_struct() { - let field_pats = subpats.into_iter() - .zip(&ident_exprs) - .map(|(pat, &(sp, ident, _, _))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } - codemap::Spanned { - span: pat.span, - node: ast::FieldPat { - ident: ident.unwrap(), - pat: pat, - is_shorthand: false, - }, - } - }) - .collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } else { - cx.pat_enum(self.span, struct_path, subpats) + let pattern = match *struct_def { + VariantData::Struct(..) => { + let field_pats = subpats.into_iter() + .zip(&ident_exprs) + .map(|(pat, &(sp, ident, _, _))| { + if ident.is_none() { + cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); + } + codemap::Spanned { + span: pat.span, + node: ast::FieldPat { + ident: ident.unwrap(), + pat: pat, + is_shorthand: false, + }, + } + }) + .collect(); + cx.pat_struct(self.span, struct_path, field_pats) + } + VariantData::Tuple(..) => { + cx.pat_tuple_struct(self.span, struct_path, subpats) + } + VariantData::Unit(..) => { + cx.pat_path(self.span, struct_path) + } }; (pattern, ident_exprs) From 31d56cb144ead0811935a09d32d7b2febc5b42de Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 17 Aug 2016 04:05:04 -0700 Subject: [PATCH 118/768] Add UI test for E0053 --- .../trait-impl-fn-incompatibility.rs | 27 +++++++++++++++++++ .../trait-impl-fn-incompatibility.stderr | 23 ++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs create mode 100644 src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs new file mode 100644 index 0000000000000..099c8699e493b --- /dev/null +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs @@ -0,0 +1,27 @@ +// 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. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +trait Foo { + fn foo(x: u16); + fn bar(&mut self, bar: &mut Bar); +} + +struct Bar; + +impl Foo for Bar { + fn foo(x: i16) { } + fn bar(&mut self, bar: &Bar) { } +} + +fn main() { +} + diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr new file mode 100644 index 0000000000000..e5dfdc8e910df --- /dev/null +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -0,0 +1,23 @@ +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/trait-impl-fn-incompatibility.rs:21:15 + | +14 | fn foo(x: u16); + | --- original trait requirement +... +21 | fn foo(x: i16) { } + | ^^^ expected u16, found i16 + +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/trait-impl-fn-incompatibility.rs:22:28 + | +15 | fn bar(&mut self, bar: &mut Bar); + | -------- original trait requirement +... +22 | fn bar(&mut self, bar: &Bar) { } + | ^^^^ values differ in mutability + | + = note: expected type `fn(&mut Bar, &mut Bar)` + = note: found type `fn(&mut Bar, &Bar)` + +error: aborting due to 2 previous errors + From ed54226467f60a6ca15aabe9cc1f58763503a817 Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Thu, 18 Aug 2016 00:43:18 +0200 Subject: [PATCH 119/768] Fix tidy check. --- src/test/compile-fail/E0221.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs index c67bfb822c068..651054580408d 100644 --- a/src/test/compile-fail/E0221.rs +++ b/src/test/compile-fail/E0221.rs @@ -18,7 +18,7 @@ trait Foo { trait Bar : Foo { type A: T2; fn do_something() { - let _: Self::A; + let _: Self::A; //~^ ERROR E0221 //~| NOTE ambiguous associated type `A` //~| NOTE associated type `Self` could derive from `Foo` From 864b3efd3302c9447f4d689779efda4a7b52c294 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 17 Aug 2016 15:53:10 -0700 Subject: [PATCH 120/768] Fix tidy and nits --- src/librustc_borrowck/borrowck/mod.rs | 16 +++++++++------- .../region-borrow-params-issue-29793-small.rs | 8 ++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 7e3466c1ad84a..fd5db97b5d8bc 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -43,7 +43,7 @@ use std::mem; use std::rc::Rc; use syntax::ast; use syntax::attr::AttrMetaMethods; -use syntax_pos::{MultiSpan, Span, BytePos}; +use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; @@ -963,14 +963,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .emit(); } - fn convert_region_to_span(&self, region: ty::Region) -> Option { + fn region_end_span(&self, region: ty::Region) -> Option { match region { ty::ReScope(scope) => { match scope.span(&self.tcx.region_maps, &self.tcx.map) { Some(s) => { - let mut last_span = s; - last_span.lo = BytePos(last_span.hi.0 - 1); - Some(last_span) + Some(s.end_point()) } None => { None @@ -1024,6 +1022,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { err_out_of_scope(super_scope, sub_scope, cause) => { match cause { euv::ClosureCapture(s) => { + // The primary span starts out as the closure creation point. + // Change the primary span here to highlight the use of the variable + // in the closure, because it seems more natural. Highlight + // closure creation point as a secondary span. match db.span.primary_span() { Some(primary) => { db.span = MultiSpan::from_span(s); @@ -1038,8 +1040,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - let sub_span = self.convert_region_to_span(sub_scope); - let super_span = self.convert_region_to_span(super_scope); + let sub_span = self.region_end_span(sub_scope); + let super_span = self.region_end_span(super_scope); match (sub_span, super_span) { (Some(s1), Some(s2)) if s1 == s2 => { diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs index 196c233a0b5c3..18206a68515fe 100644 --- a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs +++ b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs @@ -27,8 +27,8 @@ fn escaping_borrow_of_closure_params_1() { //~| NOTE values in a scope are dropped in the opposite order they are created return f; }; - //~^ NOTE borrowed value dropped before borrower - //~| NOTE borrowed value dropped before borrower + //~^ NOTE borrowed value dropped before borrower + //~| NOTE borrowed value dropped before borrower // We delberately do not call `g`; this small version of the test, // after adding such a call, was (properly) rejected even when the @@ -50,8 +50,8 @@ fn escaping_borrow_of_closure_params_2() { //~| NOTE values in a scope are dropped in the opposite order they are created f }; - //~^ NOTE borrowed value dropped before borrower - //~| NOTE borrowed value dropped before borrower + //~^ NOTE borrowed value dropped before borrower + //~| NOTE borrowed value dropped before borrower // (we don't call `g`; see above) } From dcee93a8030c3a62c5a05b45b050f90251d93af8 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Tue, 16 Aug 2016 04:11:48 -0400 Subject: [PATCH 121/768] replace Add example with something more evocative of addition Currently most of the operator traits use trivial implementation examples that only perform side effects. Honestly, that might not be too bad for the sake of documentation; but anyway, here's a proposal to move a slightly modified version of the module-level point-addition example into the `Add` documentation, since it's more evocative of addition semantics. Part of #29365 wrap identifiers in backticks minor rephrasing fix module-level documentation to be more truthful This branch changes the example for `Add` to no longer be a "minimum implementation that prints something to the screen". --- src/libcore/ops.rs | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..9e6310ed460d2 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -62,8 +62,7 @@ //! } //! ``` //! -//! See the documentation for each trait for a minimum implementation that -//! prints something to the screen. +//! See the documentation for each trait for an example implementation. #![stable(feature = "rust1", since = "1.0.0")] @@ -166,25 +165,38 @@ macro_rules! forward_ref_binop { /// /// # Examples /// -/// A trivial implementation of `Add`. When `Foo + Foo` happens, it ends up -/// calling `add`, and therefore, `main` prints `Adding!`. +/// This example creates a `Point` struct that implements the `Add` trait, and +/// then demonstrates adding two `Point`s. /// /// ``` /// use std::ops::Add; /// -/// struct Foo; +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } /// -/// impl Add for Foo { -/// type Output = Foo; +/// impl Add for Point { +/// type Output = Point; /// -/// fn add(self, _rhs: Foo) -> Foo { -/// println!("Adding!"); -/// self +/// fn add(self, other: Point) -> Point { +/// Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// } +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y /// } /// } /// /// fn main() { -/// Foo + Foo; +/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, +/// Point { x: 3, y: 3 }); /// } /// ``` #[lang = "add"] From d107d2259098a2d683bb7c92876ec0abdf4716ca Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 17 Aug 2016 00:22:03 +0000 Subject: [PATCH 122/768] Refactor `module.add_import_directive()` -> `resolver.add_import_directive()`. --- src/librustc_resolve/build_reduced_graph.rs | 6 +++--- src/librustc_resolve/resolve_imports.rs | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 116c1b7a6d06f..ea946d0117b66 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -130,7 +130,7 @@ impl<'b> Resolver<'b> { let subclass = ImportDirectiveSubclass::single(binding.name, source_name); let span = view_path.span; - parent.add_import_directive(module_path, subclass, span, item.id, vis); + self.add_import_directive(module_path, subclass, span, item.id, vis); self.unresolved_imports += 1; } ViewPathList(_, ref source_items) => { @@ -176,14 +176,14 @@ impl<'b> Resolver<'b> { }; let subclass = ImportDirectiveSubclass::single(rename, name); let (span, id) = (source_item.span, source_item.node.id()); - parent.add_import_directive(module_path, subclass, span, id, vis); + self.add_import_directive(module_path, subclass, span, id, vis); self.unresolved_imports += 1; } } ViewPathGlob(_) => { let subclass = GlobImport { is_prelude: is_prelude }; let span = view_path.span; - parent.add_import_directive(module_path, subclass, span, item.id, vis); + self.add_import_directive(module_path, subclass, span, item.id, vis); self.unresolved_imports += 1; } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e08a30e40d354..a0539206fa42f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -212,8 +212,11 @@ impl<'a> ::ModuleS<'a> { Failed(None) } +} - pub fn add_import_directive(&self, +impl<'a> Resolver<'a> { + // Add an import directive to the current module. + pub fn add_import_directive(&mut self, module_path: Vec, subclass: ImportDirectiveSubclass, span: Span, @@ -228,23 +231,21 @@ impl<'a> ::ModuleS<'a> { vis: vis, }); - self.unresolved_imports.borrow_mut().push(directive); + self.current_module.unresolved_imports.borrow_mut().push(directive); match directive.subclass { SingleImport { target, .. } => { for &ns in &[ValueNS, TypeNS] { - self.resolution(target, ns).borrow_mut().single_imports - .add_directive(directive); + let mut resolution = self.current_module.resolution(target, ns).borrow_mut(); + resolution.single_imports.add_directive(directive); } } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. GlobImport { is_prelude: true } => {} - GlobImport { .. } => self.globs.borrow_mut().push(directive), + GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive), } } -} -impl<'a> Resolver<'a> { // Given a binding and an import directive that resolves to it, // return the corresponding binding defined by the import directive. fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) From c64cd86be866242a88bb1c103dfddf407ebdadde Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 17 Aug 2016 00:42:14 +0000 Subject: [PATCH 123/768] Add field `parent` to `ImportDirective`. --- src/librustc_resolve/lib.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d90a932a63d86..742d955e38a2b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -756,7 +756,7 @@ pub struct ModuleS<'a> { no_implicit_prelude: Cell, - glob_importers: RefCell, &'a ImportDirective<'a>)>>, + glob_importers: RefCell>>, globs: RefCell>>, // Used to memoize the traits in this module for faster searches through all traits in scope. diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a0539206fa42f..83b1f64a33a9a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -63,6 +63,7 @@ impl ImportDirectiveSubclass { #[derive(Debug,Clone)] pub struct ImportDirective<'a> { pub id: NodeId, + parent: Module<'a>, module_path: Vec, target_module: Cell>>, // the resolution of `module_path` subclass: ImportDirectiveSubclass, @@ -223,6 +224,7 @@ impl<'a> Resolver<'a> { id: NodeId, vis: ty::Visibility) { let directive = self.arenas.alloc_import_directive(ImportDirective { + parent: self.current_module, module_path: module_path, target_module: Cell::new(None), subclass: subclass, @@ -306,9 +308,9 @@ impl<'a> Resolver<'a> { // Define `new_binding` in `module`s glob importers. if new_binding.is_importable() && new_binding.is_pseudo_public() { - for &(importer, directive) in module.glob_importers.borrow_mut().iter() { + for directive in module.glob_importers.borrow_mut().iter() { let imported_binding = self.import(new_binding, directive); - let _ = self.try_define(importer, name, ns, imported_binding); + let _ = self.try_define(directive.parent, name, ns, imported_binding); } } @@ -317,8 +319,6 @@ impl<'a> Resolver<'a> { } struct ImportResolvingError<'a> { - /// Module where the error happened - source_module: Module<'a>, import_directive: &'a ImportDirective<'a>, span: Span, help: String, @@ -402,9 +402,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // Define a "dummy" resolution containing a Def::Err as a placeholder for a // failed resolution - fn import_dummy_binding(&mut self, - source_module: Module<'b>, - directive: &'b ImportDirective<'b>) { + fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) { if let SingleImport { target, .. } = directive.subclass { let dummy_binding = self.arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Def(Def::Err), @@ -413,8 +411,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }); let dummy_binding = self.import(dummy_binding, directive); - let _ = self.try_define(source_module, target, ValueNS, dummy_binding.clone()); - let _ = self.try_define(source_module, target, TypeNS, dummy_binding); + let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone()); + let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding); } } @@ -423,7 +421,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { fn import_resolving_error(&mut self, e: ImportResolvingError<'b>) { // If the error is a single failed import then create a "fake" import // resolution for it so that later resolve stages won't complain. - self.import_dummy_binding(e.source_module, e.import_directive); + self.import_dummy_binding(e.import_directive); let path = import_path_to_string(&e.import_directive.module_path, &e.import_directive.subclass); resolve_error(self.resolver, @@ -445,7 +443,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { None => (import_directive.span, String::new()), }; errors.push(ImportResolvingError { - source_module: self.current_module, import_directive: import_directive, span: span, help: help, @@ -511,7 +508,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { .emit(); // Do not import this illegal binding. Import a dummy binding and pretend // everything is fine - self.import_dummy_binding(module, directive); + self.import_dummy_binding(directive); return Success(()); } Success(binding) if !self.is_accessible(binding.vis) => {} @@ -635,7 +632,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } // Add to target_module's glob_importers - target_module.glob_importers.borrow_mut().push((module, directive)); + target_module.glob_importers.borrow_mut().push(directive); // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. From 37154ca95d801c83974e23b913154da402ae5d79 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 17 Aug 2016 00:52:18 +0000 Subject: [PATCH 124/768] Refactor `unresolved_imports` -> `indeterminate_imports`. --- src/librustc_resolve/build_reduced_graph.rs | 3 - src/librustc_resolve/lib.rs | 8 +- src/librustc_resolve/resolve_imports.rs | 113 ++++++++------------ 3 files changed, 47 insertions(+), 77 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index ea946d0117b66..2dac64ad2bba9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -131,7 +131,6 @@ impl<'b> Resolver<'b> { let subclass = ImportDirectiveSubclass::single(binding.name, source_name); let span = view_path.span; self.add_import_directive(module_path, subclass, span, item.id, vis); - self.unresolved_imports += 1; } ViewPathList(_, ref source_items) => { // Make sure there's at most one `mod` import in the list. @@ -177,14 +176,12 @@ impl<'b> Resolver<'b> { let subclass = ImportDirectiveSubclass::single(rename, name); let (span, id) = (source_item.span, source_item.node.id()); self.add_import_directive(module_path, subclass, span, id, vis); - self.unresolved_imports += 1; } } ViewPathGlob(_) => { let subclass = GlobImport { is_prelude: is_prelude }; let span = view_path.span; self.add_import_directive(module_path, subclass, span, item.id, vis); - self.unresolved_imports += 1; } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 742d955e38a2b..1660a270cbd4f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -752,7 +752,6 @@ pub struct ModuleS<'a> { extern_crate_id: Option, resolutions: RefCell>>>, - unresolved_imports: RefCell>>, no_implicit_prelude: Cell, @@ -782,7 +781,6 @@ impl<'a> ModuleS<'a> { def: def, extern_crate_id: None, resolutions: RefCell::new(HashMap::new()), - unresolved_imports: RefCell::new(Vec::new()), no_implicit_prelude: Cell::new(false), glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), @@ -965,8 +963,8 @@ pub struct Resolver<'a> { structs: FnvHashMap>, - // The number of imports that are currently unresolved. - unresolved_imports: usize, + // All indeterminate imports (i.e. imports not known to succeed or fail). + indeterminate_imports: Vec<&'a ImportDirective<'a>>, // The module that represents the current item scope. current_module: Module<'a>, @@ -1153,7 +1151,7 @@ impl<'a> Resolver<'a> { trait_item_map: FnvHashMap(), structs: FnvHashMap(), - unresolved_imports: 0, + indeterminate_imports: Vec::new(), current_module: graph_root, value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 83b1f64a33a9a..23a5b3c499011 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -233,7 +233,7 @@ impl<'a> Resolver<'a> { vis: vis, }); - self.current_module.unresolved_imports.borrow_mut().push(directive); + self.indeterminate_imports.push(directive); match directive.subclass { SingleImport { target, .. } => { for &ns in &[ValueNS, TypeNS] { @@ -360,43 +360,52 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { /// point iteration. fn resolve_imports(&mut self) { let mut i = 0; - let mut prev_unresolved_imports = 0; + let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; let mut errors = Vec::new(); - loop { - debug!("(resolving imports) iteration {}, {} imports left", i, self.unresolved_imports); - - // Attempt to resolve imports in all local modules. - for module in self.arenas.local_modules().iter() { - self.current_module = module; - self.resolve_imports_in_current_module(&mut errors); - } - - if self.unresolved_imports == 0 { - debug!("(resolving imports) success"); - for module in self.arenas.local_modules().iter() { - self.finalize_resolutions_in(module, false); + while self.indeterminate_imports.len() < prev_num_indeterminates { + prev_num_indeterminates = self.indeterminate_imports.len(); + debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates); + + let mut imports = Vec::new(); + ::std::mem::swap(&mut imports, &mut self.indeterminate_imports); + + for import in imports { + match self.resolve_import(&import) { + Failed(err) => { + let (span, help) = match err { + Some((span, msg)) => (span, format!(". {}", msg)), + None => (import.span, String::new()), + }; + errors.push(ImportResolvingError { + import_directive: import, + span: span, + help: help, + }); + } + Indeterminate => self.indeterminate_imports.push(import), + Success(()) => {} } - break; } - if self.unresolved_imports == prev_unresolved_imports { - // resolving failed - // Report unresolved imports only if no hard error was already reported - // to avoid generating multiple errors on the same import. - // Imports that are still indeterminate at this point are actually blocked - // by errored imports, so there is no point reporting them. - for module in self.arenas.local_modules().iter() { - self.finalize_resolutions_in(module, errors.len() == 0); - } - for e in errors { - self.import_resolving_error(e) - } - break; + i += 1; + } + + for module in self.arenas.local_modules().iter() { + self.finalize_resolutions_in(module); + } + + // Report unresolved imports only if no hard error was already reported + // to avoid generating multiple errors on the same import. + if errors.len() == 0 { + if let Some(import) = self.indeterminate_imports.iter().next() { + let error = ResolutionError::UnresolvedImport(None); + resolve_error(self.resolver, import.span, error); } + } - i += 1; - prev_unresolved_imports = self.unresolved_imports; + for e in errors { + self.import_resolving_error(e) } } @@ -429,35 +438,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { ResolutionError::UnresolvedImport(Some((&path, &e.help)))); } - /// Attempts to resolve imports for the given module only. - fn resolve_imports_in_current_module(&mut self, errors: &mut Vec>) { - let mut imports = Vec::new(); - let mut unresolved_imports = self.current_module.unresolved_imports.borrow_mut(); - ::std::mem::swap(&mut imports, &mut unresolved_imports); - - for import_directive in imports { - match self.resolve_import(&import_directive) { - Failed(err) => { - let (span, help) = match err { - Some((span, msg)) => (span, format!(". {}", msg)), - None => (import_directive.span, String::new()), - }; - errors.push(ImportResolvingError { - import_directive: import_directive, - span: span, - help: help, - }); - } - Indeterminate => unresolved_imports.push(import_directive), - Success(()) => { - // Decrement the count of unresolved imports. - assert!(self.unresolved_imports >= 1); - self.unresolved_imports -= 1; - } - } - } - } - /// Attempts to resolve the given import. The return value indicates /// failure if we're certain the name does not exist, indeterminate if we /// don't know whether the name exists at the moment due to other @@ -468,6 +448,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { names_to_string(&directive.module_path), module_to_string(self.current_module)); + let module = directive.parent; + self.current_module = module; + let target_module = match directive.target_module.get() { Some(module) => module, _ => match self.resolve_module_path(&directive.module_path, @@ -490,7 +473,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let value_result = self.resolve_name_in_module(target_module, source, ValueNS, false, true); let type_result = self.resolve_name_in_module(target_module, source, TypeNS, false, true); - let module = self.current_module; let mut privacy_error = true; for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined), (TypeNS, &type_result, type_determined)] { @@ -658,7 +640,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // Miscellaneous post-processing, including recording reexports, reporting conflicts, // reporting the PRIVATE_IN_PUBLIC lint, and reporting unresolved imports. - fn finalize_resolutions_in(&mut self, module: Module<'b>, report_unresolved_imports: bool) { + fn finalize_resolutions_in(&mut self, module: Module<'b>) { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut() = Vec::new(); @@ -706,13 +688,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.export_map.insert(node_id, reexports); } } - - if report_unresolved_imports { - for import in module.unresolved_imports.borrow().iter() { - resolve_error(self.resolver, import.span, ResolutionError::UnresolvedImport(None)); - break; - } - } } } From c1362d8cc53176e0bf0db73fefc98ca9b9035457 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 15 Aug 2016 01:08:31 +0000 Subject: [PATCH 125/768] Clean up `build_reduced_graph.rs`. --- src/librustc_resolve/build_reduced_graph.rs | 44 +++++++++------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 2dac64ad2bba9..3b3058c6da7be 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -56,12 +56,7 @@ impl<'b> Resolver<'b> { pub fn build_reduced_graph(&mut self, krate: &Crate) { let no_implicit_prelude = attr::contains_name(&krate.attrs, "no_implicit_prelude"); self.graph_root.no_implicit_prelude.set(no_implicit_prelude); - - let mut visitor = BuildReducedGraphVisitor { - parent: self.graph_root, - resolver: self, - }; - visit::walk_crate(&mut visitor, krate); + visit::walk_crate(&mut BuildReducedGraphVisitor { resolver: self }, krate); } /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; @@ -84,11 +79,10 @@ impl<'b> Resolver<'b> { } /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) { - let parent = *parent_ref; + fn build_reduced_graph_for_item(&mut self, item: &Item) { + let parent = self.current_module; let name = item.ident.name; let sp = item.span; - self.current_module = parent; let vis = self.resolve_visibility(&item.vis); match item.node { @@ -213,7 +207,7 @@ impl<'b> Resolver<'b> { }); self.define(parent, name, TypeNS, (module, sp, vis)); self.module_map.insert(item.id, module); - *parent_ref = module; + self.current_module = module; // Descend into the module. } ItemKind::ForeignMod(..) => {} @@ -306,6 +300,9 @@ impl<'b> Resolver<'b> { } ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), } + + visit::walk_item(&mut BuildReducedGraphVisitor { resolver: self }, item); + self.current_module = parent; } // Constructs the reduced graph for one variant. Variants exist in the @@ -330,9 +327,8 @@ impl<'b> Resolver<'b> { } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, - foreign_item: &ForeignItem, - parent: Module<'b>) { + fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem) { + let parent = self.current_module; let name = foreign_item.ident.name; let def = match foreign_item.node { @@ -343,12 +339,12 @@ impl<'b> Resolver<'b> { Def::Static(self.definitions.local_def_id(foreign_item.id), m) } }; - self.current_module = parent; let vis = self.resolve_visibility(&foreign_item.vis); self.define(parent, name, ValueNS, (def, foreign_item.span, vis)); } - fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &mut Module<'b>) { + fn build_reduced_graph_for_block(&mut self, block: &Block) { + let parent = self.current_module; if self.block_needs_anonymous_module(block) { let block_id = block.id; @@ -359,8 +355,11 @@ impl<'b> Resolver<'b> { let parent_link = BlockParentLink(parent, block_id); let new_module = self.new_module(parent_link, None, false); self.module_map.insert(block_id, new_module); - *parent = new_module; + self.current_module = new_module; // Descend into the block. } + + visit::walk_block(&mut BuildReducedGraphVisitor { resolver: self }, block); + self.current_module = parent; } /// Builds the reduced graph for a single item in an external crate. @@ -484,25 +483,18 @@ impl<'b> Resolver<'b> { struct BuildReducedGraphVisitor<'a, 'b: 'a> { resolver: &'a mut Resolver<'b>, - parent: Module<'b>, } impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { fn visit_item(&mut self, item: &Item) { - let old_parent = self.parent; - self.resolver.build_reduced_graph_for_item(item, &mut self.parent); - visit::walk_item(self, item); - self.parent = old_parent; + self.resolver.build_reduced_graph_for_item(item); } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { - self.resolver.build_reduced_graph_for_foreign_item(foreign_item, &self.parent); + self.resolver.build_reduced_graph_for_foreign_item(foreign_item); } fn visit_block(&mut self, block: &Block) { - let old_parent = self.parent; - self.resolver.build_reduced_graph_for_block(block, &mut self.parent); - visit::walk_block(self, block); - self.parent = old_parent; + self.resolver.build_reduced_graph_for_block(block); } } From 89de52eff08d7416b9fd4ab0adc2e818590e84d0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 14 Aug 2016 23:42:05 +0000 Subject: [PATCH 126/768] Add field `current_vis` to `Resolver`. --- src/librustc_resolve/build_reduced_graph.rs | 7 ++++++- src/librustc_resolve/lib.rs | 23 ++++++++++----------- src/librustc_resolve/resolve_imports.rs | 10 ++++++++- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3b3058c6da7be..579853446525e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -81,6 +81,7 @@ impl<'b> Resolver<'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item) { let parent = self.current_module; + let parent_vis = self.current_vis; let name = item.ident.name; let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -207,7 +208,10 @@ impl<'b> Resolver<'b> { }); self.define(parent, name, TypeNS, (module, sp, vis)); self.module_map.insert(item.id, module); - self.current_module = module; // Descend into the module. + + // Descend into the module. + self.current_module = module; + self.current_vis = ty::Visibility::Restricted(item.id); } ItemKind::ForeignMod(..) => {} @@ -303,6 +307,7 @@ impl<'b> Resolver<'b> { visit::walk_item(&mut BuildReducedGraphVisitor { resolver: self }, item); self.current_module = parent; + self.current_vis = parent_vis; } // Constructs the reduced graph for one variant. Variants exist in the diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1660a270cbd4f..08cfc662e9bea 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -969,6 +969,10 @@ pub struct Resolver<'a> { // The module that represents the current item scope. current_module: Module<'a>, + // The visibility of `pub(self)` items in the current scope. + // Equivalently, the visibility required for an item to be accessible from the current scope. + current_vis: ty::Visibility, + // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. value_ribs: Vec>, @@ -1154,6 +1158,7 @@ impl<'a> Resolver<'a> { indeterminate_imports: Vec::new(), current_module: graph_root, + current_vis: ty::Visibility::Restricted(ast::CRATE_NODE_ID), value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], type_ribs: vec![Rib::new(ModuleRibKind(graph_root))], label_ribs: Vec::new(), @@ -1197,6 +1202,7 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { self.current_module = self.graph_root; + self.current_vis = ty::Visibility::Restricted(ast::CRATE_NODE_ID); visit::walk_crate(self, krate); check_unused::check_crate(self, krate); @@ -1562,13 +1568,15 @@ impl<'a> Resolver<'a> { let module = self.module_map.get(&id).cloned(); // clones a reference if let Some(module) = module { // Move down in the graph. - let orig_module = ::std::mem::replace(&mut self.current_module, module); + let orig_module = replace(&mut self.current_module, module); + let orig_vis = replace(&mut self.current_vis, ty::Visibility::Restricted(id)); self.value_ribs.push(Rib::new(ModuleRibKind(module))); self.type_ribs.push(Rib::new(ModuleRibKind(module))); f(self); self.current_module = orig_module; + self.current_vis = orig_vis; self.value_ribs.pop(); self.type_ribs.pop(); } else { @@ -2706,7 +2714,6 @@ impl<'a> Resolver<'a> { fn with_empty_ribs(&mut self, f: F) -> T where F: FnOnce(&mut Resolver<'a>) -> T, { - use ::std::mem::replace; let value_ribs = replace(&mut self.value_ribs, Vec::new()); let type_ribs = replace(&mut self.type_ribs, Vec::new()); let label_ribs = replace(&mut self.label_ribs, Vec::new()); @@ -3264,13 +3271,7 @@ impl<'a> Resolver<'a> { ast::Visibility::Public => return ty::Visibility::Public, ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID), ast::Visibility::Restricted { ref path, id } => (path, id), - ast::Visibility::Inherited => { - let current_module = - self.get_nearest_normal_module_parent_or_self(self.current_module); - let id = - self.definitions.as_local_node_id(current_module.def_id().unwrap()).unwrap(); - return ty::Visibility::Restricted(id); - } + ast::Visibility::Inherited => return self.current_vis, }; let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect(); @@ -3299,9 +3300,7 @@ impl<'a> Resolver<'a> { } fn is_accessible(&self, vis: ty::Visibility) -> bool { - let current_module = self.get_nearest_normal_module_parent_or_self(self.current_module); - let node_id = self.definitions.as_local_node_id(current_module.def_id().unwrap()).unwrap(); - vis.is_accessible_from(node_id, self) + vis.is_at_least(self.current_vis, self) } fn check_privacy(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 23a5b3c499011..17933abec27b0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -356,6 +356,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // remain or unsuccessfully when no forward progress in resolving imports // is made. + fn set_current_module(&mut self, module: Module<'b>) { + self.current_module = module; + self.current_vis = ty::Visibility::Restricted({ + let normal_module = self.get_nearest_normal_module_parent_or_self(module); + self.definitions.as_local_node_id(normal_module.def_id().unwrap()).unwrap() + }); + } + /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. fn resolve_imports(&mut self) { @@ -449,7 +457,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { module_to_string(self.current_module)); let module = directive.parent; - self.current_module = module; + self.set_current_module(module); let target_module = match directive.target_module.get() { Some(module) => module, From bfc98f59a48d7c8a65cd1a15656bb6165fb3589f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 1 Aug 2016 20:43:48 +0000 Subject: [PATCH 127/768] Refactor away `module.resolve_name()`. --- src/librustc_resolve/lib.rs | 37 ++------ src/librustc_resolve/resolve_imports.rs | 115 ++++++++++++++---------- 2 files changed, 75 insertions(+), 77 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 08cfc662e9bea..71dee48f3396d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1250,12 +1250,13 @@ impl<'a> Resolver<'a> { index: usize, span: Span) -> ResolveResult> { - fn search_parent_externals(needle: Name, module: Module) -> Option { - match module.resolve_name(needle, TypeNS, false) { + fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>) + -> Option> { + match this.resolve_name_in_module(module, needle, TypeNS, false, false) { Success(binding) if binding.is_extern_crate() => Some(module), _ => match module.parent_link { ModuleParentLink(ref parent, _) => { - search_parent_externals(needle, parent) + search_parent_externals(this, needle, parent) } _ => None, }, @@ -1275,11 +1276,12 @@ impl<'a> Resolver<'a> { let segment_name = name.as_str(); let module_name = module_to_string(search_module); let msg = if "???" == &module_name { - match search_parent_externals(name, &self.current_module) { + let current_module = self.current_module; + match search_parent_externals(self, name, current_module) { Some(module) => { let path_str = names_to_string(module_path); let target_mod_str = module_to_string(&module); - let current_mod_str = module_to_string(&self.current_module); + let current_mod_str = module_to_string(current_module); let prefix = if target_mod_str == current_mod_str { "self::".to_string() @@ -1436,8 +1438,8 @@ impl<'a> Resolver<'a> { if module.def.is_some() { return match self.prelude { Some(prelude) if !module.no_implicit_prelude.get() => { - prelude.resolve_name(name, ns, false).success() - .map(LexicalScopeBinding::Item) + self.resolve_name_in_module(prelude, name, ns, false, false).success() + .map(LexicalScopeBinding::Item) } _ => None, }; @@ -1523,27 +1525,6 @@ impl<'a> Resolver<'a> { return Success(PrefixFound(containing_module, i)); } - /// Attempts to resolve the supplied name in the given module for the - /// given namespace. If successful, returns the binding corresponding to - /// the name. - fn resolve_name_in_module(&mut self, - module: Module<'a>, - name: Name, - namespace: Namespace, - use_lexical_scope: bool, - record_used: bool) - -> ResolveResult<&'a NameBinding<'a>> { - debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module)); - - self.populate_module_if_necessary(module); - module.resolve_name(name, namespace, use_lexical_scope).and_then(|binding| { - if record_used { - self.record_use(name, namespace, binding); - } - Success(binding) - }) - } - // AST resolution // // We maintain a list of value ribs and type ribs. diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 17933abec27b0..0905632d4e627 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -133,19 +133,77 @@ impl<'a> NameResolution<'a> { _ => None, // The binding could be shadowed by a single import, so it is not known. }) } +} + +impl<'a> ::ModuleS<'a> { + fn resolution(&self, name: Name, ns: Namespace) -> &'a RefCell> { + *self.resolutions.borrow_mut().entry((name, ns)) + .or_insert_with(|| self.arenas.alloc_name_resolution()) + } +} + +impl<'a> Resolver<'a> { + /// Attempts to resolve the supplied name in the given module for the given namespace. + /// If successful, returns the binding corresponding to the name. + pub fn resolve_name_in_module(&mut self, + module: Module<'a>, + name: Name, + ns: Namespace, + allow_private_imports: bool, + record_used: bool) + -> ResolveResult<&'a NameBinding<'a>> { + self.populate_module_if_necessary(module); + + let resolution = module.resolution(name, ns); + let resolution = match resolution.borrow_state() { + ::std::cell::BorrowState::Unused => resolution.borrow_mut(), + _ => return Failed(None), // This happens when there is a cycle of imports + }; + + if let Some(result) = self.try_result(&resolution, ns, allow_private_imports) { + // If the resolution doesn't depend on glob definability, check privacy and return. + return result.and_then(|binding| { + if !allow_private_imports && binding.is_import() && !binding.is_pseudo_public() { + return Failed(None); + } + if record_used { + self.record_use(name, ns, binding); + } + Success(binding) + }); + } + + // Check if the globs are determined + for directive in module.globs.borrow().iter() { + if !allow_private_imports && directive.vis != ty::Visibility::Public { continue } + if let Some(target_module) = directive.target_module.get() { + let result = self.resolve_name_in_module(target_module, name, ns, false, false); + if let Indeterminate = result { + return Indeterminate; + } + } else { + return Indeterminate; + } + } + + Failed(None) + } // Returns Some(the resolution of the name), or None if the resolution depends // on whether more globs can define the name. - fn try_result(&self, ns: Namespace, allow_private_imports: bool) + fn try_result(&mut self, + resolution: &NameResolution<'a>, + ns: Namespace, + allow_private_imports: bool) -> Option>> { - match self.binding { + match resolution.binding { Some(binding) if !binding.is_glob_import() => - return Some(Success(binding)), - _ => {} // Items and single imports are not shadowable + return Some(Success(binding)), // Items and single imports are not shadowable. + _ => {} }; // Check if a single import can still define the name. - match self.single_imports { + match resolution.single_imports { SingleImports::None => {}, SingleImports::AtLeastOne => return Some(Indeterminate), SingleImports::MaybeOne(directive) => { @@ -153,7 +211,7 @@ impl<'a> NameResolution<'a> { // the name, and (3) no public glob has defined the name, the resolution depends // on whether more globs can define the name. if !allow_private_imports && directive.vis != ty::Visibility::Public && - !self.binding.map(NameBinding::is_pseudo_public).unwrap_or(false) { + !resolution.binding.map(NameBinding::is_pseudo_public).unwrap_or(false) { return None; } @@ -165,57 +223,16 @@ impl<'a> NameResolution<'a> { SingleImport { source, .. } => source, GlobImport { .. } => unreachable!(), }; - match target_module.resolve_name(name, ns, false) { + match self.resolve_name_in_module(target_module, name, ns, false, false) { Failed(_) => {} _ => return Some(Indeterminate), } } } - self.binding.map(Success) - } -} - -impl<'a> ::ModuleS<'a> { - fn resolution(&self, name: Name, ns: Namespace) -> &'a RefCell> { - *self.resolutions.borrow_mut().entry((name, ns)) - .or_insert_with(|| self.arenas.alloc_name_resolution()) - } - - pub fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool) - -> ResolveResult<&'a NameBinding<'a>> { - let resolution = self.resolution(name, ns); - let resolution = match resolution.borrow_state() { - ::std::cell::BorrowState::Unused => resolution.borrow_mut(), - _ => return Failed(None), // This happens when there is a cycle of imports - }; - - if let Some(result) = resolution.try_result(ns, allow_private_imports) { - // If the resolution doesn't depend on glob definability, check privacy and return. - return result.and_then(|binding| { - let allowed = allow_private_imports || !binding.is_import() || - binding.is_pseudo_public(); - if allowed { Success(binding) } else { Failed(None) } - }); - } - - // Check if the globs are determined - for directive in self.globs.borrow().iter() { - if !allow_private_imports && directive.vis != ty::Visibility::Public { continue } - match directive.target_module.get() { - None => return Indeterminate, - Some(target_module) => match target_module.resolve_name(name, ns, false) { - Indeterminate => return Indeterminate, - _ => {} - } - } - } - - Failed(None) + resolution.binding.map(Success) } -} -impl<'a> Resolver<'a> { // Add an import directive to the current module. pub fn add_import_directive(&mut self, module_path: Vec, From 75c3fd89d47d6da340ef6c1b98e80968d0218337 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 17 Aug 2016 01:33:19 +0000 Subject: [PATCH 128/768] Refactor away the field `arenas` of `ModuleS`. --- src/librustc_resolve/lib.rs | 14 ++++---------- src/librustc_resolve/resolve_imports.rs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 71dee48f3396d..efc0247e6ff09 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -765,17 +765,12 @@ pub struct ModuleS<'a> { // access the children must be preceded with a // `populate_module_if_necessary` call. populated: Cell, - - arenas: &'a ResolverArenas<'a>, } pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { - fn new(parent_link: ParentLink<'a>, - def: Option, - external: bool, - arenas: &'a ResolverArenas<'a>) -> Self { + fn new(parent_link: ParentLink<'a>, def: Option, external: bool) -> Self { ModuleS { parent_link: parent_link, def: def, @@ -786,7 +781,6 @@ impl<'a> ModuleS<'a> { globs: RefCell::new((Vec::new())), traits: RefCell::new(None), populated: Cell::new(!external), - arenas: arenas } } @@ -1136,7 +1130,7 @@ impl<'a> Resolver<'a> { -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); let graph_root = - ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, arenas); + ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false); let graph_root = arenas.alloc_module(graph_root); let mut module_map = NodeMap(); module_map.insert(CRATE_NODE_ID, graph_root); @@ -1211,12 +1205,12 @@ impl<'a> Resolver<'a> { fn new_module(&self, parent_link: ParentLink<'a>, def: Option, external: bool) -> Module<'a> { - self.arenas.alloc_module(ModuleS::new(parent_link, def, external, self.arenas)) + self.arenas.alloc_module(ModuleS::new(parent_link, def, external)) } fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), false, self.arenas); + let mut module = ModuleS::new(parent_link, Some(def), false); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 0905632d4e627..05c4430a68700 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -135,14 +135,13 @@ impl<'a> NameResolution<'a> { } } -impl<'a> ::ModuleS<'a> { - fn resolution(&self, name: Name, ns: Namespace) -> &'a RefCell> { - *self.resolutions.borrow_mut().entry((name, ns)) - .or_insert_with(|| self.arenas.alloc_name_resolution()) +impl<'a> Resolver<'a> { + fn resolution(&self, module: Module<'a>, name: Name, ns: Namespace) + -> &'a RefCell> { + *module.resolutions.borrow_mut().entry((name, ns)) + .or_insert_with(|| self.arenas.alloc_name_resolution()) } -} -impl<'a> Resolver<'a> { /// Attempts to resolve the supplied name in the given module for the given namespace. /// If successful, returns the binding corresponding to the name. pub fn resolve_name_in_module(&mut self, @@ -154,7 +153,7 @@ impl<'a> Resolver<'a> { -> ResolveResult<&'a NameBinding<'a>> { self.populate_module_if_necessary(module); - let resolution = module.resolution(name, ns); + let resolution = self.resolution(module, name, ns); let resolution = match resolution.borrow_state() { ::std::cell::BorrowState::Unused => resolution.borrow_mut(), _ => return Failed(None), // This happens when there is a cycle of imports @@ -240,8 +239,9 @@ impl<'a> Resolver<'a> { span: Span, id: NodeId, vis: ty::Visibility) { + let current_module = self.current_module; let directive = self.arenas.alloc_import_directive(ImportDirective { - parent: self.current_module, + parent: current_module, module_path: module_path, target_module: Cell::new(None), subclass: subclass, @@ -254,7 +254,7 @@ impl<'a> Resolver<'a> { match directive.subclass { SingleImport { target, .. } => { for &ns in &[ValueNS, TypeNS] { - let mut resolution = self.current_module.resolution(target, ns).borrow_mut(); + let mut resolution = self.resolution(current_module, target, ns).borrow_mut(); resolution.single_imports.add_directive(directive); } } @@ -311,7 +311,7 @@ impl<'a> Resolver<'a> { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. let (new_binding, t) = { - let mut resolution = &mut *module.resolution(name, ns).borrow_mut(); + let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut(); let was_known = resolution.binding().is_some(); let t = f(self, resolution); From 05afe15d1f7b29b5f8f006f6e9ec16c8a7cd4a0c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 5 Aug 2016 01:58:59 +0000 Subject: [PATCH 129/768] Refactor `record_used: bool` -> `record_used: Option`. --- src/librustc_resolve/lib.rs | 24 +++++++++++++----------- src/librustc_resolve/resolve_imports.rs | 15 +++++++++------ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index efc0247e6ff09..f200ae2f75873 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1246,7 +1246,7 @@ impl<'a> Resolver<'a> { -> ResolveResult> { fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>) -> Option> { - match this.resolve_name_in_module(module, needle, TypeNS, false, false) { + match this.resolve_name_in_module(module, needle, TypeNS, false, None) { Success(binding) if binding.is_extern_crate() => Some(module), _ => match module.parent_link { ModuleParentLink(ref parent, _) => { @@ -1265,7 +1265,7 @@ impl<'a> Resolver<'a> { // modules as we go. while index < module_path_len { let name = module_path[index]; - match self.resolve_name_in_module(search_module, name, TypeNS, false, true) { + match self.resolve_name_in_module(search_module, name, TypeNS, false, Some(span)) { Failed(None) => { let segment_name = name.as_str(); let module_name = module_to_string(search_module); @@ -1361,7 +1361,7 @@ impl<'a> Resolver<'a> { // first component of the path in the current lexical // scope and then proceed to resolve below that. let ident = ast::Ident::with_empty_ctxt(module_path[0]); - match self.resolve_ident_in_lexical_scope(ident, TypeNS, true) + match self.resolve_ident_in_lexical_scope(ident, TypeNS, Some(span)) .and_then(LexicalScopeBinding::module) { None => return Failed(None), Some(containing_module) => { @@ -1404,7 +1404,7 @@ impl<'a> Resolver<'a> { fn resolve_ident_in_lexical_scope(&mut self, mut ident: ast::Ident, ns: Namespace, - record_used: bool) + record_used: Option) -> Option> { if ns == TypeNS { ident = ast::Ident::with_empty_ctxt(ident.name); @@ -1432,7 +1432,7 @@ impl<'a> Resolver<'a> { if module.def.is_some() { return match self.prelude { Some(prelude) if !module.no_implicit_prelude.get() => { - self.resolve_name_in_module(prelude, name, ns, false, false).success() + self.resolve_name_in_module(prelude, name, ns, false, None).success() .map(LexicalScopeBinding::Item) } _ => None, @@ -2287,7 +2287,7 @@ impl<'a> Resolver<'a> { PatKind::Ident(bmode, ref ident, ref opt_pat) => { // First try to resolve the identifier as some existing // entity, then fall back to a fresh binding. - let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, false) + let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None) .and_then(LexicalScopeBinding::item); let resolution = binding.and_then(NameBinding::def).and_then(|def| { let always_binding = !pat_src.is_refutable() || opt_pat.is_some() || @@ -2454,11 +2454,11 @@ impl<'a> Resolver<'a> { // // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. - let def = resolve_identifier_with_fallback(self, true).ok_or(false); + let def = resolve_identifier_with_fallback(self, Some(span)).ok_or(false); return def.and_then(|def| self.adjust_local_def(def, span).ok_or(true)).map(mk_res); } - let unqualified_def = resolve_identifier_with_fallback(self, false); + let unqualified_def = resolve_identifier_with_fallback(self, None); let qualified_binding = self.resolve_module_relative_path(span, segments, namespace); match (qualified_binding, unqualified_def) { (Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => { @@ -2478,7 +2478,7 @@ impl<'a> Resolver<'a> { fn resolve_identifier(&mut self, identifier: ast::Ident, namespace: Namespace, - record_used: bool) + record_used: Option) -> Option { if identifier.name == keywords::Invalid.name() { return None; @@ -2613,7 +2613,8 @@ impl<'a> Resolver<'a> { } let name = segments.last().unwrap().identifier.name; - let result = self.resolve_name_in_module(containing_module, name, namespace, false, true); + let result = + self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); result.success().map(|binding| { self.check_privacy(name, binding, span); binding @@ -2657,7 +2658,8 @@ impl<'a> Resolver<'a> { } let name = segments.last().unwrap().name(); - let result = self.resolve_name_in_module(containing_module, name, namespace, false, true); + let result = + self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); result.success().map(|binding| { self.check_privacy(name, binding, span); binding diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 05c4430a68700..28401b2e240f0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -149,7 +149,7 @@ impl<'a> Resolver<'a> { name: Name, ns: Namespace, allow_private_imports: bool, - record_used: bool) + record_used: Option) -> ResolveResult<&'a NameBinding<'a>> { self.populate_module_if_necessary(module); @@ -165,7 +165,7 @@ impl<'a> Resolver<'a> { if !allow_private_imports && binding.is_import() && !binding.is_pseudo_public() { return Failed(None); } - if record_used { + if record_used.is_some() { self.record_use(name, ns, binding); } Success(binding) @@ -176,7 +176,7 @@ impl<'a> Resolver<'a> { for directive in module.globs.borrow().iter() { if !allow_private_imports && directive.vis != ty::Visibility::Public { continue } if let Some(target_module) = directive.target_module.get() { - let result = self.resolve_name_in_module(target_module, name, ns, false, false); + let result = self.resolve_name_in_module(target_module, name, ns, false, None); if let Indeterminate = result { return Indeterminate; } @@ -222,7 +222,7 @@ impl<'a> Resolver<'a> { SingleImport { source, .. } => source, GlobImport { .. } => unreachable!(), }; - match self.resolve_name_in_module(target_module, name, ns, false, false) { + match self.resolve_name_in_module(target_module, name, ns, false, None) { Failed(_) => {} _ => return Some(Indeterminate), } @@ -495,8 +495,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; // We need to resolve both namespaces for this to succeed. - let value_result = self.resolve_name_in_module(target_module, source, ValueNS, false, true); - let type_result = self.resolve_name_in_module(target_module, source, TypeNS, false, true); + let span = directive.span; + let value_result = + self.resolve_name_in_module(target_module, source, ValueNS, false, Some(span)); + let type_result = + self.resolve_name_in_module(target_module, source, TypeNS, false, Some(span)); let mut privacy_error = true; for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined), From 7608bbdea869b061a65c996cac6c15d840436a7c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 15 Aug 2016 20:51:19 +0000 Subject: [PATCH 130/768] Refactor `resolve_module_path` to take an `Option` instead of a `Span`. --- src/librustc_resolve/lib.rs | 36 +++++++++++-------------- src/librustc_resolve/resolve_imports.rs | 2 +- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f200ae2f75873..d514d7e906a8d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1242,7 +1242,7 @@ impl<'a> Resolver<'a> { mut search_module: Module<'a>, module_path: &[Name], index: usize, - span: Span) + span: Option) -> ResolveResult> { fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>) -> Option> { @@ -1265,7 +1265,7 @@ impl<'a> Resolver<'a> { // modules as we go. while index < module_path_len { let name = module_path[index]; - match self.resolve_name_in_module(search_module, name, TypeNS, false, Some(span)) { + match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { Failed(None) => { let segment_name = name.as_str(); let module_name = module_to_string(search_module); @@ -1291,7 +1291,7 @@ impl<'a> Resolver<'a> { format!("Could not find `{}` in `{}`", segment_name, module_name) }; - return Failed(Some((span, msg))); + return Failed(span.map(|span| (span, msg))); } Failed(err) => return Failed(err), Indeterminate => { @@ -1304,11 +1304,13 @@ impl<'a> Resolver<'a> { // Check to see whether there are type bindings, and, if // so, whether there is a module within. if let Some(module_def) = binding.module() { - self.check_privacy(name, binding, span); + if let Some(span) = span { + self.check_privacy(name, binding, span); + } search_module = module_def; } else { let msg = format!("Not a module `{}`", name); - return Failed(Some((span, msg))); + return Failed(span.map(|span| (span, msg))); } } } @@ -1324,7 +1326,7 @@ impl<'a> Resolver<'a> { fn resolve_module_path(&mut self, module_path: &[Name], use_lexical_scope: UseLexicalScopeFlag, - span: Span) + span: Option) -> ResolveResult> { if module_path.len() == 0 { return Success(self.graph_root) // Use the crate root @@ -1361,7 +1363,7 @@ impl<'a> Resolver<'a> { // first component of the path in the current lexical // scope and then proceed to resolve below that. let ident = ast::Ident::with_empty_ctxt(module_path[0]); - match self.resolve_ident_in_lexical_scope(ident, TypeNS, Some(span)) + match self.resolve_ident_in_lexical_scope(ident, TypeNS, span) .and_then(LexicalScopeBinding::module) { None => return Failed(None), Some(containing_module) => { @@ -1378,10 +1380,7 @@ impl<'a> Resolver<'a> { } } - self.resolve_module_path_from_root(search_module, - module_path, - start_index, - span) + self.resolve_module_path_from_root(search_module, module_path, start_index, span) } /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. @@ -1485,7 +1484,7 @@ impl<'a> Resolver<'a> { /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`; /// (b) some chain of `super::`. /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * - fn resolve_module_prefix(&mut self, module_path: &[Name], span: Span) + fn resolve_module_prefix(&mut self, module_path: &[Name], span: Option) -> ResolveResult> { // Start at the current module if we see `self` or `super`, or at the // top of the crate otherwise. @@ -1504,7 +1503,7 @@ impl<'a> Resolver<'a> { match self.get_nearest_normal_module_parent(containing_module) { None => { let msg = "There are too many initial `super`s.".into(); - return Failed(Some((span, msg))); + return Failed(span.map(|span| (span, msg))); } Some(new_module) => { containing_module = new_module; @@ -2592,7 +2591,7 @@ impl<'a> Resolver<'a> { .collect::>(); let containing_module; - match self.resolve_module_path(&module_path, UseLexicalScope, span) { + match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { Failed(err) => { let (span, msg) = match err { Some((span, msg)) => (span, msg), @@ -2632,10 +2631,7 @@ impl<'a> Resolver<'a> { let root_module = self.graph_root; let containing_module; - match self.resolve_module_path_from_root(root_module, - &module_path, - 0, - span) { + match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) { Failed(err) => { let (span, msg) = match err { Some((span, msg)) => (span, msg), @@ -2915,7 +2911,7 @@ impl<'a> Resolver<'a> { match self.resolve_module_path(&name_path[..], UseLexicalScope, - expr.span) { + Some(expr.span)) { Success(e) => { if let Some(def_type) = e.def { def = def_type; @@ -3253,7 +3249,7 @@ impl<'a> Resolver<'a> { let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect(); let mut path_resolution = err_path_resolution(); - let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, path.span) { + let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { Success(module) => { let def = module.def.unwrap(); path_resolution = PathResolution::new(def); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 28401b2e240f0..3c44051503634 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -480,7 +480,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Some(module) => module, _ => match self.resolve_module_path(&directive.module_path, DontUseLexicalScope, - directive.span) { + Some(directive.span)) { Success(module) => module, Indeterminate => return Indeterminate, Failed(err) => return Failed(err), From e1c9efcba48f098482ee6033835a4fe321268709 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 17 Aug 2016 20:48:53 +0000 Subject: [PATCH 131/768] Refactor `value_determined` -> `value_result`, `type_determined` -> `type_result`. --- src/librustc_resolve/resolve_imports.rs | 85 +++++++++++++------------ 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 3c44051503634..6e1128c67735e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -38,23 +38,23 @@ impl<'a> Resolver<'a> { /// Contains data for specific types of import directives. #[derive(Clone, Debug)] -pub enum ImportDirectiveSubclass { +pub enum ImportDirectiveSubclass<'a> { SingleImport { target: Name, source: Name, - type_determined: Cell, - value_determined: Cell, + value_result: Cell, bool /* determined? */>>, + type_result: Cell, bool /* determined? */>>, }, GlobImport { is_prelude: bool }, } -impl ImportDirectiveSubclass { +impl<'a> ImportDirectiveSubclass<'a> { pub fn single(target: Name, source: Name) -> Self { SingleImport { target: target, source: source, - type_determined: Cell::new(false), - value_determined: Cell::new(false), + type_result: Cell::new(Err(false)), + value_result: Cell::new(Err(false)), } } } @@ -66,7 +66,7 @@ pub struct ImportDirective<'a> { parent: Module<'a>, module_path: Vec, target_module: Cell>>, // the resolution of `module_path` - subclass: ImportDirectiveSubclass, + subclass: ImportDirectiveSubclass<'a>, span: Span, vis: ty::Visibility, // see note in ImportResolutionPerNamespace about how to use this } @@ -235,7 +235,7 @@ impl<'a> Resolver<'a> { // Add an import directive to the current module. pub fn add_import_directive(&mut self, module_path: Vec, - subclass: ImportDirectiveSubclass, + subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, vis: ty::Visibility) { @@ -488,30 +488,35 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; directive.target_module.set(Some(target_module)); - let (source, target, value_determined, type_determined) = match directive.subclass { - SingleImport { source, target, ref value_determined, ref type_determined } => - (source, target, value_determined, type_determined), + let (source, target, value_result, type_result) = match directive.subclass { + SingleImport { source, target, ref value_result, ref type_result } => + (source, target, value_result, type_result), GlobImport { .. } => return self.resolve_glob_import(target_module, directive), }; - // We need to resolve both namespaces for this to succeed. - let span = directive.span; - let value_result = - self.resolve_name_in_module(target_module, source, ValueNS, false, Some(span)); - let type_result = - self.resolve_name_in_module(target_module, source, TypeNS, false, Some(span)); - let mut privacy_error = true; - for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined), - (TypeNS, &type_result, type_determined)] { - match *result { - Failed(..) if !determined.get() => { - determined.set(true); + for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { + let was_determined = if let Err(false) = result.get() { + result.set({ + let span = Some(directive.span); + match self.resolve_name_in_module(target_module, source, ns, false, span) { + Success(binding) => Ok(binding), + Indeterminate => Err(false), + Failed(_) => Err(true), + } + }); + false + } else { + true + }; + + match result.get() { + Err(true) if !was_determined => { self.update_resolution(module, target, ns, |_, resolution| { resolution.single_imports.directive_failed() }); } - Success(binding) if !binding.is_importable() => { + Ok(binding) if !binding.is_importable() => { let msg = format!("`{}` is not directly importable", target); struct_span_err!(self.session, directive.span, E0253, "{}", &msg) .span_label(directive.span, &format!("cannot be imported directly")) @@ -521,9 +526,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.import_dummy_binding(directive); return Success(()); } - Success(binding) if !self.is_accessible(binding.vis) => {} - Success(binding) if !determined.get() => { - determined.set(true); + Ok(binding) if !self.is_accessible(binding.vis) => {} + Ok(binding) if !was_determined => { let imported_binding = self.import(binding, directive); let conflict = self.try_define(module, target, ns, imported_binding); if let Err(old_binding) = conflict { @@ -532,14 +536,15 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } privacy_error = false; } - Success(_) => privacy_error = false, + Ok(_) => privacy_error = false, _ => {} } } - match (&value_result, &type_result) { - (&Indeterminate, _) | (_, &Indeterminate) => return Indeterminate, - (&Failed(_), &Failed(_)) => { + let (value_result, type_result) = (value_result.get(), type_result.get()); + match (value_result, type_result) { + (Err(false), _) | (_, Err(false)) => return Indeterminate, + (Err(true), Err(true)) => { let resolutions = target_module.resolutions.borrow(); let names = resolutions.iter().filter_map(|(&(ref name, _), resolution)| { if *name == source { return None; } // Never suggest the same name @@ -565,17 +570,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } if privacy_error { - for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] { - let binding = match *result { Success(binding) => binding, _ => continue }; + for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { + let binding = match result { Ok(binding) => binding, _ => continue }; self.privacy_errors.push(PrivacyError(directive.span, source, binding)); let imported_binding = self.import(binding, directive); let _ = self.try_define(module, target, ns, imported_binding); } } - match (&value_result, &type_result) { - (&Success(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, self) && - self.is_accessible(binding.vis) => { + match (value_result, type_result) { + (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, self) && + self.is_accessible(binding.vis) => { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = format!("consider marking `{}` as `pub` in the imported module", source); @@ -584,8 +589,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { .emit(); } - (_, &Success(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, self) && - self.is_accessible(binding.vis) => { + (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, self) && + self.is_accessible(binding.vis) => { if binding.is_extern_crate() { let msg = format!("extern crate `{}` is private, and cannot be reexported \ (error E0364), consider declaring with `pub`", @@ -607,9 +612,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - let def = match type_result.success().and_then(NameBinding::def) { + let def = match type_result.ok().and_then(NameBinding::def) { Some(def) => def, - None => value_result.success().and_then(NameBinding::def).unwrap(), + None => value_result.ok().and_then(NameBinding::def).unwrap(), }; let path_resolution = PathResolution::new(def); self.def_map.insert(directive.id, path_resolution); From 165b0b618cbe83bf15d40742bd2cb9db935097d6 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 15 Aug 2016 22:43:25 +0000 Subject: [PATCH 132/768] Check privacy in `resolve_name_in_module`. --- src/librustc_resolve/lib.rs | 19 ++----------------- src/librustc_resolve/resolve_imports.rs | 5 ++++- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d514d7e906a8d..6896439640571 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1304,9 +1304,6 @@ impl<'a> Resolver<'a> { // Check to see whether there are type bindings, and, if // so, whether there is a module within. if let Some(module_def) = binding.module() { - if let Some(span) = span { - self.check_privacy(name, binding, span); - } search_module = module_def; } else { let msg = format!("Not a module `{}`", name); @@ -2614,10 +2611,7 @@ impl<'a> Resolver<'a> { let name = segments.last().unwrap().identifier.name; let result = self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); - result.success().map(|binding| { - self.check_privacy(name, binding, span); - binding - }).ok_or(false) + result.success().ok_or(false) } /// Invariant: This must be called only during main resolution, not during @@ -2656,10 +2650,7 @@ impl<'a> Resolver<'a> { let name = segments.last().unwrap().name(); let result = self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); - result.success().map(|binding| { - self.check_privacy(name, binding, span); - binding - }).ok_or(false) + result.success().ok_or(false) } fn with_no_errors(&mut self, f: F) -> T @@ -3276,12 +3267,6 @@ impl<'a> Resolver<'a> { vis.is_at_least(self.current_vis, self) } - fn check_privacy(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span) { - if !self.is_accessible(binding.vis) { - self.privacy_errors.push(PrivacyError(span, name, binding)); - } - } - fn report_privacy_errors(&self) { if self.privacy_errors.len() == 0 { return } let mut reported_spans = HashSet::new(); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 6e1128c67735e..0757ff7ddbfd8 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -165,8 +165,11 @@ impl<'a> Resolver<'a> { if !allow_private_imports && binding.is_import() && !binding.is_pseudo_public() { return Failed(None); } - if record_used.is_some() { + if let Some(span) = record_used { self.record_use(name, ns, binding); + if !self.is_accessible(binding.vis) { + self.privacy_errors.push(PrivacyError(span, name, binding)); + } } Success(binding) }); From fbc322975f198a98d917b5dad0eee557f9889508 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 15 Aug 2016 08:19:09 +0000 Subject: [PATCH 133/768] Refactor out `finalize_import()` from `resolve_import()`. --- src/librustc_resolve/lib.rs | 6 +- src/librustc_resolve/resolve_imports.rs | 220 +++++++++++++----------- 2 files changed, 125 insertions(+), 101 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6896439640571..a0f0fccac8651 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -957,7 +957,10 @@ pub struct Resolver<'a> { structs: FnvHashMap>, - // All indeterminate imports (i.e. imports not known to succeed or fail). + // All imports known to succeed or fail. + determined_imports: Vec<&'a ImportDirective<'a>>, + + // All non-determined imports. indeterminate_imports: Vec<&'a ImportDirective<'a>>, // The module that represents the current item scope. @@ -1149,6 +1152,7 @@ impl<'a> Resolver<'a> { trait_item_map: FnvHashMap(), structs: FnvHashMap(), + determined_imports: Vec::new(), indeterminate_imports: Vec::new(), current_module: graph_root, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 0757ff7ddbfd8..c2f8e31277c3f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -144,6 +144,7 @@ impl<'a> Resolver<'a> { /// Attempts to resolve the supplied name in the given module for the given namespace. /// If successful, returns the binding corresponding to the name. + /// Invariant: if `record_used` is `Some`, import resolution must be complete. pub fn resolve_name_in_module(&mut self, module: Module<'a>, name: Name, @@ -159,32 +160,46 @@ impl<'a> Resolver<'a> { _ => return Failed(None), // This happens when there is a cycle of imports }; - if let Some(result) = self.try_result(&resolution, ns, allow_private_imports) { - // If the resolution doesn't depend on glob definability, check privacy and return. - return result.and_then(|binding| { - if !allow_private_imports && binding.is_import() && !binding.is_pseudo_public() { + let is_disallowed_private_import = |binding: &NameBinding| { + !allow_private_imports && !binding.is_pseudo_public() && binding.is_import() + }; + + if let Some(span) = record_used { + if let Some(binding) = resolution.binding { + if is_disallowed_private_import(binding) { return Failed(None); } - if let Some(span) = record_used { - self.record_use(name, ns, binding); - if !self.is_accessible(binding.vis) { - self.privacy_errors.push(PrivacyError(span, name, binding)); - } + self.record_use(name, ns, binding); + if !self.is_accessible(binding.vis) { + self.privacy_errors.push(PrivacyError(span, name, binding)); + } + } + + return resolution.binding.map(Success).unwrap_or(Failed(None)); + } + + // If the resolution doesn't depend on glob definability, check privacy and return. + if let Some(result) = self.try_result(&resolution, ns) { + return result.and_then(|binding| { + if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) { + Success(binding) + } else { + Failed(None) } - Success(binding) }); } // Check if the globs are determined for directive in module.globs.borrow().iter() { - if !allow_private_imports && directive.vis != ty::Visibility::Public { continue } - if let Some(target_module) = directive.target_module.get() { - let result = self.resolve_name_in_module(target_module, name, ns, false, None); - if let Indeterminate = result { + if self.is_accessible(directive.vis) { + if let Some(target_module) = directive.target_module.get() { + let result = self.resolve_name_in_module(target_module, name, ns, true, None); + if let Indeterminate = result { + return Indeterminate; + } + } else { return Indeterminate; } - } else { - return Indeterminate; } } @@ -193,10 +208,7 @@ impl<'a> Resolver<'a> { // Returns Some(the resolution of the name), or None if the resolution depends // on whether more globs can define the name. - fn try_result(&mut self, - resolution: &NameResolution<'a>, - ns: Namespace, - allow_private_imports: bool) + fn try_result(&mut self, resolution: &NameResolution<'a>, ns: Namespace) -> Option>> { match resolution.binding { Some(binding) if !binding.is_glob_import() => @@ -206,17 +218,8 @@ impl<'a> Resolver<'a> { // Check if a single import can still define the name. match resolution.single_imports { - SingleImports::None => {}, SingleImports::AtLeastOne => return Some(Indeterminate), - SingleImports::MaybeOne(directive) => { - // If (1) we don't allow private imports, (2) no public single import can define - // the name, and (3) no public glob has defined the name, the resolution depends - // on whether more globs can define the name. - if !allow_private_imports && directive.vis != ty::Visibility::Public && - !resolution.binding.map(NameBinding::is_pseudo_public).unwrap_or(false) { - return None; - } - + SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis) => { let target_module = match directive.target_module.get() { Some(target_module) => target_module, None => return Some(Indeterminate), @@ -225,11 +228,12 @@ impl<'a> Resolver<'a> { SingleImport { source, .. } => source, GlobImport { .. } => unreachable!(), }; - match self.resolve_name_in_module(target_module, name, ns, false, None) { + match self.resolve_name_in_module(target_module, name, ns, true, None) { Failed(_) => {} _ => return Some(Indeterminate), } } + SingleImports::MaybeOne(_) | SingleImports::None => {}, } resolution.binding.map(Success) @@ -389,7 +393,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { fn resolve_imports(&mut self) { let mut i = 0; let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - let mut errors = Vec::new(); while self.indeterminate_imports.len() < prev_num_indeterminates { prev_num_indeterminates = self.indeterminate_imports.len(); @@ -400,19 +403,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { for import in imports { match self.resolve_import(&import) { - Failed(err) => { - let (span, help) = match err { - Some((span, msg)) => (span, format!(". {}", msg)), - None => (import.span, String::new()), - }; - errors.push(ImportResolvingError { - import_directive: import, - span: span, - help: help, - }); - } + Failed(_) => self.determined_imports.push(import), Indeterminate => self.indeterminate_imports.push(import), - Success(()) => {} + Success(()) => self.determined_imports.push(import), } } @@ -423,6 +416,22 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.finalize_resolutions_in(module); } + let mut errors = Vec::new(); + for i in 0 .. self.determined_imports.len() { + let import = self.determined_imports[i]; + if let Failed(err) = self.finalize_import(import) { + let (span, help) = match err { + Some((span, msg)) => (span, format!(". {}", msg)), + None => (import.span, String::new()), + }; + errors.push(ImportResolvingError { + import_directive: import, + span: span, + help: help, + }); + } + } + // Report unresolved imports only if no hard error was already reported // to avoid generating multiple errors on the same import. if errors.len() == 0 { @@ -481,9 +490,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let target_module = match directive.target_module.get() { Some(module) => module, - _ => match self.resolve_module_path(&directive.module_path, - DontUseLexicalScope, - Some(directive.span)) { + _ => match self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None) { Success(module) => module, Indeterminate => return Indeterminate, Failed(err) => return Failed(err), @@ -494,27 +501,29 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let (source, target, value_result, type_result) = match directive.subclass { SingleImport { source, target, ref value_result, ref type_result } => (source, target, value_result, type_result), - GlobImport { .. } => return self.resolve_glob_import(target_module, directive), + GlobImport { .. } => { + self.resolve_glob_import(directive); + return Success(()); + } }; - let mut privacy_error = true; + let mut indeterminate = false; for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - let was_determined = if let Err(false) = result.get() { + if let Err(false) = result.get() { result.set({ - let span = Some(directive.span); - match self.resolve_name_in_module(target_module, source, ns, false, span) { + match self.resolve_name_in_module(target_module, source, ns, false, None) { Success(binding) => Ok(binding), Indeterminate => Err(false), Failed(_) => Err(true), } }); - false } else { - true + continue }; match result.get() { - Err(true) if !was_determined => { + Err(false) => indeterminate = true, + Err(true) => { self.update_resolution(module, target, ns, |_, resolution| { resolution.single_imports.directive_failed() }); @@ -529,26 +538,55 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.import_dummy_binding(directive); return Success(()); } - Ok(binding) if !self.is_accessible(binding.vis) => {} - Ok(binding) if !was_determined => { + Ok(binding) => { let imported_binding = self.import(binding, directive); let conflict = self.try_define(module, target, ns, imported_binding); if let Err(old_binding) = conflict { let binding = &self.import(binding, directive); self.report_conflict(module, target, ns, binding, old_binding); } - privacy_error = false; } - Ok(_) => privacy_error = false, - _ => {} } } - let (value_result, type_result) = (value_result.get(), type_result.get()); - match (value_result, type_result) { - (Err(false), _) | (_, Err(false)) => return Indeterminate, - (Err(true), Err(true)) => { - let resolutions = target_module.resolutions.borrow(); + if indeterminate { Indeterminate } else { Success(()) } + } + + fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> { + self.set_current_module(directive.parent); + + let ImportDirective { ref module_path, span, .. } = *directive; + let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span)); + let module = match module_result { + Success(module) => module, + Indeterminate => return Indeterminate, + Failed(err) => return Failed(err), + }; + + let (source, value_result, type_result) = match directive.subclass { + SingleImport { source, ref value_result, ref type_result, .. } => + (source, value_result.get(), type_result.get()), + GlobImport { .. } if module.def_id() == directive.parent.def_id() => { + // Importing a module into itself is not allowed. + let msg = "Cannot glob-import a module into itself.".into(); + return Failed(Some((directive.span, msg))); + } + GlobImport { .. } => return Success(()), + }; + + for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { + if let Ok(binding) = result { + self.record_use(source, ns, binding); + } + } + + if value_result.is_err() && type_result.is_err() { + let (value_result, type_result); + value_result = self.resolve_name_in_module(module, source, ValueNS, false, Some(span)); + type_result = self.resolve_name_in_module(module, source, TypeNS, false, Some(span)); + + return if let (Failed(_), Failed(_)) = (value_result, type_result) { + let resolutions = module.resolutions.borrow(); let names = resolutions.iter().filter_map(|(&(ref name, _), resolution)| { if *name == source { return None; } // Never suggest the same name match *resolution.borrow() { @@ -561,29 +599,22 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Some(name) => format!(". Did you mean to use `{}`?", name), None => "".to_owned(), }; - let module_str = module_to_string(target_module); + let module_str = module_to_string(module); let msg = if &module_str == "???" { format!("There is no `{}` in the crate root{}", source, lev_suggestion) } else { format!("There is no `{}` in `{}`{}", source, module_str, lev_suggestion) }; - return Failed(Some((directive.span, msg))); - } - _ => (), - } - - if privacy_error { - for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - let binding = match result { Ok(binding) => binding, _ => continue }; - self.privacy_errors.push(PrivacyError(directive.span, source, binding)); - let imported_binding = self.import(binding, directive); - let _ = self.try_define(module, target, ns, imported_binding); + Failed(Some((directive.span, msg))) + } else { + // `resolve_name_in_module` reported a privacy error. + self.import_dummy_binding(directive); + Success(()) } } match (value_result, type_result) { - (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, self) && - self.is_accessible(binding.vis) => { + (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, self) => { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = format!("consider marking `{}` as `pub` in the imported module", source); @@ -592,8 +623,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { .emit(); } - (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, self) && - self.is_accessible(binding.vis) => { + (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, self) => { if binding.is_extern_crate() { let msg = format!("extern crate `{}` is private, and cannot be reexported \ (error E0364), consider declaring with `pub`", @@ -626,27 +656,20 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { return Success(()); } - // Resolves a glob import. Note that this function cannot fail; it either - // succeeds or bails out (as importing * from an empty module or a module - // that exports nothing is valid). target_module is the module we are - // actually importing, i.e., `foo` in `use foo::*`. - fn resolve_glob_import(&mut self, target_module: Module<'b>, directive: &'b ImportDirective<'b>) - -> ResolveResult<()> { + fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) { + let target_module = directive.target_module.get().unwrap(); + self.populate_module_if_necessary(target_module); + if let Some(Def::Trait(_)) = target_module.def { self.session.span_err(directive.span, "items in traits are not importable."); } - let module = self.current_module; - if module.def_id() == target_module.def_id() { - // This means we are trying to glob import a module into itself, and it is a no-go - let msg = "Cannot glob-import a module into itself.".into(); - return Failed(Some((directive.span, msg))); - } - self.populate_module_if_necessary(target_module); - - if let GlobImport { is_prelude: true } = directive.subclass { + let module = directive.parent; + if target_module.def_id() == module.def_id() { + return; + } else if let GlobImport { is_prelude: true } = directive.subclass { self.prelude = Some(target_module); - return Success(()); + return; } // Add to target_module's glob_importers @@ -669,9 +692,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let resolution = PathResolution::new(Def::Mod(did)); self.def_map.insert(directive.id, resolution); } - - debug!("(resolving glob import) successfully resolved import"); - return Success(()); } // Miscellaneous post-processing, including recording reexports, reporting conflicts, From da1f7731f6cebcf8b8a896c65b38e19b102e19c4 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 3 Aug 2016 12:55:01 +1200 Subject: [PATCH 134/768] rustdoc: remove the `!` from macro URLs and titles --- src/librustdoc/clean/mod.rs | 8 +++++--- src/test/rustdoc/issue-26606.rs | 2 +- src/test/rustdoc/macros.rs | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 75d21399f05e6..39b1a04e98e69 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2803,7 +2803,7 @@ pub struct Macro { impl Clean for doctree::Macro { fn clean(&self, cx: &DocContext) -> Item { - let name = format!("{}!", self.name.clean(cx)); + let name = self.name.clean(cx); Item { name: Some(name.clone()), attrs: self.attrs.clean(cx), @@ -2814,8 +2814,10 @@ impl Clean for doctree::Macro { def_id: cx.map.local_def_id(self.id), inner: MacroItem(Macro { source: format!("macro_rules! {} {{\n{}}}", - name.trim_right_matches('!'), self.matchers.iter().map(|span| - format!(" {} => {{ ... }};\n", span.to_src(cx))).collect::()), + name, + self.matchers.iter().map(|span| { + format!(" {} => {{ ... }};\n", span.to_src(cx)) + }).collect::()), imported_from: self.imported_from.clean(cx), }), } diff --git a/src/test/rustdoc/issue-26606.rs b/src/test/rustdoc/issue-26606.rs index df40c01686dcc..12de76654512d 100644 --- a/src/test/rustdoc/issue-26606.rs +++ b/src/test/rustdoc/issue-26606.rs @@ -12,7 +12,7 @@ // ignore-cross-compile // build-aux-docs -// @has issue_26606_macro/macro.make_item!.html +// @has issue_26606_macro/macro.make_item.html #[macro_use] extern crate issue_26606_macro; diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs index b052ad2da2fa9..f4115d8229a54 100644 --- a/src/test/rustdoc/macros.rs +++ b/src/test/rustdoc/macros.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// @has macros/macro.my_macro!.html //pre 'macro_rules! my_macro {' +// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {' // @has - //pre '() => { ... };' // @has - //pre '($a:tt) => { ... };' // @has - //pre '($e:expr) => { ... };' From e6cc4c5d13f8819c72568f9675e84c1d17368c67 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 16 Aug 2016 10:36:39 +1200 Subject: [PATCH 135/768] Fix links --- src/doc/book/error-handling.md | 8 ++++---- src/libcollections/fmt.rs | 2 +- src/libstd/io/mod.rs | 6 +++--- src/libstd/lib.rs | 2 +- src/libstd/primitive_docs.rs | 2 +- src/tools/linkchecker/Cargo.lock | 6 ++++++ 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md index 6e13b464e4c25..a62e1b7dfa9c5 100644 --- a/src/doc/book/error-handling.md +++ b/src/doc/book/error-handling.md @@ -59,7 +59,7 @@ handling is reducing the amount of explicit case analysis the programmer has to do while keeping code composable. Keeping code composable is important, because without that requirement, we -could [`panic`](../std/macro.panic!.html) whenever we +could [`panic`](../std/macro.panic.html) whenever we come across something unexpected. (`panic` causes the current task to unwind, and in most cases, the entire program aborts.) Here's an example: @@ -944,7 +944,7 @@ macro_rules! try { } ``` -(The [real definition](../std/macro.try!.html) is a bit more +(The [real definition](../std/macro.try.html) is a bit more sophisticated. We will address that later.) Using the `try!` macro makes it very easy to simplify our last example. Since @@ -1271,7 +1271,7 @@ macro_rules! try { ``` This is not its real definition. Its real definition is -[in the standard library](../std/macro.try!.html): +[in the standard library](../std/macro.try.html): @@ -2178,7 +2178,7 @@ heuristics! [`From`](../std/convert/trait.From.html) and [`Error`](../std/error/trait.Error.html) - impls to make the [`try!`](../std/macro.try!.html) + impls to make the [`try!`](../std/macro.try.html) macro more ergonomic. * If you're writing a library and your code can produce errors, define your own error type and implement the diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index be0ef85d6b114..b7cbfb60ec4e9 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -530,7 +530,7 @@ use string; /// assert_eq!(s, "Hello, world!"); /// ``` /// -/// [format!]: ../macro.format!.html +/// [format!]: ../macro.format.html #[stable(feature = "rust1", since = "1.0.0")] pub fn format(args: Arguments) -> string::String { let mut output = string::String::new(); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 88fd4186e0a2a..307d014fd68c6 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -236,7 +236,7 @@ //! to read the line and print it, so we use `()`. //! //! [result]: type.Result.html -//! [try]: ../macro.try!.html +//! [try]: ../macro.try.html //! //! ## Platform-specific behavior //! @@ -957,8 +957,8 @@ pub trait Write { /// explicitly be called. The [`write!`][write] macro should be favored to /// invoke this method instead. /// - /// [formatargs]: ../macro.format_args!.html - /// [write]: ../macro.write!.html + /// [formatargs]: ../macro.format_args.html + /// [write]: ../macro.write.html /// /// This function internally uses the [`write_all`][writeall] method on /// this trait and hence will continuously write data so long as no errors diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c05e0c3ca68df..ff3b9c6d04163 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -175,7 +175,7 @@ //! [`atomic`]: sync/atomic/index.html //! [`collections`]: collections/index.html //! [`for`]: ../book/loops.html#for -//! [`format!`]: macro.format!.html +//! [`format!`]: macro.format.html //! [`fs`]: fs/index.html //! [`io`]: io/index.html //! [`iter`]: iter/index.html diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index d31a593037622..2b92da6c684a4 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -27,7 +27,7 @@ /// assert!(!bool_val); /// ``` /// -/// [`assert!`]: macro.assert!.html +/// [`assert!`]: macro.assert.html /// [`if`]: ../book/if.html /// [`BitAnd`]: ops/trait.BitAnd.html /// [`BitOr`]: ops/trait.BitOr.html diff --git a/src/tools/linkchecker/Cargo.lock b/src/tools/linkchecker/Cargo.lock index ed5fe081ffb2e..d71df6d3f83a8 100644 --- a/src/tools/linkchecker/Cargo.lock +++ b/src/tools/linkchecker/Cargo.lock @@ -42,3 +42,9 @@ dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[metadata] +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" +"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" +"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" +"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119" From 683bcc02955f988ab2726f1b7708baa6c1e64b7b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 3 May 2016 13:01:54 +1200 Subject: [PATCH 136/768] Use a Carrier trait with the `?` operator Allows use with `Option` and custom `Result`-like types. --- src/libcore/ops.rs | 125 ++++++++++++++++++++++ src/librustc/hir/lowering.rs | 130 ++++++++++++++--------- src/test/run-pass/try-operator-custom.rs | 73 +++++++++++++ src/test/run-pass/try-operator.rs | 17 +++ 4 files changed, 296 insertions(+), 49 deletions(-) create mode 100644 src/test/run-pass/try-operator-custom.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 4ac1b8394f450..a869b3c4f98c5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -75,6 +75,8 @@ use cmp::PartialOrd; use fmt; use marker::{Sized, Unsize}; +use result::Result::{self, Ok, Err}; +use option::Option::{self, Some, None}; /// The `Drop` trait is used to run some code when a value goes out of scope. /// This is sometimes called a 'destructor'. @@ -2150,3 +2152,126 @@ pub trait BoxPlace : Place { /// Creates a globally fresh place. fn make_place() -> Self; } + +/// A trait for types which have success and error states and are meant to work +/// with the question mark operator. +/// When the `?` operator is used with a value, whether the value is in the +/// success or error state is determined by calling `translate`. +/// +/// This trait is **very** experimental, it will probably be iterated on heavily +/// before it is stabilised. Implementors should expect change. Users of `?` +/// should not rely on any implementations of `Carrier` other than `Result`, +/// i.e., you should not expect `?` to continue to work with `Option`, etc. +#[unstable(feature = "question_mark_carrier", issue = "31436")] +pub trait Carrier { + /// The type of the value when computation succeeds. + type Success; + /// The type of the value when computation errors out. + type Error; + + /// Create a `Carrier` from a success value. + fn from_success(Self::Success) -> Self; + + /// Create a `Carrier` from an error value. + fn from_error(Self::Error) -> Self; + + /// Translate this `Carrier` to another implementation of `Carrier` with the + /// same associated types. + fn translate(self) -> T where T: Carrier; +} + +#[unstable(feature = "question_mark_carrier", issue = "31436")] +impl Carrier for Result { + type Success = U; + type Error = V; + + fn from_success(u: U) -> Result { + Ok(u) + } + + fn from_error(e: V) -> Result { + Err(e) + } + + fn translate(self) -> T + where T: Carrier + { + match self { + Ok(u) => T::from_success(u), + Err(e) => T::from_error(e), + } + } +} + +#[unstable(feature = "question_mark_carrier", issue = "31436")] +impl Carrier for Option { + type Success = U; + type Error = (); + + fn from_success(u: U) -> Option { + Some(u) + } + + fn from_error(_: ()) -> Option { + None + } + + fn translate(self) -> T + where T: Carrier + { + match self { + Some(u) => T::from_success(u), + None => T::from_error(()), + } + } +} + +// Implementing Carrier for bools means it's easy to write short-circuiting +// functions. E.g., +// ``` +// fn foo() -> bool { +// if !(f() || g()) { +// return false; +// } +// +// some_computation(); +// if h() { +// return false; +// } +// +// more_computation(); +// i() +// } +// ``` +// becomes +// ``` +// fn foo() -> bool { +// (f() || g())?; +// some_computation(); +// (!h())?; +// more_computation(); +// i() +// } +// ``` +#[unstable(feature = "question_mark_carrier", issue = "31436")] +impl Carrier for bool { + type Success = (); + type Error = (); + + fn from_success(_: ()) -> bool { + true + } + + fn from_error(_: ()) -> bool { + false + } + + fn translate(self) -> T + where T: Carrier + { + match self { + true => T::from_success(()), + false => T::from_error(()), + } + } +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c2b211238b2f1..b45610c3fe820 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -966,7 +966,7 @@ impl<'a> LoweringContext<'a> { let inplace_finalize = ["ops", "InPlace", "finalize"]; let make_call = |this: &mut LoweringContext, p, args| { - let path = this.core_path(e.span, p); + let path = this.std_path(e.span, p); let path = this.expr_path(path, ThinVec::new()); this.expr_call(e.span, path, args) }; @@ -1159,15 +1159,13 @@ impl<'a> LoweringContext<'a> { ast_expr: &Expr, path: &[&str], fields: &[(&str, &P)]) -> P { - let strs = this.std_path(&iter::once(&"ops") - .chain(path) - .map(|s| *s) - .collect::>()); - - let structpath = this.path_global(ast_expr.span, strs); + let struct_path = this.std_path(ast_expr.span, + &iter::once(&"ops").chain(path) + .map(|s| *s) + .collect::>()); let hir_expr = if fields.len() == 0 { - this.expr_path(structpath, ast_expr.attrs.clone()) + this.expr_path(struct_path, ast_expr.attrs.clone()) } else { let fields = fields.into_iter().map(|&(s, e)| { let expr = this.lower_expr(&e); @@ -1180,7 +1178,7 @@ impl<'a> LoweringContext<'a> { }).collect(); let attrs = ast_expr.attrs.clone(); - this.expr_struct(ast_expr.span, structpath, fields, None, attrs) + this.expr_struct(ast_expr.span, struct_path, fields, None, attrs) }; this.signal_block_expr(hir_vec![], @@ -1463,11 +1461,7 @@ impl<'a> LoweringContext<'a> { // `match ::std::iter::Iterator::next(&mut iter) { ... }` let match_expr = { - let next_path = { - let strs = self.std_path(&["iter", "Iterator", "next"]); - - self.path_global(e.span, strs) - }; + let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]); let iter = self.expr_ident(e.span, iter, iter_pat.id); let ref_mut_iter = self.expr_mut_addr_of(e.span, iter); let next_path = self.expr_path(next_path, ThinVec::new()); @@ -1494,11 +1488,8 @@ impl<'a> LoweringContext<'a> { // `match ::std::iter::IntoIterator::into_iter() { ... }` let into_iter_expr = { - let into_iter_path = { - let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]); - - self.path_global(e.span, strs) - }; + let into_iter_path = self.std_path(e.span, + &["iter", "IntoIterator", "into_iter"]); let into_iter = self.expr_path(into_iter_path, ThinVec::new()); self.expr_call(e.span, into_iter, hir_vec![head]) @@ -1527,16 +1518,32 @@ impl<'a> LoweringContext<'a> { // to: // // { - // match { + // match { Carrier::translate( { } ) } { // Ok(val) => val, - // Err(err) => { - // return Err(From::from(err)) - // } + // Err(err) => { return Carrier::from_error(From::from(err)); } // } // } - // expand - let sub_expr = self.lower_expr(sub_expr); + // { Carrier::translate( { } ) } + let discr = { + // expand + let sub_expr = self.lower_expr(sub_expr); + let sub_expr = self.signal_block_expr(hir_vec![], + sub_expr, + e.span, + hir::PopUnstableBlock, + ThinVec::new()); + + let path = self.std_path(e.span, &["ops", "Carrier", "translate"]); + let path = self.expr_path(path, ThinVec::new()); + let call = self.expr_call(e.span, path, hir_vec![sub_expr]); + + self.signal_block_expr(hir_vec![], + call, + e.span, + hir::PushUnstableBlock, + ThinVec::new()) + }; // Ok(val) => val let ok_arm = { @@ -1548,32 +1555,35 @@ impl<'a> LoweringContext<'a> { self.arm(hir_vec![ok_pat], val_expr) }; - // Err(err) => return Err(From::from(err)) + // Err(err) => { return Carrier::from_error(From::from(err)); } let err_arm = { let err_ident = self.str_to_ident("err"); let err_local = self.pat_ident(e.span, err_ident); let from_expr = { - let path = self.std_path(&["convert", "From", "from"]); - let path = self.path_global(e.span, path); + let path = self.std_path(e.span, &["convert", "From", "from"]); let from = self.expr_path(path, ThinVec::new()); let err_expr = self.expr_ident(e.span, err_ident, err_local.id); self.expr_call(e.span, from, hir_vec![err_expr]) }; - let err_expr = { - let path = self.std_path(&["result", "Result", "Err"]); - let path = self.path_global(e.span, path); - let err_ctor = self.expr_path(path, ThinVec::new()); - self.expr_call(e.span, err_ctor, hir_vec![from_expr]) + let from_err_expr = { + let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]); + let from_err = self.expr_path(path, ThinVec::new()); + self.expr_call(e.span, from_err, hir_vec![from_expr]) }; - let err_pat = self.pat_err(e.span, err_local); + let ret_expr = self.expr(e.span, - hir::Expr_::ExprRet(Some(err_expr)), - ThinVec::new()); - self.arm(hir_vec![err_pat], ret_expr) + hir::Expr_::ExprRet(Some(from_err_expr)), + ThinVec::new()); + let ret_stmt = self.stmt_expr(ret_expr); + let block = self.signal_block_stmt(ret_stmt, e.span, + hir::PushUnstableBlock, ThinVec::new()); + + let err_pat = self.pat_err(e.span, err_local); + self.arm(hir_vec![err_pat], block) }; - return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm], + return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm], hir::MatchSource::TryDesugar); } @@ -1787,6 +1797,15 @@ impl<'a> LoweringContext<'a> { (respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id) } + // Turns `` into `;`, note that this produces a StmtSemi, not a + // StmtExpr. + fn stmt_expr(&self, expr: P) -> hir::Stmt { + hir::Stmt { + span: expr.span, + node: hir::StmtSemi(expr, self.next_id()), + } + } + fn block_expr(&mut self, expr: P) -> P { self.block_all(expr.span, hir::HirVec::new(), Some(expr)) } @@ -1803,26 +1822,22 @@ impl<'a> LoweringContext<'a> { } fn pat_ok(&mut self, span: Span, pat: P) -> P { - let ok = self.std_path(&["result", "Result", "Ok"]); - let path = self.path_global(span, ok); + let path = self.std_path(span, &["result", "Result", "Ok"]); self.pat_enum(span, path, hir_vec![pat]) } fn pat_err(&mut self, span: Span, pat: P) -> P { - let err = self.std_path(&["result", "Result", "Err"]); - let path = self.path_global(span, err); + let path = self.std_path(span, &["result", "Result", "Err"]); self.pat_enum(span, path, hir_vec![pat]) } fn pat_some(&mut self, span: Span, pat: P) -> P { - let some = self.std_path(&["option", "Option", "Some"]); - let path = self.path_global(span, some); + let path = self.std_path(span, &["option", "Option", "Some"]); self.pat_enum(span, path, hir_vec![pat]) } fn pat_none(&mut self, span: Span) -> P { - let none = self.std_path(&["option", "Option", "None"]); - let path = self.path_global(span, none); + let path = self.std_path(span, &["option", "Option", "None"]); self.pat_enum(span, path, hir_vec![]) } @@ -1920,7 +1935,7 @@ impl<'a> LoweringContext<'a> { } } - fn std_path(&mut self, components: &[&str]) -> Vec { + fn std_path_components(&mut self, components: &[&str]) -> Vec { let mut v = Vec::new(); if let Some(s) = self.crate_root { v.push(token::intern(s)); @@ -1931,8 +1946,8 @@ impl<'a> LoweringContext<'a> { // Given suffix ["b","c","d"], returns path `::std::b::c::d` when // `fld.cx.use_std`, and `::core::b::c::d` otherwise. - fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path { - let idents = self.std_path(components); + fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path { + let idents = self.std_path_components(components); self.path_global(span, idents) } @@ -1953,4 +1968,21 @@ impl<'a> LoweringContext<'a> { }); self.expr_block(block, attrs) } + + fn signal_block_stmt(&mut self, + stmt: hir::Stmt, + span: Span, + rule: hir::BlockCheckMode, + attrs: ThinVec) + -> P { + let id = self.next_id(); + let block = P(hir::Block { + rules: rule, + span: span, + id: id, + stmts: hir_vec![stmt], + expr: None, + }); + self.expr_block(block, attrs) + } } diff --git a/src/test/run-pass/try-operator-custom.rs b/src/test/run-pass/try-operator-custom.rs new file mode 100644 index 0000000000000..577d19a58960d --- /dev/null +++ b/src/test/run-pass/try-operator-custom.rs @@ -0,0 +1,73 @@ +// 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. + +#![feature(question_mark, question_mark_carrier)] + +use std::ops::Carrier; + +enum MyResult { + Awesome(T), + Terrible(U) +} + +impl Carrier for MyResult { + type Success = U; + type Error = V; + + fn from_success(u: U) -> MyResult { + MyResult::Awesome(u) + } + + fn from_error(e: V) -> MyResult { + MyResult::Terrible(e) + } + + fn translate(self) -> T + where T: Carrier + { + match self { + MyResult::Awesome(u) => T::from_success(u), + MyResult::Terrible(e) => T::from_error(e), + } + } +} + +fn f(x: i32) -> Result { + if x == 0 { + Ok(42) + } else { + let y = g(x)?; + Ok(y) + } +} + +fn g(x: i32) -> MyResult { + let _y = f(x - 1)?; + MyResult::Terrible("Hello".to_owned()) +} + +fn h() -> MyResult { + let a: Result = Err("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn i() -> MyResult { + let a: MyResult = MyResult::Terrible("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn main() { + assert!(f(0) == Ok(42)); + assert!(f(10) == Err("Hello".to_owned())); + let _ = h(); + let _ = i(); +} diff --git a/src/test/run-pass/try-operator.rs b/src/test/run-pass/try-operator.rs index de5ccf09c5923..8076e00fd08ac 100644 --- a/src/test/run-pass/try-operator.rs +++ b/src/test/run-pass/try-operator.rs @@ -144,6 +144,23 @@ fn merge_error() -> Result { Ok(s.parse::()? + 1) } +fn option() -> Option { + let x = Some(42); + let y = x?; + Some(y + 2) +} + +fn bool() -> bool { + let x = true; + let y = false; + let z = true; + + (x || y)?; + let a: () = z?; + x?; + true +} + fn main() { assert_eq!(Ok(3), on_method()); From 0dc13ee7f23f878e626771c1a3925b37b19fd6e4 Mon Sep 17 00:00:00 2001 From: clementmiao Date: Wed, 17 Aug 2016 22:03:52 -0700 Subject: [PATCH 137/768] updated E0395 to new error format --- src/librustc_mir/transform/qualify_consts.rs | 11 ++++++++--- src/test/compile-fail/E0395.rs | 2 +- src/test/compile-fail/issue-25826.rs | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 103a15dadb61c..a9ef702ee0548 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -678,9 +678,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { - span_err!(self.tcx.sess, self.span, E0395, - "raw pointers cannot be compared in {}s", - self.mode); + struct_span_err!( + self.tcx.sess, self.span, E0395, + "raw pointers cannot be compared in {}s", + self.mode) + .span_label( + self.span, + &format!("comparing raw pointers in static")) + .emit(); } } } diff --git a/src/test/compile-fail/E0395.rs b/src/test/compile-fail/E0395.rs index 6ab66313a0472..98f08cd68c22d 100644 --- a/src/test/compile-fail/E0395.rs +++ b/src/test/compile-fail/E0395.rs @@ -12,6 +12,6 @@ static FOO: i32 = 42; static BAR: i32 = 42; static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR E0395 - + //~| NOTE comparing raw pointers in static fn main() { } diff --git a/src/test/compile-fail/issue-25826.rs b/src/test/compile-fail/issue-25826.rs index 00e1279d58a0e..468282fa7cca9 100644 --- a/src/test/compile-fail/issue-25826.rs +++ b/src/test/compile-fail/issue-25826.rs @@ -12,5 +12,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = id:: as *const () < id:: as *const (); //~^ ERROR raw pointers cannot be compared in constants [E0395] + //~^^ NOTE comparing raw pointers in static println!("{}", A); } From dae1406b822c1357f701047951e747dbca2b1446 Mon Sep 17 00:00:00 2001 From: clementmiao Date: Wed, 17 Aug 2016 22:45:21 -0700 Subject: [PATCH 138/768] updated E0396 to new error format --- src/librustc_mir/transform/qualify_consts.rs | 10 +++++++--- src/test/compile-fail/E0396.rs | 1 + src/test/compile-fail/const-deref-ptr.rs | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 103a15dadb61c..e5473d288d4f3 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -490,9 +490,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if let ty::TyRawPtr(_) = base_ty.sty { this.add(Qualif::NOT_CONST); if this.mode != Mode::Fn { - span_err!(this.tcx.sess, this.span, E0396, - "raw pointers cannot be dereferenced in {}s", - this.mode); + struct_span_err!(this.tcx.sess, + this.span, E0396, + "raw pointers cannot be dereferenced in {}s", + this.mode) + .span_label(this.span, + &format!("dereference of raw pointer in constant")) + .emit(); } } } diff --git a/src/test/compile-fail/E0396.rs b/src/test/compile-fail/E0396.rs index 7f34acdfb9007..47080fb6e9ef7 100644 --- a/src/test/compile-fail/E0396.rs +++ b/src/test/compile-fail/E0396.rs @@ -11,6 +11,7 @@ const REG_ADDR: *const u8 = 0x5f3759df as *const u8; const VALUE: u8 = unsafe { *REG_ADDR }; //~ ERROR E0396 + //~| NOTE dereference of raw pointer in constant fn main() { } diff --git a/src/test/compile-fail/const-deref-ptr.rs b/src/test/compile-fail/const-deref-ptr.rs index fa15f3e87c694..c626801d48c03 100644 --- a/src/test/compile-fail/const-deref-ptr.rs +++ b/src/test/compile-fail/const-deref-ptr.rs @@ -12,5 +12,6 @@ fn main() { static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396 + //~| NOTE dereference of raw pointer in constant println!("{}", C); } From 6976991569977e8097da5f7660a31a42d11e48d2 Mon Sep 17 00:00:00 2001 From: Erik Uggeldahl Date: Thu, 18 Aug 2016 02:03:42 -0400 Subject: [PATCH 139/768] Fix tiny spelling mistake in book Changed datastructure to data structure --- src/doc/book/borrow-and-asref.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/borrow-and-asref.md b/src/doc/book/borrow-and-asref.md index 1cfeb2620bd08..c30b2e68665f1 100644 --- a/src/doc/book/borrow-and-asref.md +++ b/src/doc/book/borrow-and-asref.md @@ -8,7 +8,7 @@ different. Here’s a quick refresher on what these two traits mean. # Borrow -The `Borrow` trait is used when you’re writing a datastructure, and you want to +The `Borrow` trait is used when you’re writing a data structure, and you want to use either an owned or borrowed type as synonymous for some purpose. For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: @@ -86,7 +86,7 @@ We can see how they’re kind of the same: they both deal with owned and borrowe versions of some type. However, they’re a bit different. Choose `Borrow` when you want to abstract over different kinds of borrowing, or -when you’re building a datastructure that treats owned and borrowed values in +when you’re building a data structure that treats owned and borrowed values in equivalent ways, such as hashing and comparison. Choose `AsRef` when you want to convert something to a reference directly, and From 5b969a2a58da5a1c7f6ea0587b9ff97b56e2f21d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 00:11:56 +0000 Subject: [PATCH 140/768] Improve import failure detection. --- src/librustc_resolve/resolve_imports.rs | 31 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c2f8e31277c3f..195333f4acda2 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -68,7 +68,7 @@ pub struct ImportDirective<'a> { target_module: Cell>>, // the resolution of `module_path` subclass: ImportDirectiveSubclass<'a>, span: Span, - vis: ty::Visibility, // see note in ImportResolutionPerNamespace about how to use this + vis: Cell, } impl<'a> ImportDirective<'a> { @@ -191,7 +191,7 @@ impl<'a> Resolver<'a> { // Check if the globs are determined for directive in module.globs.borrow().iter() { - if self.is_accessible(directive.vis) { + if self.is_accessible(directive.vis.get()) { if let Some(target_module) = directive.target_module.get() { let result = self.resolve_name_in_module(target_module, name, ns, true, None); if let Indeterminate = result { @@ -219,7 +219,7 @@ impl<'a> Resolver<'a> { // Check if a single import can still define the name. match resolution.single_imports { SingleImports::AtLeastOne => return Some(Indeterminate), - SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis) => { + SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { let target_module = match directive.target_module.get() { Some(target_module) => target_module, None => return Some(Indeterminate), @@ -254,7 +254,7 @@ impl<'a> Resolver<'a> { subclass: subclass, span: span, id: id, - vis: vis, + vis: Cell::new(vis), }); self.indeterminate_imports.push(directive); @@ -282,7 +282,7 @@ impl<'a> Resolver<'a> { directive: directive, }, span: directive.span, - vis: directive.vis, + vis: directive.vis.get(), } } @@ -488,13 +488,22 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let module = directive.parent; self.set_current_module(module); - let target_module = match directive.target_module.get() { - Some(module) => module, - _ => match self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None) { + let target_module = if let Some(module) = directive.target_module.get() { + module + } else { + let vis = directive.vis.get(); + // For better failure detection, pretend that the import will not define any names + // while resolving its module path. + directive.vis.set(ty::Visibility::PrivateExternal); + let result = + self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None); + directive.vis.set(vis); + + match result { Success(module) => module, Indeterminate => return Indeterminate, Failed(err) => return Failed(err), - }, + } }; directive.target_module.set(Some(target_module)); @@ -614,7 +623,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } match (value_result, type_result) { - (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, self) => { + (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = format!("consider marking `{}` as `pub` in the imported module", source); @@ -623,7 +632,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { .emit(); } - (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, self) => { + (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { if binding.is_extern_crate() { let msg = format!("extern crate `{}` is private, and cannot be reexported \ (error E0364), consider declaring with `pub`", From 11c38fdce08d3fa38cb9a6a585215ce8957da3a9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 01:43:26 +0000 Subject: [PATCH 141/768] Rename `target_module` to `module` or `imported_module`. --- src/librustc_resolve/resolve_imports.rs | 50 ++++++++++++------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 195333f4acda2..e76a93a6db03a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -65,7 +65,7 @@ pub struct ImportDirective<'a> { pub id: NodeId, parent: Module<'a>, module_path: Vec, - target_module: Cell>>, // the resolution of `module_path` + imported_module: Cell>>, // the resolution of `module_path` subclass: ImportDirectiveSubclass<'a>, span: Span, vis: Cell, @@ -192,8 +192,8 @@ impl<'a> Resolver<'a> { // Check if the globs are determined for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { - if let Some(target_module) = directive.target_module.get() { - let result = self.resolve_name_in_module(target_module, name, ns, true, None); + if let Some(module) = directive.imported_module.get() { + let result = self.resolve_name_in_module(module, name, ns, true, None); if let Indeterminate = result { return Indeterminate; } @@ -220,15 +220,15 @@ impl<'a> Resolver<'a> { match resolution.single_imports { SingleImports::AtLeastOne => return Some(Indeterminate), SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { - let target_module = match directive.target_module.get() { - Some(target_module) => target_module, + let module = match directive.imported_module.get() { + Some(module) => module, None => return Some(Indeterminate), }; let name = match directive.subclass { SingleImport { source, .. } => source, GlobImport { .. } => unreachable!(), }; - match self.resolve_name_in_module(target_module, name, ns, true, None) { + match self.resolve_name_in_module(module, name, ns, true, None) { Failed(_) => {} _ => return Some(Indeterminate), } @@ -250,7 +250,7 @@ impl<'a> Resolver<'a> { let directive = self.arenas.alloc_import_directive(ImportDirective { parent: current_module, module_path: module_path, - target_module: Cell::new(None), + imported_module: Cell::new(None), subclass: subclass, span: span, id: id, @@ -485,10 +485,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { names_to_string(&directive.module_path), module_to_string(self.current_module)); - let module = directive.parent; - self.set_current_module(module); + self.set_current_module(directive.parent); - let target_module = if let Some(module) = directive.target_module.get() { + let module = if let Some(module) = directive.imported_module.get() { module } else { let vis = directive.vis.get(); @@ -506,7 +505,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } }; - directive.target_module.set(Some(target_module)); + directive.imported_module.set(Some(module)); let (source, target, value_result, type_result) = match directive.subclass { SingleImport { source, target, ref value_result, ref type_result } => (source, target, value_result, type_result), @@ -520,7 +519,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { if let Err(false) = result.get() { result.set({ - match self.resolve_name_in_module(target_module, source, ns, false, None) { + match self.resolve_name_in_module(module, source, ns, false, None) { Success(binding) => Ok(binding), Indeterminate => Err(false), Failed(_) => Err(true), @@ -533,7 +532,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { match result.get() { Err(false) => indeterminate = true, Err(true) => { - self.update_resolution(module, target, ns, |_, resolution| { + self.update_resolution(directive.parent, target, ns, |_, resolution| { resolution.single_imports.directive_failed() }); } @@ -549,10 +548,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } Ok(binding) => { let imported_binding = self.import(binding, directive); - let conflict = self.try_define(module, target, ns, imported_binding); + let conflict = self.try_define(directive.parent, target, ns, imported_binding); if let Err(old_binding) = conflict { let binding = &self.import(binding, directive); - self.report_conflict(module, target, ns, binding, old_binding); + self.report_conflict(directive.parent, target, ns, binding, old_binding); } } } @@ -666,38 +665,37 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) { - let target_module = directive.target_module.get().unwrap(); - self.populate_module_if_necessary(target_module); + let module = directive.imported_module.get().unwrap(); + self.populate_module_if_necessary(module); - if let Some(Def::Trait(_)) = target_module.def { + if let Some(Def::Trait(_)) = module.def { self.session.span_err(directive.span, "items in traits are not importable."); } - let module = directive.parent; - if target_module.def_id() == module.def_id() { + if module.def_id() == directive.parent.def_id() { return; } else if let GlobImport { is_prelude: true } = directive.subclass { - self.prelude = Some(target_module); + self.prelude = Some(module); return; } - // Add to target_module's glob_importers - target_module.glob_importers.borrow_mut().push(directive); + // Add to module's glob_importers + module.glob_importers.borrow_mut().push(directive); // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. - let bindings = target_module.resolutions.borrow().iter().filter_map(|(name, resolution)| { + let bindings = module.resolutions.borrow().iter().filter_map(|(name, resolution)| { resolution.borrow().binding().map(|binding| (*name, binding)) }).collect::>(); for ((name, ns), binding) in bindings { if binding.is_importable() && binding.is_pseudo_public() { let imported_binding = self.import(binding, directive); - let _ = self.try_define(module, name, ns, imported_binding); + let _ = self.try_define(directive.parent, name, ns, imported_binding); } } // Record the destination of this import - if let Some(did) = target_module.def_id() { + if let Some(did) = module.def_id() { let resolution = PathResolution::new(Def::Mod(did)); self.def_map.insert(directive.id, resolution); } From 6cd43f6ee92fa3a235482fa28c5ac2c799018b8a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 01:46:18 +0000 Subject: [PATCH 142/768] Rename `source` -> `name` in `finalize_import`. --- src/librustc_resolve/resolve_imports.rs | 41 ++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e76a93a6db03a..04702d02555e1 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -571,7 +571,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Failed(err) => return Failed(err), }; - let (source, value_result, type_result) = match directive.subclass { + let (name, value_result, type_result) = match directive.subclass { SingleImport { source, ref value_result, ref type_result, .. } => (source, value_result.get(), type_result.get()), GlobImport { .. } if module.def_id() == directive.parent.def_id() => { @@ -584,34 +584,34 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { if let Ok(binding) = result { - self.record_use(source, ns, binding); + self.record_use(name, ns, binding); } } if value_result.is_err() && type_result.is_err() { let (value_result, type_result); - value_result = self.resolve_name_in_module(module, source, ValueNS, false, Some(span)); - type_result = self.resolve_name_in_module(module, source, TypeNS, false, Some(span)); + value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span)); + type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span)); return if let (Failed(_), Failed(_)) = (value_result, type_result) { let resolutions = module.resolutions.borrow(); - let names = resolutions.iter().filter_map(|(&(ref name, _), resolution)| { - if *name == source { return None; } // Never suggest the same name + let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| { + if *n == name { return None; } // Never suggest the same name match *resolution.borrow() { - NameResolution { binding: Some(_), .. } => Some(name), + NameResolution { binding: Some(_), .. } => Some(n), NameResolution { single_imports: SingleImports::None, .. } => None, - _ => Some(name), + _ => Some(n), } }); - let lev_suggestion = match find_best_match_for_name(names, &source.as_str(), None) { + let lev_suggestion = match find_best_match_for_name(names, &name.as_str(), None) { Some(name) => format!(". Did you mean to use `{}`?", name), None => "".to_owned(), }; let module_str = module_to_string(module); let msg = if &module_str == "???" { - format!("There is no `{}` in the crate root{}", source, lev_suggestion) + format!("There is no `{}` in the crate root{}", name, lev_suggestion) } else { - format!("There is no `{}` in `{}`{}", source, module_str, lev_suggestion) + format!("There is no `{}` in `{}`{}", name, module_str, lev_suggestion) }; Failed(Some((directive.span, msg))) } else { @@ -623,9 +623,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { match (value_result, type_result) { (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - let msg = format!("`{}` is private, and cannot be reexported", source); - let note_msg = format!("consider marking `{}` as `pub` in the imported module", - source); + let msg = format!("`{}` is private, and cannot be reexported", name); + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", name); struct_span_err!(self.session, directive.span, E0364, "{}", &msg) .span_note(directive.span, ¬e_msg) .emit(); @@ -635,15 +635,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if binding.is_extern_crate() { let msg = format!("extern crate `{}` is private, and cannot be reexported \ (error E0364), consider declaring with `pub`", - source); + name); self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); } else { - let mut err = struct_span_err!(self.session, directive.span, E0365, - "`{}` is private, and cannot be reexported", - source); - err.span_label(directive.span, &format!("reexport of private `{}`", source)); - err.note(&format!("consider declaring type or module `{}` with `pub`", source)); - err.emit(); + struct_span_err!(self.session, directive.span, E0365, + "`{}` is private, and cannot be reexported", name) + .span_label(directive.span, &format!("reexport of private `{}`", name)) + .note(&format!("consider declaring type or module `{}` with `pub`", name)) + .emit(); } } From cc079c3af2624066686c2941f65f07f3aa609d23 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 03:39:48 +0000 Subject: [PATCH 143/768] Refactor away `ImportResolvingError`. --- src/librustc_resolve/resolve_imports.rs | 40 +++++++------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 04702d02555e1..bde175bcd6f19 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -342,12 +342,6 @@ impl<'a> Resolver<'a> { } } -struct ImportResolvingError<'a> { - import_directive: &'a ImportDirective<'a>, - span: Span, - help: String, -} - struct ImportResolver<'a, 'b: 'a> { resolver: &'a mut Resolver<'b>, } @@ -416,34 +410,33 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.finalize_resolutions_in(module); } - let mut errors = Vec::new(); + let mut errors = false; for i in 0 .. self.determined_imports.len() { let import = self.determined_imports[i]; if let Failed(err) = self.finalize_import(import) { + errors = true; let (span, help) = match err { Some((span, msg)) => (span, format!(". {}", msg)), None => (import.span, String::new()), }; - errors.push(ImportResolvingError { - import_directive: import, - span: span, - help: help, - }); + + // If the error is a single failed import then create a "fake" import + // resolution for it so that later resolve stages won't complain. + self.import_dummy_binding(import); + let path = import_path_to_string(&import.module_path, &import.subclass); + let error = ResolutionError::UnresolvedImport(Some((&path, &help))); + resolve_error(self.resolver, span, error); } } // Report unresolved imports only if no hard error was already reported // to avoid generating multiple errors on the same import. - if errors.len() == 0 { + if !errors { if let Some(import) = self.indeterminate_imports.iter().next() { let error = ResolutionError::UnresolvedImport(None); resolve_error(self.resolver, import.span, error); } } - - for e in errors { - self.import_resolving_error(e) - } } // Define a "dummy" resolution containing a Def::Err as a placeholder for a @@ -462,19 +455,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - /// Resolves an `ImportResolvingError` into the correct enum discriminant - /// and passes that on to `resolve_error`. - fn import_resolving_error(&mut self, e: ImportResolvingError<'b>) { - // If the error is a single failed import then create a "fake" import - // resolution for it so that later resolve stages won't complain. - self.import_dummy_binding(e.import_directive); - let path = import_path_to_string(&e.import_directive.module_path, - &e.import_directive.subclass); - resolve_error(self.resolver, - e.span, - ResolutionError::UnresolvedImport(Some((&path, &e.help)))); - } - /// Attempts to resolve the given import. The return value indicates /// failure if we're certain the name does not exist, indeterminate if we /// don't know whether the name exists at the moment due to other From 951d3d6872daa1db11a7678606a5a9791220fb1d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 02:00:47 +0000 Subject: [PATCH 144/768] Fix fallout in tests. --- src/test/compile-fail/task-rng-isnt-sendable.rs | 1 - src/test/compile-fail/use-from-trait-xc.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index a11df776e06d3..9c0a2267d7cf8 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -16,5 +16,4 @@ fn test_send() {} pub fn main() { test_send::(); - //~^ ERROR : std::marker::Send` is not satisfied } diff --git a/src/test/compile-fail/use-from-trait-xc.rs b/src/test/compile-fail/use-from-trait-xc.rs index 687cdba1542bd..a40fa2337214e 100644 --- a/src/test/compile-fail/use-from-trait-xc.rs +++ b/src/test/compile-fail/use-from-trait-xc.rs @@ -21,10 +21,10 @@ use use_from_trait_xc::Trait::Assoc; use use_from_trait_xc::Trait::CONST; //~^ ERROR `CONST` is not directly importable -use use_from_trait_xc::Foo::new; +use use_from_trait_xc::Foo::new; //~ ERROR struct `Foo` is private //~^ ERROR unresolved import `use_from_trait_xc::Foo::new` -use use_from_trait_xc::Foo::C; +use use_from_trait_xc::Foo::C; //~ ERROR struct `Foo` is private //~^ ERROR unresolved import `use_from_trait_xc::Foo::C` use use_from_trait_xc::Bar::new as bnew; From a6e8f3ba8332cc4a7c32a64cf0df6f67b32a3dd3 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 05:39:32 +0000 Subject: [PATCH 145/768] Add type `Determinacy`. --- src/librustc_resolve/resolve_imports.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index bde175bcd6f19..c0a9ee1c48380 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use self::Determinacy::*; use self::ImportDirectiveSubclass::*; use Module; @@ -36,14 +37,20 @@ impl<'a> Resolver<'a> { } } +#[derive(Copy, Clone, Debug)] +pub enum Determinacy { + Determined, + Undetermined, +} + /// Contains data for specific types of import directives. #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { SingleImport { target: Name, source: Name, - value_result: Cell, bool /* determined? */>>, - type_result: Cell, bool /* determined? */>>, + value_result: Cell, Determinacy>>, + type_result: Cell, Determinacy>>, }, GlobImport { is_prelude: bool }, } @@ -53,8 +60,8 @@ impl<'a> ImportDirectiveSubclass<'a> { SingleImport { target: target, source: source, - type_result: Cell::new(Err(false)), - value_result: Cell::new(Err(false)), + type_result: Cell::new(Err(Undetermined)), + value_result: Cell::new(Err(Undetermined)), } } } @@ -497,12 +504,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let mut indeterminate = false; for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - if let Err(false) = result.get() { + if let Err(Undetermined) = result.get() { result.set({ match self.resolve_name_in_module(module, source, ns, false, None) { Success(binding) => Ok(binding), - Indeterminate => Err(false), - Failed(_) => Err(true), + Indeterminate => Err(Undetermined), + Failed(_) => Err(Determined), } }); } else { @@ -510,8 +517,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; match result.get() { - Err(false) => indeterminate = true, - Err(true) => { + Err(Undetermined) => indeterminate = true, + Err(Determined) => { self.update_resolution(directive.parent, target, ns, |_, resolution| { resolution.single_imports.directive_failed() }); From c2b6f7211472d5e1321e9836f5b339aec1d916d8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 17 Aug 2016 22:56:43 -0400 Subject: [PATCH 146/768] Add a few doc examples for `std::ffi::OsStr`. * `std::ffi::OsStr::new`. * `std::ffi::OsStr::is_empty`. * `std::ffi::OsStr::len`. --- src/libstd/ffi/os_str.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 0d29e62485abb..3d23a9a2383ff 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -251,6 +251,14 @@ impl Hash for OsString { impl OsStr { /// Coerces into an `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &OsStr { s.as_ref() @@ -283,6 +291,18 @@ impl OsStr { } /// Checks whether the `OsStr` is empty. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new(""); + /// assert!(os_str.is_empty()); + /// + /// let os_str = OsStr::new("foo"); + /// assert!(!os_str.is_empty()); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn is_empty(&self) -> bool { self.inner.inner.is_empty() @@ -296,6 +316,18 @@ impl OsStr { /// other methods like `OsString::with_capacity` to avoid reallocations. /// /// See `OsStr` introduction for more information about encoding. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new(""); + /// assert_eq!(os_str.len(), 0); + /// + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_str.len(), 3); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn len(&self) -> usize { self.inner.inner.len() From de91872a3337dddf9a0d27df7bfb64f3965c81b0 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 13 Aug 2016 14:42:36 -0400 Subject: [PATCH 147/768] Add a FusedIterator trait. This trait can be used to avoid the overhead of a fuse wrapper when an iterator is already well-behaved. Conforming to: RFC 1581 Closes: #35602 --- src/liballoc/boxed.rs | 4 + src/liballoc/lib.rs | 2 +- src/libcollections/binary_heap.rs | 11 ++- src/libcollections/btree/map.rs | 27 +++++- src/libcollections/btree/set.rs | 21 ++++- src/libcollections/enum_set.rs | 5 +- src/libcollections/lib.rs | 1 + src/libcollections/linked_list.rs | 11 ++- src/libcollections/str.rs | 4 + src/libcollections/string.rs | 5 +- src/libcollections/vec.rs | 8 +- src/libcollections/vec_deque.rs | 15 +++- src/libcore/char.rs | 18 ++++ src/libcore/iter/mod.rs | 130 +++++++++++++++++++++++++++-- src/libcore/iter/range.rs | 24 +++++- src/libcore/iter/sources.rs | 11 ++- src/libcore/iter/traits.rs | 16 ++++ src/libcore/option.rs | 14 +++- src/libcore/result.rs | 10 +++ src/libcore/slice.rs | 25 ++++++ src/libcore/str/mod.rs | 25 +++++- src/librustc_unicode/char.rs | 6 ++ src/librustc_unicode/lib.rs | 1 + src/librustc_unicode/u_str.rs | 9 +- src/libstd/ascii.rs | 4 + src/libstd/collections/hash/map.rs | 17 +++- src/libstd/collections/hash/set.rs | 28 ++++++- src/libstd/lib.rs | 1 + src/libstd/path.rs | 8 +- 29 files changed, 437 insertions(+), 24 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 7ba5ca30941f4..dae12f6e8bdf7 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -61,6 +61,7 @@ use core::borrow; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; +use core::iter::FusedIterator; use core::marker::{self, Unsize}; use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; @@ -529,6 +530,9 @@ impl DoubleEndedIterator for Box { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Box {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Box {} + /// `FnBox` is a version of the `FnOnce` intended for use with boxed /// closure objects. The idea is that where one would normally store a diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0293d5402c4c9..90037f813cda6 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -91,7 +91,7 @@ #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(unsize)] -#![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))] +#![cfg_attr(not(test), feature(fused, raw, fn_traits, placement_new_protocol))] #![cfg_attr(test, feature(test, box_heap))] // Allow testing this library diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b9f5c6fcab909..42b29fa6e44ee 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -152,7 +152,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::ops::{Drop, Deref, DerefMut}; -use core::iter::FromIterator; +use core::iter::{FromIterator, FusedIterator}; use core::mem::swap; use core::mem::size_of; use core::ptr; @@ -981,6 +981,9 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + /// An iterator that moves out of a `BinaryHeap`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -1014,6 +1017,9 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + /// An iterator that drains a `BinaryHeap`. #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { @@ -1046,6 +1052,9 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl From> for BinaryHeap { fn from(vec: Vec) -> BinaryHeap { diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index c3a7d4023754a..7b09cd2115d58 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -11,7 +11,7 @@ use core::cmp::Ordering; use core::fmt::Debug; use core::hash::{Hash, Hasher}; -use core::iter::{FromIterator, Peekable}; +use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; use core::ops::Index; use core::{fmt, intrinsics, mem, ptr}; @@ -1147,6 +1147,9 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} + impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { if self.length == 0 { @@ -1216,6 +1219,9 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} + impl IntoIterator for BTreeMap { type Item = (K, V); type IntoIter = IntoIter; @@ -1338,6 +1344,9 @@ impl ExactSizeIterator for IntoIter { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + impl<'a, K, V> Iterator for Keys<'a, K, V> { type Item = &'a K; @@ -1362,6 +1371,9 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} + impl<'a, K, V> Clone for Keys<'a, K, V> { fn clone(&self) -> Keys<'a, K, V> { Keys { inner: self.inner.clone() } @@ -1392,6 +1404,9 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Values<'a, K, V> {} + impl<'a, K, V> Clone for Values<'a, K, V> { fn clone(&self) -> Values<'a, K, V> { Values { inner: self.inner.clone() } @@ -1437,6 +1452,10 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} + + impl<'a, K, V> Range<'a, K, V> { unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { let handle = self.front; @@ -1511,6 +1530,9 @@ impl<'a, K, V> Range<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Range<'a, K, V> {} + impl<'a, K, V> Clone for Range<'a, K, V> { fn clone(&self) -> Range<'a, K, V> { Range { @@ -1574,6 +1596,9 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} + impl<'a, K, V> RangeMut<'a, K, V> { unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { let handle = ptr::read(&self.back); diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 0f885bc2950a6..5d7b00f57c83b 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -15,7 +15,7 @@ use core::cmp::Ordering::{self, Less, Greater, Equal}; use core::cmp::{min, max}; use core::fmt::Debug; use core::fmt; -use core::iter::{Peekable, FromIterator}; +use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub}; use borrow::Borrow; @@ -805,6 +805,8 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { @@ -828,6 +830,8 @@ impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} impl<'a, T> Clone for Range<'a, T> { fn clone(&self) -> Range<'a, T> { @@ -847,6 +851,9 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Range<'a, T> {} + /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { match (x, y) { @@ -890,6 +897,9 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} + impl<'a, T> Clone for SymmetricDifference<'a, T> { fn clone(&self) -> SymmetricDifference<'a, T> { SymmetricDifference { @@ -920,6 +930,9 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} + impl<'a, T> Clone for Intersection<'a, T> { fn clone(&self) -> Intersection<'a, T> { Intersection { @@ -960,6 +973,9 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} + impl<'a, T> Clone for Union<'a, T> { fn clone(&self) -> Union<'a, T> { Union { @@ -991,3 +1007,6 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { (max(a_len, b_len), Some(a_len + b_len)) } } + +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 0c66c0564c3ea..2456a04e40a3a 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -20,7 +20,7 @@ use core::marker; use core::fmt; -use core::iter::FromIterator; +use core::iter::{FromIterator, FusedIterator}; use core::ops::{Sub, BitOr, BitAnd, BitXor}; // FIXME(contentions): implement union family of methods? (general design may be @@ -266,6 +266,9 @@ impl Iterator for Iter { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Iter {} + impl FromIterator for EnumSet { fn from_iter>(iter: I) -> EnumSet { let mut ret = EnumSet::new(); diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 21387a1aa9554..2781059c1d543 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -37,6 +37,7 @@ #![feature(core_intrinsics)] #![feature(dropck_parametricity)] #![feature(fmt_internals)] +#![feature(fused)] #![feature(heap_api)] #![feature(inclusive_range)] #![feature(lang_items)] diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 6842f02e0e19b..1f52af9f913e9 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -19,7 +19,7 @@ use alloc::boxed::{Box, IntermediateBox}; use core::cmp::Ordering; use core::fmt; use core::hash::{Hasher, Hash}; -use core::iter::FromIterator; +use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem; use core::ops::{BoxPlace, InPlace, Place, Placer}; @@ -757,6 +757,9 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; @@ -801,6 +804,9 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for IterMut<'a, T> {} + impl<'a, T> IterMut<'a, T> { /// Inserts the given element just after the element most recently returned by `.next()`. /// The inserted element does not appear in the iteration. @@ -908,6 +914,9 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for LinkedList { fn from_iter>(iter: I) -> Self { diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 4c64019de097e..999c84ba70538 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -23,6 +23,7 @@ use core::str as core_str; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; +use core::iter::FusedIterator; use rustc_unicode::str::{UnicodeStr, Utf16Encoder}; use vec_deque::VecDeque; @@ -136,6 +137,9 @@ impl<'a> Iterator for EncodeUtf16<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for EncodeUtf16<'a> {} + // Return the initial codepoint accumulator for the first byte. // The first byte is special, only want bottom 5 bits for width 2, 4 bits // for width 3, and 3 bits for width 4 diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 788c838cd3fc8..d4de726cfafd6 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -57,7 +57,7 @@ use core::fmt; use core::hash; -use core::iter::FromIterator; +use core::iter::{FromIterator, FusedIterator}; use core::mem; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; @@ -1995,3 +1995,6 @@ impl<'a> DoubleEndedIterator for Drain<'a> { self.iter.next_back() } } + +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Drain<'a> {} diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 522890a2e2682..a866cdeb7ec3e 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -68,7 +68,7 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; -use core::iter::FromIterator; +use core::iter::{FromIterator, FusedIterator}; use core::mem; use core::ops::{Index, IndexMut}; use core::ops; @@ -1845,6 +1845,9 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { fn clone(&self) -> IntoIter { @@ -1932,3 +1935,6 @@ impl<'a, T> Drop for Drain<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Drain<'a, T> {} + +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Drain<'a, T> {} diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 812a67a7e78ed..57e00576e45f4 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -20,7 +20,7 @@ use core::cmp::Ordering; use core::fmt; -use core::iter::{repeat, FromIterator}; +use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::{Index, IndexMut}; use core::ptr; @@ -1894,6 +1894,10 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + + /// `VecDeque` mutable iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { @@ -1946,6 +1950,9 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for IterMut<'a, T> {} + /// A by-value VecDeque iterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] @@ -1980,6 +1987,9 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + /// A draining VecDeque iterator #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { @@ -2069,6 +2079,9 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for VecDeque { fn eq(&self, other: &VecDeque) -> bool { diff --git a/src/libcore/char.rs b/src/libcore/char.rs index a3440fe8aa644..98b7632a220dd 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -18,6 +18,7 @@ use prelude::v1::*; use char_private::is_printable; +use iter::FusedIterator; use mem::transmute; // UTF-8 ranges and tags for encoding characters @@ -516,6 +517,9 @@ impl ExactSizeIterator for EscapeUnicode { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EscapeUnicode {} + /// An iterator that yields the literal escape code of a `char`. /// /// This `struct` is created by the [`escape_default()`] method on [`char`]. See @@ -616,6 +620,9 @@ impl ExactSizeIterator for EscapeDefault { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EscapeDefault {} + /// An iterator that yields the literal escape code of a `char`. /// /// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its @@ -637,6 +644,9 @@ impl Iterator for EscapeDebug { #[unstable(feature = "char_escape_debug", issue = "35068")] impl ExactSizeIterator for EscapeDebug { } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EscapeDebug {} + /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. /// @@ -675,6 +685,9 @@ impl Iterator for EncodeUtf8 { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EncodeUtf8 {} + /// An iterator over `u16` entries represending the UTF-16 encoding of a `char` /// value. /// @@ -714,6 +727,8 @@ impl Iterator for EncodeUtf16 { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EncodeUtf16 {} /// An iterator over an iterator of bytes of the characters the bytes represent /// as UTF-8 @@ -760,3 +775,6 @@ impl> Iterator for DecodeUtf8 { }) } } + +#[unstable(feature = "fused", issue = "35602")] +impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index d2de0d46d746b..cfe117c0b1d69 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -330,6 +330,8 @@ pub use self::sources::{Once, once}; pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Sum, Product}; +#[unstable(feature = "fused", issue = "35602")] +pub use self::traits::FusedIterator; mod iterator; mod range; @@ -370,6 +372,10 @@ impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { impl ExactSizeIterator for Rev where I: ExactSizeIterator + DoubleEndedIterator {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Rev + where I: FusedIterator + DoubleEndedIterator {} + /// An iterator that clones the elements of an underlying iterator. /// /// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its @@ -413,6 +419,11 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned where I: ExactSizeIterator, T: Clone {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, I, T: 'a> FusedIterator for Cloned + where I: FusedIterator, T: Clone +{} + /// An iterator that repeats endlessly. /// /// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its @@ -451,6 +462,9 @@ impl Iterator for Cycle where I: Clone + Iterator { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Cycle where I: Clone + Iterator {} + /// An iterator that strings two iterators together. /// /// This `struct` is created by the [`chain()`] method on [`Iterator`]. See its @@ -613,6 +627,13 @@ impl DoubleEndedIterator for Chain where } } +// Note: *both* must be fused to handle double-ended iterators. +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Chain + where A: FusedIterator, + B: FusedIterator, +{} + /// An iterator that iterates two other iterators simultaneously. /// /// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its @@ -823,6 +844,10 @@ unsafe impl TrustedRandomAccess for Zip } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Zip + where A: FusedIterator, B: FusedIterator, {} + /// An iterator that maps the values of `iter` with `f`. /// /// This `struct` is created by the [`map()`] method on [`Iterator`]. See its @@ -919,6 +944,10 @@ impl DoubleEndedIterator for Map where impl ExactSizeIterator for Map where F: FnMut(I::Item) -> B {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Map + where F: FnMut(I::Item) -> B {} + /// An iterator that filters the elements of `iter` with `predicate`. /// /// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its @@ -979,6 +1008,10 @@ impl DoubleEndedIterator for Filter } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Filter + where P: FnMut(&I::Item) -> bool {} + /// An iterator that uses `f` to both filter and map elements from `iter`. /// /// This `struct` is created by the [`filter_map()`] method on [`Iterator`]. See its @@ -1041,6 +1074,10 @@ impl DoubleEndedIterator for FilterMap } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for FilterMap + where F: FnMut(I::Item) -> Option {} + /// An iterator that yields the current count and the element during iteration. /// /// This `struct` is created by the [`enumerate()`] method on [`Iterator`]. See its @@ -1128,6 +1165,9 @@ unsafe impl TrustedRandomAccess for Enumerate } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Enumerate where I: FusedIterator {} + /// An iterator with a `peek()` that returns an optional reference to the next /// element. /// @@ -1195,6 +1235,9 @@ impl Iterator for Peekable { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Peekable {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Peekable {} + impl Peekable { /// Returns a reference to the next() value without advancing the iterator. /// @@ -1296,6 +1339,10 @@ impl Iterator for SkipWhile } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for SkipWhile + where I: FusedIterator, P: FnMut(&I::Item) -> bool {} + /// An iterator that only accepts elements while `predicate` is true. /// /// This `struct` is created by the [`take_while()`] method on [`Iterator`]. See its @@ -1351,6 +1398,10 @@ impl Iterator for TakeWhile } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for TakeWhile + where I: FusedIterator, P: FnMut(&I::Item) -> bool {} + /// An iterator that skips over `n` elements of `iter`. /// /// This `struct` is created by the [`skip()`] method on [`Iterator`]. See its @@ -1442,6 +1493,9 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Skip where I: FusedIterator {} + /// An iterator that only iterates over the first `n` iterations of `iter`. /// /// This `struct` is created by the [`take()`] method on [`Iterator`]. See its @@ -1503,6 +1557,8 @@ impl Iterator for Take where I: Iterator{ #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Take where I: FusedIterator {} /// An iterator to maintain state while iterating another iterator. /// @@ -1549,6 +1605,10 @@ impl Iterator for Scan where } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Scan + where I: FusedIterator, F: FnMut(&mut St, I::Item) -> Option {} + /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// @@ -1635,6 +1695,10 @@ impl DoubleEndedIterator for FlatMap wher } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for FlatMap + where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} + /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// @@ -1651,12 +1715,15 @@ pub struct Fuse { done: bool } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Fuse where I: Iterator {} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Fuse where I: Iterator { type Item = ::Item; #[inline] - fn next(&mut self) -> Option<::Item> { + default fn next(&mut self) -> Option<::Item> { if self.done { None } else { @@ -1667,7 +1734,7 @@ impl Iterator for Fuse where I: Iterator { } #[inline] - fn nth(&mut self, n: usize) -> Option { + default fn nth(&mut self, n: usize) -> Option { if self.done { None } else { @@ -1678,7 +1745,7 @@ impl Iterator for Fuse where I: Iterator { } #[inline] - fn last(self) -> Option { + default fn last(self) -> Option { if self.done { None } else { @@ -1687,7 +1754,7 @@ impl Iterator for Fuse where I: Iterator { } #[inline] - fn count(self) -> usize { + default fn count(self) -> usize { if self.done { 0 } else { @@ -1696,7 +1763,7 @@ impl Iterator for Fuse where I: Iterator { } #[inline] - fn size_hint(&self) -> (usize, Option) { + default fn size_hint(&self) -> (usize, Option) { if self.done { (0, Some(0)) } else { @@ -1708,7 +1775,7 @@ impl Iterator for Fuse where I: Iterator { #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { #[inline] - fn next_back(&mut self) -> Option<::Item> { + default fn next_back(&mut self) -> Option<::Item> { if self.done { None } else { @@ -1719,6 +1786,53 @@ impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { } } +unsafe impl TrustedRandomAccess for Fuse + where I: TrustedRandomAccess, +{ + unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { + self.iter.get_unchecked(i) + } +} + +#[unstable(feature = "fused", issue = "35602")] +impl Iterator for Fuse where I: FusedIterator { + #[inline] + fn next(&mut self) -> Option<::Item> { + self.iter.next() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "fused", reason = "recently added", issue = "35602")] +impl DoubleEndedIterator for Fuse + where I: DoubleEndedIterator + FusedIterator +{ + #[inline] + fn next_back(&mut self) -> Option<::Item> { + self.iter.next_back() + } +} + + #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Fuse where I: ExactSizeIterator {} @@ -1788,3 +1902,7 @@ impl DoubleEndedIterator for Inspect #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Inspect where F: FnMut(&I::Item) {} + +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Inspect + where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 079dfe2a81f80..48816bf66bbb7 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -16,7 +16,7 @@ use option::Option::{self, Some, None}; use marker::Sized; use usize; -use super::{DoubleEndedIterator, ExactSizeIterator, Iterator}; +use super::{DoubleEndedIterator, ExactSizeIterator, Iterator, FusedIterator}; /// Objects that can be stepped over in both directions. /// @@ -364,6 +364,10 @@ impl Iterator for StepBy> where } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for StepBy> + where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for StepBy> { type Item = A; @@ -401,6 +405,9 @@ impl Iterator for StepBy> { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for StepBy> {} + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -468,6 +475,9 @@ impl Iterator for StepBy> { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for StepBy> {} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -526,6 +536,10 @@ impl DoubleEndedIterator for ops::Range where } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for ops::Range + where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for ops::RangeFrom where for<'a> &'a A: Add<&'a A, Output = A> @@ -540,6 +554,10 @@ impl Iterator for ops::RangeFrom where } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for ops::RangeFrom + where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {} + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] impl Iterator for ops::RangeInclusive where for<'a> &'a A: Add<&'a A, Output = A> @@ -638,3 +656,7 @@ impl DoubleEndedIterator for ops::RangeInclusive where n } } + +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for ops::RangeInclusive + where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index ecd4a78b9e760..a2a019a07dcf1 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -15,7 +15,7 @@ use marker; use option::Option::{self, Some, None}; use usize; -use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator}; +use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator, FusedIterator}; /// An iterator that repeats an element endlessly. /// @@ -44,6 +44,9 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Repeat {} + /// Creates a new iterator that endlessly repeats a single element. /// /// The `repeat()` function repeats a single value over and over and over and @@ -138,6 +141,9 @@ impl ExactSizeIterator for Empty { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Empty {} + // not #[derive] because that adds a Clone bound on T, // which isn't necessary. #[stable(feature = "iter_empty", since = "1.2.0")] @@ -213,6 +219,9 @@ impl ExactSizeIterator for Once { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Once {} + /// Creates an iterator that yields an element exactly once. /// /// This is commonly used to adapt a single value into a [`chain()`] of other diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 4cbabe3f5edaf..0b6ab5a4bbb14 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -658,3 +658,19 @@ macro_rules! float_sum_product { integer_sum_product! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } float_sum_product! { f32 f64 } + +/// An iterator that always continues to yield `None` when exhausted. +/// +/// Calling next on a fused iterator that has returned `None` once is guaranteed +/// to return `None` again. This trait is should be implemented by all iterators +/// that behave this way because it allows for some significant optimizations. +/// +/// Note: In general, you should not use `FusedIterator` in generic bounds if +/// you need a fused iterator. Instead, you should just call `Iterator::fused()` +/// on the iterator. If the iterator is already fused, the additional `Fuse` +/// wrapper will be a no-op with no performance penalty. +#[unstable(feature = "fused", issue = "35602")] +pub trait FusedIterator: Iterator {} + +#[unstable(feature = "fused", issue = "35602")] +impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index fe508adb71380..51bbad085fba4 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -144,8 +144,8 @@ use self::Option::*; use clone::Clone; use convert::From; use default::Default; -use iter::ExactSizeIterator; -use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator}; +use iter::{Iterator, FromIterator, IntoIterator, ExactSizeIterator, DoubleEndedIterator}; +use iter::FusedIterator; use mem; use ops::FnOnce; use result::Result::{Ok, Err}; @@ -796,6 +796,7 @@ impl DoubleEndedIterator for Item { } impl ExactSizeIterator for Item {} +impl FusedIterator for Item {} /// An iterator over a reference of the contained item in an Option. #[stable(feature = "rust1", since = "1.0.0")] @@ -821,6 +822,9 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for Iter<'a, A> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, A> FusedIterator for Iter<'a, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> Clone for Iter<'a, A> { fn clone(&self) -> Iter<'a, A> { @@ -852,6 +856,9 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, A> FusedIterator for IterMut<'a, A> {} + /// An iterator over the item contained inside an Option. #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -876,6 +883,9 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c7ca70fc1622d..718fdf865a970 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -241,6 +241,7 @@ use self::Result::{Ok, Err}; use clone::Clone; use fmt; use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator}; +use iter::FusedIterator; use ops::FnOnce; use option::Option::{self, None, Some}; @@ -869,6 +870,9 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } } @@ -901,6 +905,9 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for IterMut<'a, T> {} + /// An iterator over the value in a `Ok` variant of a `Result`. #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -928,6 +935,9 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 3a820a14f1214..603f55a6e108e 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -992,6 +992,9 @@ iterator!{struct Iter -> *const T, &'a T} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } } @@ -1110,6 +1113,9 @@ iterator!{struct IterMut -> *mut T, &'a mut T} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for IterMut<'a, T> {} + /// An internal abstraction over the splitting iterators, so that /// splitn, splitn_mut etc can be implemented once. #[doc(hidden)] @@ -1202,6 +1208,9 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {} + /// An iterator over the subslices of the vector which are separated /// by elements that match `pred`. #[stable(feature = "rust1", since = "1.0.0")] @@ -1292,6 +1301,9 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} + /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. @@ -1408,6 +1420,10 @@ macro_rules! forward_iterator { self.inner.size_hint() } } + + #[unstable(feature = "fused", issue = "35602")] + impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> + where P: FnMut(&T) -> bool {} } } @@ -1506,6 +1522,9 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Windows<'a, T> {} + /// An iterator over a slice in (non-overlapping) chunks (`size` elements at a /// time). /// @@ -1609,6 +1628,9 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for Chunks<'a, T> {} + /// An iterator over a slice in (non-overlapping) mutable chunks (`size` /// elements at a time). When the slice len is not evenly divided by the chunk /// size, the last slice of the iteration will be the remainder. @@ -1704,6 +1726,9 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T> FusedIterator for ChunksMut<'a, T> {} + // // Free functions // diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index fdcadd43a0fb6..e18aa07b75d8e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -23,7 +23,7 @@ use convert::AsRef; use default::Default; use fmt; use iter::ExactSizeIterator; -use iter::{Map, Cloned, Iterator, DoubleEndedIterator}; +use iter::{Map, Cloned, Iterator, DoubleEndedIterator, FusedIterator}; use marker::Sized; use mem; use ops::{Fn, FnMut, FnOnce}; @@ -454,6 +454,9 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Chars<'a> {} + impl<'a> Chars<'a> { /// View the underlying data as a subslice of the original data. /// @@ -525,6 +528,9 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for CharIndices<'a> {} + impl<'a> CharIndices<'a> { /// View the underlying data as a subslice of the original data. /// @@ -593,6 +599,9 @@ impl<'a> ExactSizeIterator for Bytes<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Bytes<'a> {} + /// This macro generates a Clone impl for string pattern API /// wrapper types of the form X<'a, P> macro_rules! derive_pattern_clone { @@ -739,6 +748,13 @@ macro_rules! generate_pattern_iterators { } } + #[unstable(feature = "fused", issue = "35602")] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + + #[unstable(feature = "fused", issue = "35602")] + impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> + where P::Searcher: ReverseSearcher<'a> {} + generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, $forward_iterator, $reverse_iterator, $iterty); @@ -1088,6 +1104,9 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Lines<'a> {} + /// Created with the method [`lines_any()`]. /// /// [`lines_any()`]: ../../std/primitive.str.html#method.lines_any @@ -1151,6 +1170,10 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +#[allow(deprecated)] +impl<'a> FusedIterator for LinesAny<'a> {} + /* Section: Comparing strings */ diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 81856cb87c7c4..c2b7d7045ddd8 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -29,6 +29,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::char::CharExt as C; +use core::iter::FusedIterator; use core::fmt; use tables::{conversions, derived_property, general_category, property}; @@ -62,6 +63,9 @@ impl Iterator for ToLowercase { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for ToLowercase {} + /// Returns an iterator that yields the uppercase equivalent of a `char`. /// /// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See @@ -80,6 +84,8 @@ impl Iterator for ToUppercase { } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for ToUppercase {} enum CaseMappingIter { Three(char, char, char), diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index 3ae905eba279b..b812c262ac197 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -35,6 +35,7 @@ #![feature(char_escape_debug)] #![feature(core_char_ext)] #![feature(decode_utf8)] +#![feature(fused)] #![feature(lang_items)] #![feature(staged_api)] #![feature(unicode)] diff --git a/src/librustc_unicode/u_str.rs b/src/librustc_unicode/u_str.rs index 0bac44b837ff2..eb5b6feeb7ec4 100644 --- a/src/librustc_unicode/u_str.rs +++ b/src/librustc_unicode/u_str.rs @@ -14,7 +14,7 @@ //! methods provided by the unicode parts of the CharExt trait. use core::char; -use core::iter::Filter; +use core::iter::{Filter, FusedIterator}; use core::str::Split; /// An iterator over the non-whitespace substrings of a string, @@ -177,6 +177,10 @@ impl Iterator for Utf16Encoder } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Utf16Encoder + where I: FusedIterator {} + impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; @@ -189,3 +193,6 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { self.inner.next_back() } } + +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 0db91034eb5ac..070d7ca1eef0f 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -16,6 +16,7 @@ use prelude::v1::*; use mem; use ops::Range; +use iter::FusedIterator; /// Extension methods for ASCII-subset only operations on string slices. /// @@ -368,6 +369,9 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EscapeDefault {} + static ASCII_LOWERCASE_MAP: [u8; 256] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index cf6f76f914a15..d844a213ce251 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -15,7 +15,7 @@ use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; use hash::{Hash, Hasher, BuildHasher, SipHasher13}; -use iter::FromIterator; +use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; use ops::{Deref, Index}; use rand::{self, Rng}; @@ -1484,6 +1484,9 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); @@ -1495,6 +1498,8 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { @@ -1507,6 +1512,8 @@ impl Iterator for IntoIter { impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Keys<'a, K, V> { @@ -1519,6 +1526,8 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Values<'a, K, V> { @@ -1531,6 +1540,8 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { @@ -1543,6 +1554,8 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Drain<'a, K, V> { @@ -1555,6 +1568,8 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 837c5d8b8e18c..96efff86abf17 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -11,7 +11,7 @@ use borrow::Borrow; use fmt; use hash::{Hash, BuildHasher}; -use iter::{Chain, FromIterator}; +use iter::{Chain, FromIterator, FusedIterator}; use ops::{BitOr, BitAnd, BitXor, Sub}; use super::Recover; @@ -906,6 +906,8 @@ impl<'a, K> Iterator for Iter<'a, K> { impl<'a, K> ExactSizeIterator for Iter<'a, K> { fn len(&self) -> usize { self.iter.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { @@ -918,6 +920,8 @@ impl Iterator for IntoIter { impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K> Iterator for Drain<'a, K> { @@ -930,6 +934,8 @@ impl<'a, K> Iterator for Drain<'a, K> { impl<'a, K> ExactSizeIterator for Drain<'a, K> { fn len(&self) -> usize { self.iter.len() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Intersection<'a, T, S> { @@ -961,6 +967,11 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T, S> FusedIterator for Intersection<'a, T, S> + where T: Eq + Hash, S: BuildHasher +{} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Difference<'a, T, S> { fn clone(&self) -> Difference<'a, T, S> { @@ -991,6 +1002,11 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T, S> FusedIterator for Difference<'a, T, S> + where T: Eq + Hash, S: BuildHasher +{} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { fn clone(&self) -> SymmetricDifference<'a, T, S> { @@ -1008,11 +1024,21 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> + where T: Eq + Hash, S: BuildHasher +{} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Union<'a, T, S> { fn clone(&self) -> Union<'a, T, S> { Union { iter: self.iter.clone() } } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a, T, S> FusedIterator for Union<'a, T, S> + where T: Eq + Hash, S: BuildHasher +{} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c05e0c3ca68df..9807e383c5ca1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -232,6 +232,7 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] +#![feature(fused)] #![feature(hashmap_hasher)] #![feature(heap_api)] #![feature(inclusive_range)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 2d19561139b58..bc8fd66a438f5 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -107,7 +107,7 @@ use fmt; use fs; use hash::{Hash, Hasher}; use io; -use iter; +use iter::{self, FusedIterator}; use mem; use ops::{self, Deref}; use string::String; @@ -858,6 +858,9 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Iter<'a> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Iterator for Components<'a> { type Item = Component<'a>; @@ -958,6 +961,9 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Components<'a> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> cmp::PartialEq for Components<'a> { fn eq(&self, other: &Components<'a>) -> bool { From 59481823675a7392e8160b659b0f7fa119df60fd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Aug 2016 19:39:12 +0200 Subject: [PATCH 148/768] Add Span field for Generics structs --- src/librustc/hir/fold.rs | 3 +- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/mod.rs | 36 ++--------------------- src/librustc/hir/print.rs | 2 ++ src/librustc/infer/error_reporting.rs | 1 + src/librustc_typeck/lib.rs | 11 ++++--- src/libsyntax/ast.rs | 6 ++-- src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/mod.rs | 5 ++-- src/libsyntax/parse/parser.rs | 8 +++-- src/libsyntax/print/pprust.rs | 2 ++ src/libsyntax_ext/deriving/generic/mod.rs | 3 +- src/libsyntax_ext/deriving/generic/ty.rs | 6 ++-- src/test/compile-fail/E0132.rs | 2 +- 14 files changed, 37 insertions(+), 52 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 0edfd16bdfd1b..0b362bac8882b 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -577,13 +577,14 @@ pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) -> o_lt.map(|lt| fld.fold_lifetime(lt)) } -pub fn noop_fold_generics(Generics { ty_params, lifetimes, where_clause }: Generics, +pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_clause, span}: Generics, fld: &mut T) -> Generics { Generics { ty_params: fld.fold_ty_params(ty_params), lifetimes: fld.fold_lifetime_defs(lifetimes), where_clause: fld.fold_where_clause(where_clause), + span: fld.new_span(span), } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c2b211238b2f1..cb219bbe18ae8 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -466,6 +466,7 @@ impl<'a> LoweringContext<'a> { ty_params: self.lower_ty_params(&g.ty_params), lifetimes: self.lower_lifetime_defs(&g.lifetimes), where_clause: self.lower_where_clause(&g.where_clause), + span: g.span, } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d41cdfabdf4c0..f351384c2b89e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -36,7 +36,7 @@ use hir::def::Def; use hir::def_id::DefId; use util::nodemap::{NodeMap, FnvHashSet}; -use syntax_pos::{BytePos, mk_sp, Span, ExpnId}; +use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, respan, Spanned}; use syntax::abi::Abi; use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect}; @@ -301,6 +301,7 @@ pub struct Generics { pub lifetimes: HirVec, pub ty_params: HirVec, pub where_clause: WhereClause, + pub span: Span, } impl Generics { @@ -312,6 +313,7 @@ impl Generics { id: DUMMY_NODE_ID, predicates: HirVec::new(), }, + span: DUMMY_SP, } } @@ -326,38 +328,6 @@ impl Generics { pub fn is_parameterized(&self) -> bool { self.is_lt_parameterized() || self.is_type_parameterized() } - - // Does return a span which includes lifetimes and type parameters, - // not where clause. - pub fn span(&self) -> Option { - if !self.is_parameterized() { - None - } else { - let mut span: Option = None; - for lifetime in self.lifetimes.iter() { - if let Some(ref mut span) = span { - let life_span = lifetime.lifetime.span; - span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi }; - span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo }; - } else { - span = Some(lifetime.lifetime.span.clone()); - } - } - for ty_param in self.ty_params.iter() { - if let Some(ref mut span) = span { - span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo }; - span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi }; - } else { - span = Some(ty_param.span.clone()); - } - } - if let Some(ref mut span) = span { - span.lo = span.lo - BytePos(1); - span.hi = span.hi + BytePos(1); - } - span - } - } } /// A `where` clause in a definition diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 66c1bc7642c56..1cbead123d871 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -523,6 +523,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: hir::HirVec::new(), }, + span: syntax_pos::DUMMY_SP, }; self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?; } @@ -2224,6 +2225,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: hir::HirVec::new(), }, + span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, unsafety, diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9a6375719c1bc..03ad12d2d99f8 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1293,6 +1293,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { lifetimes: lifetimes.into(), ty_params: ty_params, where_clause: where_clause, + span: generics.span, } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8a8232535c775..b24eb8cba1cf3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -216,10 +216,10 @@ fn check_main_fn_ty(ccx: &CrateCtxt, Some(hir_map::NodeItem(it)) => { match it.node { hir::ItemFn(_, _, _, _, ref generics, _) => { - if let Some(gen_span) = generics.span() { - struct_span_err!(ccx.tcx.sess, gen_span, E0131, + if generics.is_parameterized() { + struct_span_err!(ccx.tcx.sess, generics.span, E0131, "main function is not allowed to have type parameters") - .span_label(gen_span, + .span_label(generics.span, &format!("main cannot have type parameters")) .emit(); return; @@ -269,10 +269,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt, match it.node { hir::ItemFn(_,_,_,_,ref ps,_) if ps.is_parameterized() => { - let sp = if let Some(sp) = ps.span() { sp } else { start_span }; - struct_span_err!(tcx.sess, sp, E0132, + struct_span_err!(tcx.sess, ps.span, E0132, "start function is not allowed to have type parameters") - .span_label(sp, + .span_label(ps.span, &format!("start function cannot have type parameters")) .emit(); return; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..968956d3391a0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -336,7 +336,7 @@ pub struct TyParam { pub id: NodeId, pub bounds: TyParamBounds, pub default: Option>, - pub span: Span + pub span: Span, } /// Represents lifetimes and type parameters attached to a declaration @@ -346,6 +346,7 @@ pub struct Generics { pub lifetimes: Vec, pub ty_params: P<[TyParam]>, pub where_clause: WhereClause, + pub span: Span, } impl Generics { @@ -368,7 +369,8 @@ impl Default for Generics { where_clause: WhereClause { id: DUMMY_NODE_ID, predicates: Vec::new(), - } + }, + span: DUMMY_SP, } } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b257ab98987dc..c566aa5661be0 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -698,12 +698,13 @@ pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) o_lt.map(|lt| fld.fold_lifetime(lt)) } -pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_clause}: Generics, +pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_clause, span}: Generics, fld: &mut T) -> Generics { Generics { ty_params: fld.fold_ty_params(ty_params), lifetimes: fld.fold_lifetime_defs(lifetimes), where_clause: fld.fold_where_clause(where_clause), + span: fld.new_span(span), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d130..eb59a8e24d3fd 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -674,7 +674,7 @@ pub fn integer_lit(s: &str, mod tests { use super::*; use std::rc::Rc; - use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION}; + use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION}; use codemap::Spanned; use ast::{self, PatKind}; use abi::Abi; @@ -945,7 +945,8 @@ mod tests { where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), - } + }, + span: syntax_pos::DUMMY_SP, }, P(ast::Block { stmts: vec!(ast::Stmt { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 126e8816d0559..19f44924067db 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -716,8 +716,8 @@ impl<'a> Parser<'a> { let gt_str = Parser::token_to_string(&token::Gt); let this_token_str = self.this_token_to_string(); Err(self.fatal(&format!("expected `{}`, found `{}`", - gt_str, - this_token_str))) + gt_str, + this_token_str))) } } } @@ -4251,6 +4251,7 @@ impl<'a> Parser<'a> { /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics); + let span_lo = self.span.lo; if self.eat(&token::Lt) { let lifetime_defs = self.parse_lifetime_defs()?; @@ -4273,7 +4274,8 @@ impl<'a> Parser<'a> { where_clause: WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), - } + }, + span: mk_sp(span_lo, self.last_span.hi), }) } else { Ok(ast::Generics::default()) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..22b0bb2c07ad0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1001,6 +1001,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, + span: syntax_pos::DUMMY_SP, }; try!(self.print_ty_fn(f.abi, f.unsafety, @@ -2982,6 +2983,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, + span: syntax_pos::DUMMY_SP, }; try!(self.print_fn(decl, unsafety, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..6773088670f58 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> { } }); - let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics + let Generics { mut lifetimes, ty_params, mut where_clause, span } = self.generics .to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); @@ -590,6 +590,7 @@ impl<'a> TraitDef<'a> { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), where_clause: where_clause, + span: span, }; // Create the reference to the trait. diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 356c54fcf3120..210878b7c9f0e 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -207,7 +207,8 @@ fn mk_ty_param(cx: &ExtCtxt, cx.typaram(span, cx.ident_of(name), bounds, None) } -fn mk_generics(lifetimes: Vec, ty_params: Vec) -> Generics { +fn mk_generics(lifetimes: Vec, ty_params: Vec, span: Span) + -> Generics { Generics { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), @@ -215,6 +216,7 @@ fn mk_generics(lifetimes: Vec, ty_params: Vec) - id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, + span: span, } } @@ -257,7 +259,7 @@ impl<'a> LifetimeBounds<'a> { } }) .collect(); - mk_generics(lifetimes, ty_params) + mk_generics(lifetimes, ty_params, span) } } diff --git a/src/test/compile-fail/E0132.rs b/src/test/compile-fail/E0132.rs index 1a33fb24ca1a1..91ff6b85a42ce 100644 --- a/src/test/compile-fail/E0132.rs +++ b/src/test/compile-fail/E0132.rs @@ -11,7 +11,7 @@ #![feature(start)] #[start] -fn f() {} //~ ERROR E0132 +fn f< T >() {} //~ ERROR E0132 //~| NOTE start function cannot have type parameters fn main() { From 0ff128228f7955c0182689e107416abe7b46b157 Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Mon, 8 Aug 2016 18:46:06 -0700 Subject: [PATCH 149/768] track Location in visitor, combine Location --- src/librustc/mir/repr.rs | 11 + src/librustc/mir/visit.rs | 211 ++++++++++-------- .../borrowck/mir/dataflow/impls.rs | 19 +- .../borrowck/mir/elaborate_drops.rs | 26 +-- .../borrowck/mir/gather_moves.rs | 31 +-- src/librustc_borrowck/borrowck/mir/mod.rs | 6 +- src/librustc_borrowck/borrowck/mir/patch.rs | 9 +- src/librustc_metadata/decoder.rs | 3 +- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/mod.rs | 10 - src/librustc_mir/pretty.rs | 2 +- src/librustc_mir/transform/no_landing_pads.rs | 7 +- src/librustc_mir/transform/promote_consts.rs | 48 ++-- src/librustc_mir/transform/qualify_consts.rs | 83 +++---- src/librustc_mir/transform/type_check.rs | 26 ++- src/librustc_trans/collector.rs | 19 +- src/librustc_trans/mir/analyze.rs | 22 +- .../auxiliary/dummy_mir_pass.rs | 4 +- 18 files changed, 276 insertions(+), 263 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index f511d820fac58..5279d05260896 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1239,3 +1239,14 @@ impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = IntoIter; } + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)] +pub struct Location { + /// the location is within this block + pub block: BasicBlock, + + /// the location is the start of the this statement; or, if `statement_index` + /// == num-statements, then the start of the terminator. + pub statement_index: usize, +} + diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ead8de86dbae4..0a0872b5edafe 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -103,60 +103,70 @@ macro_rules! make_mir_visitor { fn visit_statement(&mut self, block: BasicBlock, - statement: & $($mutability)* Statement<'tcx>) { - self.super_statement(block, statement); + statement: & $($mutability)* Statement<'tcx>, + location: Location) { + self.super_statement(block, statement, location); } fn visit_assign(&mut self, block: BasicBlock, lvalue: & $($mutability)* Lvalue<'tcx>, - rvalue: & $($mutability)* Rvalue<'tcx>) { - self.super_assign(block, lvalue, rvalue); + rvalue: & $($mutability)* Rvalue<'tcx>, + location: Location) { + self.super_assign(block, lvalue, rvalue, location); } fn visit_terminator(&mut self, block: BasicBlock, - terminator: & $($mutability)* Terminator<'tcx>) { - self.super_terminator(block, terminator); + terminator: & $($mutability)* Terminator<'tcx>, + location: Location) { + self.super_terminator(block, terminator, location); } fn visit_terminator_kind(&mut self, block: BasicBlock, - kind: & $($mutability)* TerminatorKind<'tcx>) { - self.super_terminator_kind(block, kind); + kind: & $($mutability)* TerminatorKind<'tcx>, + location: Location) { + self.super_terminator_kind(block, kind, location); } fn visit_assert_message(&mut self, - msg: & $($mutability)* AssertMessage<'tcx>) { - self.super_assert_message(msg); + msg: & $($mutability)* AssertMessage<'tcx>, + location: Location) { + self.super_assert_message(msg, location); } fn visit_rvalue(&mut self, - rvalue: & $($mutability)* Rvalue<'tcx>) { - self.super_rvalue(rvalue); + rvalue: & $($mutability)* Rvalue<'tcx>, + location: Location) { + self.super_rvalue(rvalue, location); } fn visit_operand(&mut self, - operand: & $($mutability)* Operand<'tcx>) { - self.super_operand(operand); + operand: & $($mutability)* Operand<'tcx>, + location: Location) { + self.super_operand(operand, location); } fn visit_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext) { - self.super_lvalue(lvalue, context); + context: LvalueContext, + location: Location) { + self.super_lvalue(lvalue, context, location); } fn visit_projection(&mut self, lvalue: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext) { - self.super_projection(lvalue, context); + context: LvalueContext, + location: Location) { + self.super_projection(lvalue, context, location); } fn visit_projection_elem(&mut self, lvalue: & $($mutability)* LvalueElem<'tcx>, - context: LvalueContext) { - self.super_projection_elem(lvalue, context); + context: LvalueContext, + location: Location) { + self.super_projection_elem(lvalue, context, location); } fn visit_branch(&mut self, @@ -166,17 +176,20 @@ macro_rules! make_mir_visitor { } fn visit_constant(&mut self, - constant: & $($mutability)* Constant<'tcx>) { - self.super_constant(constant); + constant: & $($mutability)* Constant<'tcx>, + location: Location) { + self.super_constant(constant, location); } fn visit_literal(&mut self, - literal: & $($mutability)* Literal<'tcx>) { - self.super_literal(literal); + literal: & $($mutability)* Literal<'tcx>, + location: Location) { + self.super_literal(literal, location); } fn visit_def_id(&mut self, - def_id: & $($mutability)* DefId) { + def_id: & $($mutability)* DefId, + _: Location) { self.super_def_id(def_id); } @@ -206,18 +219,21 @@ macro_rules! make_mir_visitor { } fn visit_const_val(&mut self, - const_val: & $($mutability)* ConstVal) { + const_val: & $($mutability)* ConstVal, + _: Location) { self.super_const_val(const_val); } fn visit_const_usize(&mut self, - const_usize: & $($mutability)* ConstUsize) { + const_usize: & $($mutability)* ConstUsize, + _: Location) { self.super_const_usize(const_usize); } fn visit_typed_const_val(&mut self, - val: & $($mutability)* TypedConstVal<'tcx>) { - self.super_typed_const_val(val); + val: & $($mutability)* TypedConstVal<'tcx>, + location: Location) { + self.super_typed_const_val(val, location); } fn visit_var_decl(&mut self, @@ -280,12 +296,16 @@ macro_rules! make_mir_visitor { is_cleanup: _ } = *data; + let mut index = 0; for statement in statements { - self.visit_statement(block, statement); + let location = Location { block: block, statement_index: index }; + self.visit_statement(block, statement, location); + index += 1; } if let Some(ref $($mutability)* terminator) = *terminator { - self.visit_terminator(block, terminator); + let location = Location { block: block, statement_index: index }; + self.visit_terminator(block, terminator, location); } } @@ -304,7 +324,8 @@ macro_rules! make_mir_visitor { fn super_statement(&mut self, block: BasicBlock, - statement: & $($mutability)* Statement<'tcx>) { + statement: & $($mutability)* Statement<'tcx>, + location: Location) { let Statement { ref $($mutability)* source_info, ref $($mutability)* kind, @@ -314,16 +335,16 @@ macro_rules! make_mir_visitor { match *kind { StatementKind::Assign(ref $($mutability)* lvalue, ref $($mutability)* rvalue) => { - self.visit_assign(block, lvalue, rvalue); + self.visit_assign(block, lvalue, rvalue, location); } StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => { - self.visit_lvalue(lvalue, LvalueContext::Store); + self.visit_lvalue(lvalue, LvalueContext::Store, location); } StatementKind::StorageLive(ref $($mutability)* lvalue) => { - self.visit_lvalue(lvalue, LvalueContext::StorageLive); + self.visit_lvalue(lvalue, LvalueContext::StorageLive, location); } StatementKind::StorageDead(ref $($mutability)* lvalue) => { - self.visit_lvalue(lvalue, LvalueContext::StorageDead); + self.visit_lvalue(lvalue, LvalueContext::StorageDead, location); } } } @@ -331,26 +352,29 @@ macro_rules! make_mir_visitor { fn super_assign(&mut self, _block: BasicBlock, lvalue: &$($mutability)* Lvalue<'tcx>, - rvalue: &$($mutability)* Rvalue<'tcx>) { - self.visit_lvalue(lvalue, LvalueContext::Store); - self.visit_rvalue(rvalue); + rvalue: &$($mutability)* Rvalue<'tcx>, + location: Location) { + self.visit_lvalue(lvalue, LvalueContext::Store, location); + self.visit_rvalue(rvalue, location); } fn super_terminator(&mut self, block: BasicBlock, - terminator: &$($mutability)* Terminator<'tcx>) { + terminator: &$($mutability)* Terminator<'tcx>, + location: Location) { let Terminator { ref $($mutability)* source_info, ref $($mutability)* kind, } = *terminator; self.visit_source_info(source_info); - self.visit_terminator_kind(block, kind); + self.visit_terminator_kind(block, kind, location); } fn super_terminator_kind(&mut self, block: BasicBlock, - kind: & $($mutability)* TerminatorKind<'tcx>) { + kind: & $($mutability)* TerminatorKind<'tcx>, + source_location: Location) { match *kind { TerminatorKind::Goto { target } => { self.visit_branch(block, target); @@ -358,7 +382,7 @@ macro_rules! make_mir_visitor { TerminatorKind::If { ref $($mutability)* cond, ref $($mutability)* targets } => { - self.visit_operand(cond); + self.visit_operand(cond, source_location); for &target in targets.as_slice() { self.visit_branch(block, target); } @@ -367,7 +391,7 @@ macro_rules! make_mir_visitor { TerminatorKind::Switch { ref $($mutability)* discr, adt_def: _, ref targets } => { - self.visit_lvalue(discr, LvalueContext::Inspect); + self.visit_lvalue(discr, LvalueContext::Inspect, source_location); for &target in targets { self.visit_branch(block, target); } @@ -377,10 +401,10 @@ macro_rules! make_mir_visitor { ref $($mutability)* switch_ty, ref $($mutability)* values, ref targets } => { - self.visit_lvalue(discr, LvalueContext::Inspect); + self.visit_lvalue(discr, LvalueContext::Inspect, source_location); self.visit_ty(switch_ty); for value in values { - self.visit_const_val(value); + self.visit_const_val(value, source_location); } for &target in targets { self.visit_branch(block, target); @@ -395,7 +419,7 @@ macro_rules! make_mir_visitor { TerminatorKind::Drop { ref $($mutability)* location, target, unwind } => { - self.visit_lvalue(location, LvalueContext::Drop); + self.visit_lvalue(location, LvalueContext::Drop, source_location); self.visit_branch(block, target); unwind.map(|t| self.visit_branch(block, t)); } @@ -404,8 +428,8 @@ macro_rules! make_mir_visitor { ref $($mutability)* value, target, unwind } => { - self.visit_lvalue(location, LvalueContext::Drop); - self.visit_operand(value); + self.visit_lvalue(location, LvalueContext::Drop, source_location); + self.visit_operand(value, source_location); self.visit_branch(block, target); unwind.map(|t| self.visit_branch(block, t)); } @@ -414,12 +438,12 @@ macro_rules! make_mir_visitor { ref $($mutability)* args, ref $($mutability)* destination, cleanup } => { - self.visit_operand(func); + self.visit_operand(func, source_location); for arg in args { - self.visit_operand(arg); + self.visit_operand(arg, source_location); } if let Some((ref $($mutability)* destination, target)) = *destination { - self.visit_lvalue(destination, LvalueContext::Call); + self.visit_lvalue(destination, LvalueContext::Call, source_location); self.visit_branch(block, target); } cleanup.map(|t| self.visit_branch(block, t)); @@ -430,8 +454,8 @@ macro_rules! make_mir_visitor { ref $($mutability)* msg, target, cleanup } => { - self.visit_operand(cond); - self.visit_assert_message(msg); + self.visit_operand(cond, source_location); + self.visit_assert_message(msg, source_location); self.visit_branch(block, target); cleanup.map(|t| self.visit_branch(block, t)); } @@ -439,47 +463,49 @@ macro_rules! make_mir_visitor { } fn super_assert_message(&mut self, - msg: & $($mutability)* AssertMessage<'tcx>) { + msg: & $($mutability)* AssertMessage<'tcx>, + location: Location) { match *msg { AssertMessage::BoundsCheck { ref $($mutability)* len, ref $($mutability)* index } => { - self.visit_operand(len); - self.visit_operand(index); + self.visit_operand(len, location); + self.visit_operand(index, location); } AssertMessage::Math(_) => {} } } fn super_rvalue(&mut self, - rvalue: & $($mutability)* Rvalue<'tcx>) { + rvalue: & $($mutability)* Rvalue<'tcx>, + location: Location) { match *rvalue { Rvalue::Use(ref $($mutability)* operand) => { - self.visit_operand(operand); + self.visit_operand(operand, location); } Rvalue::Repeat(ref $($mutability)* value, ref $($mutability)* typed_const_val) => { - self.visit_operand(value); - self.visit_typed_const_val(typed_const_val); + self.visit_operand(value, location); + self.visit_typed_const_val(typed_const_val, location); } Rvalue::Ref(r, bk, ref $($mutability)* path) => { self.visit_lvalue(path, LvalueContext::Borrow { region: r, kind: bk - }); + }, location); } Rvalue::Len(ref $($mutability)* path) => { - self.visit_lvalue(path, LvalueContext::Inspect); + self.visit_lvalue(path, LvalueContext::Inspect, location); } Rvalue::Cast(_cast_kind, ref $($mutability)* operand, ref $($mutability)* ty) => { - self.visit_operand(operand); + self.visit_operand(operand, location); self.visit_ty(ty); } @@ -489,12 +515,12 @@ macro_rules! make_mir_visitor { Rvalue::CheckedBinaryOp(_bin_op, ref $($mutability)* lhs, ref $($mutability)* rhs) => { - self.visit_operand(lhs); - self.visit_operand(rhs); + self.visit_operand(lhs, location); + self.visit_operand(rhs, location); } Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => { - self.visit_operand(op); + self.visit_operand(op, location); } Rvalue::Box(ref $($mutability)* ty) => { @@ -515,13 +541,13 @@ macro_rules! make_mir_visitor { } AggregateKind::Closure(ref $($mutability)* def_id, ref $($mutability)* closure_substs) => { - self.visit_def_id(def_id); + self.visit_def_id(def_id, location); self.visit_closure_substs(closure_substs); } } for operand in operands { - self.visit_operand(operand); + self.visit_operand(operand, location); } } @@ -529,30 +555,32 @@ macro_rules! make_mir_visitor { ref $($mutability)* inputs, asm: _ } => { for output in & $($mutability)* outputs[..] { - self.visit_lvalue(output, LvalueContext::Store); + self.visit_lvalue(output, LvalueContext::Store, location); } for input in & $($mutability)* inputs[..] { - self.visit_operand(input); + self.visit_operand(input, location); } } } } fn super_operand(&mut self, - operand: & $($mutability)* Operand<'tcx>) { + operand: & $($mutability)* Operand<'tcx>, + location: Location) { match *operand { Operand::Consume(ref $($mutability)* lvalue) => { - self.visit_lvalue(lvalue, LvalueContext::Consume); + self.visit_lvalue(lvalue, LvalueContext::Consume, location); } Operand::Constant(ref $($mutability)* constant) => { - self.visit_constant(constant); + self.visit_constant(constant, location); } } } fn super_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext) { + context: LvalueContext, + location: Location) { match *lvalue { Lvalue::Var(_) | Lvalue::Temp(_) | @@ -560,28 +588,30 @@ macro_rules! make_mir_visitor { Lvalue::ReturnPointer => { } Lvalue::Static(ref $($mutability)* def_id) => { - self.visit_def_id(def_id); + self.visit_def_id(def_id, location); } Lvalue::Projection(ref $($mutability)* proj) => { - self.visit_projection(proj, context); + self.visit_projection(proj, context, location); } } } fn super_projection(&mut self, proj: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext) { + context: LvalueContext, + location: Location) { let Projection { ref $($mutability)* base, ref $($mutability)* elem, } = *proj; - self.visit_lvalue(base, LvalueContext::Projection); - self.visit_projection_elem(elem, context); + self.visit_lvalue(base, LvalueContext::Projection, location); + self.visit_projection_elem(elem, context, location); } fn super_projection_elem(&mut self, proj: & $($mutability)* LvalueElem<'tcx>, - _context: LvalueContext) { + _context: LvalueContext, + location: Location) { match *proj { ProjectionElem::Deref => { } @@ -591,7 +621,7 @@ macro_rules! make_mir_visitor { self.visit_ty(ty); } ProjectionElem::Index(ref $($mutability)* operand) => { - self.visit_operand(operand); + self.visit_operand(operand, location); } ProjectionElem::ConstantIndex { offset: _, min_length: _, @@ -645,7 +675,8 @@ macro_rules! make_mir_visitor { } fn super_constant(&mut self, - constant: & $($mutability)* Constant<'tcx>) { + constant: & $($mutability)* Constant<'tcx>, + location: Location) { let Constant { ref $($mutability)* span, ref $($mutability)* ty, @@ -654,11 +685,12 @@ macro_rules! make_mir_visitor { self.visit_span(span); self.visit_ty(ty); - self.visit_literal(literal); + self.visit_literal(literal, location); } fn super_typed_const_val(&mut self, - constant: & $($mutability)* TypedConstVal<'tcx>) { + constant: & $($mutability)* TypedConstVal<'tcx>, + location: Location) { let TypedConstVal { ref $($mutability)* span, ref $($mutability)* ty, @@ -667,19 +699,20 @@ macro_rules! make_mir_visitor { self.visit_span(span); self.visit_ty(ty); - self.visit_const_usize(value); + self.visit_const_usize(value, location); } fn super_literal(&mut self, - literal: & $($mutability)* Literal<'tcx>) { + literal: & $($mutability)* Literal<'tcx>, + location: Location) { match *literal { Literal::Item { ref $($mutability)* def_id, ref $($mutability)* substs } => { - self.visit_def_id(def_id); + self.visit_def_id(def_id, location); self.visit_substs(substs); } Literal::Value { ref $($mutability)* value } => { - self.visit_const_val(value); + self.visit_const_val(value, location); } Literal::Promoted { index: _ } => {} } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 90858e4e8b8be..c46daf9c22537 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -9,10 +9,9 @@ // except according to those terms. use rustc::ty::TyCtxt; -use rustc::mir::repr::{self, Mir}; +use rustc::mir::repr::{self, Mir, Location}; use rustc_data_structures::indexed_vec::Idx; -use super::super::gather_moves::{Location}; use super::super::gather_moves::{MoveOutIndex, MovePathIndex}; use super::super::MoveDataParamEnv; use super::super::DropFlagState; @@ -252,7 +251,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: idx }, + Location { block: bb, statement_index: idx }, |path, s| Self::update_bits(sets, path, s) ) } @@ -265,7 +264,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: statements_len }, + Location { block: bb, statement_index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) } @@ -314,7 +313,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: idx }, + Location { block: bb, statement_index: idx }, |path, s| Self::update_bits(sets, path, s) ) } @@ -327,7 +326,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: statements_len }, + Location { block: bb, statement_index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) } @@ -375,7 +374,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: idx }, + Location { block: bb, statement_index: idx }, |path, s| Self::update_bits(sets, path, s) ) } @@ -388,7 +387,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: statements_len }, + Location { block: bb, statement_index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) } @@ -431,7 +430,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let path_map = &move_data.path_map; let rev_lookup = &move_data.rev_lookup; - let loc = Location { block: bb, index: idx }; + let loc = Location { block: bb, statement_index: idx }; debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}", stmt, loc, &loc_map[loc]); for move_index in &loc_map[loc] { @@ -473,7 +472,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let (mir, move_data) = (self.mir, &ctxt.move_data); let term = mir[bb].terminator(); let loc_map = &move_data.loc_map; - let loc = Location { block: bb, index: statements_len }; + let loc = Location { block: bb, statement_index: statements_len }; debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", term, loc, &loc_map[loc]); let bits_per_block = self.bits_per_block(ctxt); diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 111646912ade3..57ec27aca9b04 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -9,7 +9,7 @@ // except according to those terms. use indexed_set::IdxSetBuf; -use super::gather_moves::{MoveData, MovePathIndex, MovePathContent, Location}; +use super::gather_moves::{MoveData, MovePathIndex, MovePathContent}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; use super::{drop_flag_effects_for_location, on_all_children_bits}; @@ -146,9 +146,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index()) .to_owned(), }; - for stmt in 0..loc.index { + for stmt in 0..loc.statement_index { data.apply_location(self.tcx, self.mir, self.env, - Location { block: loc.block, index: stmt }); + Location { block: loc.block, statement_index: stmt }); } data } @@ -226,7 +226,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let init_data = self.initialization_data_at(Location { block: bb, - index: data.statements.len() + statement_index: data.statements.len() }); let path = self.move_data().rev_lookup.find(location); @@ -249,7 +249,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn elaborate_drops(&mut self) { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { - let loc = Location { block: bb, index: data.statements.len() }; + let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); let resume_block = self.patch.resume_block(); @@ -359,9 +359,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { unwind: Some(unwind) }, bb); on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - self.set_drop_flag(Location { block: target, index: 0 }, + self.set_drop_flag(Location { block: target, statement_index: 0 }, child, DropFlagState::Present); - self.set_drop_flag(Location { block: unwind, index: 0 }, + self.set_drop_flag(Location { block: unwind, statement_index: 0 }, child, DropFlagState::Present); }); } @@ -741,7 +741,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let drop_block = self.drop_block(c); if update_drop_flag { self.set_drop_flag( - Location { block: drop_block, index: 0 }, + Location { block: drop_block, statement_index: 0 }, c.path, DropFlagState::Absent ); @@ -924,7 +924,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_on_init(&mut self) { - let loc = Location { block: START_BLOCK, index: 0 }; + let loc = Location { block: START_BLOCK, statement_index: 0 }; let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { @@ -939,7 +939,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); - let loc = Location { block: tgt, index: 0 }; + let loc = Location { block: tgt, statement_index: 0 }; let path = self.move_data().rev_lookup.find(lv); on_all_children_bits( self.tcx, self.mir, self.move_data(), path, @@ -950,7 +950,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_for_args(&mut self) { - let loc = Location { block: START_BLOCK, index: 0 }; + let loc = Location { block: START_BLOCK, statement_index: 0 }; super::drop_flag_effects_for_function_entry( self.tcx, self.mir, self.env, |path, ds| { self.set_drop_flag(loc, path, ds); @@ -990,7 +990,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } } - let loc = Location { block: bb, index: i }; + let loc = Location { block: bb, statement_index: i }; super::drop_flag_effects_for_location( self.tcx, self.mir, self.env, loc, |path, ds| { if ds == DropFlagState::Absent || allow_initializations { @@ -1008,7 +1008,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); - let loc = Location { block: bb, index: data.statements.len() }; + let loc = Location { block: bb, statement_index: data.statements.len() }; let path = self.move_data().rev_lookup.find(lv); on_all_children_bits( self.tcx, self.mir, self.move_data(), path, diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 8ae40e71bee58..15153bc861bca 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -160,8 +160,8 @@ impl Index for LocMap { type Output = [MoveOutIndex]; fn index(&self, index: Location) -> &Self::Output { assert!(index.block.index() < self.map.len()); - assert!(index.index < self.map[index.block.index()].len()); - &self.map[index.block.index()][index.index] + assert!(index.statement_index < self.map[index.block.index()].len()); + &self.map[index.block.index()][index.statement_index] } } @@ -200,21 +200,6 @@ impl fmt::Debug for MoveOut { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Location { - /// block where action is located - pub block: BasicBlock, - /// index within above block; statement when < statments.len) or - /// the terminator (when = statements.len). - pub index: usize, -} - -impl fmt::Debug for Location { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}[{}]", self.block, self.index) - } -} - #[derive(Debug)] pub struct MovePathData<'tcx> { move_paths: Vec>, @@ -569,7 +554,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD }; for (i, stmt) in bb_data.statements.iter().enumerate() { - let source = Location { block: bb, index: i }; + let source = Location { block: bb, statement_index: i }; match stmt.kind { StatementKind::Assign(ref lval, ref rval) => { bb_ctxt.builder.create_move_path(lval); @@ -638,7 +623,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::If { ref cond, targets: _ } => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::If, cond, source); } @@ -669,7 +654,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Drop { ref location, target: _, unwind: _ } => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_move_out_lval(SK::Drop, location, source); } TerminatorKind::DropAndReplace { ref location, ref value, .. } => { @@ -677,12 +662,12 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD bb_ctxt.path_map.fill_to(assigned_path.index()); let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::Use, value, source); } TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::CallFn, func, source); for arg in args { debug!("gather_moves Call on_operand {:?} {:?}", arg, source); @@ -757,7 +742,7 @@ impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> { stmt_kind: StmtKind, lval: &Lvalue<'tcx>, source: Location) { - let i = source.index; + let i = source.statement_index; let index = MoveOutIndex::new(self.moves.len()); let path = self.builder.move_path_for(lval); diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index dbee0ea9b00e9..31380c6f71c99 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -19,7 +19,7 @@ use rustc::hir; use rustc::hir::intravisit::{FnKind}; use rustc::mir::repr; -use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator}; +use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location}; use rustc::session::Session; use rustc::ty::{self, TyCtxt}; @@ -35,7 +35,7 @@ use self::dataflow::{DataflowOperator}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use self::dataflow::{DefinitelyInitializedLvals}; -use self::gather_moves::{MoveData, MovePathIndex, Location}; +use self::gather_moves::{MoveData, MovePathIndex}; use self::gather_moves::{MovePathContent, MovePathData}; fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option> { @@ -367,7 +367,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( } let block = &mir[loc.block]; - match block.statements.get(loc.index) { + match block.statements.get(loc.statement_index) { Some(stmt) => match stmt.kind { repr::StatementKind::SetDiscriminant{ .. } => { span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck"); diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs index 417e719a9dcb9..52cd1a9f949bf 100644 --- a/src/librustc_borrowck/borrowck/mir/patch.rs +++ b/src/librustc_borrowck/borrowck/mir/patch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::gather_moves::Location; use rustc::ty::Ty; use rustc::mir::repr::*; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -89,7 +88,7 @@ impl<'tcx> MirPatch<'tcx> { }; Location { block: bb, - index: offset + statement_index: offset } } @@ -149,12 +148,12 @@ impl<'tcx> MirPatch<'tcx> { } debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); - loc.index += delta; + loc.statement_index += delta; let source_info = Self::source_info_for_index( &mir[loc.block], loc ); mir[loc.block].statements.insert( - loc.index, Statement { + loc.statement_index, Statement { source_info: source_info, kind: stmt }); @@ -163,7 +162,7 @@ impl<'tcx> MirPatch<'tcx> { } pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo { - match data.statements.get(loc.index) { + match data.statements.get(loc.statement_index) { Some(stmt) => stmt.source_info, None => data.terminator().source_info } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5488f114db32f..8fe0c2755c11e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -42,6 +42,7 @@ use rustc_const_math::ConstInt; use rustc::mir; use rustc::mir::visit::MutVisitor; +use rustc::mir::repr::Location; use std::cell::Cell; use std::io; @@ -854,7 +855,7 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v> for MirDefIdAndSpanTranslator<'cdata, 'codemap> { - fn visit_def_id(&mut self, def_id: &mut DefId) { + fn visit_def_id(&mut self, def_id: &mut DefId, _: Location) { *def_id = translate_def_id(self.crate_metadata, *def_id); } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 83f8c3b42c850..026a79b32b8f7 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -13,7 +13,7 @@ //! Routines for manipulating the control-flow graph. -use build::{CFG, Location}; +use build::CFG; use rustc::mir::repr::*; impl<'tcx> CFG<'tcx> { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 26eb782a73b00..59d6cf1185969 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -101,16 +101,6 @@ pub struct ScopeAuxiliary { pub postdoms: Vec, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct Location { - /// the location is within this block - pub block: BasicBlock, - - /// the location is the start of the this statement; or, if `statement_index` - /// == num-statements, then the start of the terminator. - pub statement_index: usize, -} - pub type ScopeAuxiliaryVec = IndexVec; /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index c58491096b94f..d46a7b2bb9506 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{Location, ScopeAuxiliaryVec, ScopeId}; +use build::{ScopeAuxiliaryVec, ScopeId}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::mir::repr::*; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 818f060ed445c..32fddd293cacd 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -19,7 +19,10 @@ use rustc::mir::transform::{Pass, MirPass, MirSource}; pub struct NoLandingPads; impl<'tcx> MutVisitor<'tcx> for NoLandingPads { - fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) { + fn visit_terminator(&mut self, + bb: BasicBlock, + terminator: &mut Terminator<'tcx>, + location: Location) { match terminator.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | @@ -37,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { unwind.take(); }, } - self.super_terminator(bb, terminator); + self.super_terminator(bb, terminator, location); } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 21b406c3bf5c9..f864f1678f236 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -28,11 +28,10 @@ use rustc::mir::traversal::ReversePostorder; use rustc::ty::TyCtxt; use syntax_pos::Span; -use build::Location; - use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::mem; +use std::usize; /// State of a temporary during collection and promotion. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -77,13 +76,12 @@ pub enum Candidate { struct TempCollector { temps: IndexVec, - location: Location, span: Span } impl<'tcx> Visitor<'tcx> for TempCollector { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) { - self.super_lvalue(lvalue, context); + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { + self.super_lvalue(lvalue, context, location); if let Lvalue::Temp(index) = *lvalue { // Ignore drops, if the temp gets promoted, // then it's constant and thus drop is noop. @@ -101,7 +99,7 @@ impl<'tcx> Visitor<'tcx> for TempCollector { LvalueContext::Store | LvalueContext::Call => { *temp = TempState::Defined { - location: self.location, + location: location, uses: 0 }; return; @@ -126,27 +124,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector { fn visit_source_info(&mut self, source_info: &SourceInfo) { self.span = source_info.span; } - - fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) { - assert_eq!(self.location.block, bb); - self.super_statement(bb, statement); - self.location.statement_index += 1; - } - - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.location.statement_index = 0; - self.location.block = bb; - self.super_basic_block_data(bb, data); - } } pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { let mut collector = TempCollector { temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls), - location: Location { - block: START_BLOCK, - statement_index: 0 - }, span: mir.span }; for (bb, data) in rpo { @@ -266,9 +248,15 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // Then, recurse for components in the Rvalue or Call. if stmt_idx < no_stmts { - self.visit_rvalue(rvalue.as_mut().unwrap()); + self.visit_rvalue(rvalue.as_mut().unwrap(), Location { + block: bb, + statement_index: stmt_idx + }); } else { - self.visit_terminator_kind(bb, call.as_mut().unwrap()); + self.visit_terminator_kind(bb, call.as_mut().unwrap(), Location { + block: bb, + statement_index: no_stmts + }); } let new_temp = self.promoted.temp_decls.push(TempDecl { @@ -327,7 +315,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } } }; - self.visit_rvalue(&mut rvalue); + self.visit_rvalue(&mut rvalue, Location{ + block: BasicBlock::new(0), + statement_index: usize::MAX + }); self.assign(Lvalue::ReturnPointer, rvalue, span); self.source.promoted.push(self.promoted); } @@ -335,11 +326,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { /// Replaces all temporaries with their promoted counterparts. impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { - fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext, + location: Location) { if let Lvalue::Temp(ref mut temp) = *lvalue { *temp = self.promote_temp(*temp); } - self.super_lvalue(lvalue, context); + self.super_lvalue(lvalue, context, location); } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 1de67922b1b3a..2879941fdc320 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -37,8 +37,6 @@ use syntax_pos::Span; use std::collections::hash_map::Entry; use std::fmt; -use build::Location; - use super::promote_consts::{self, Candidate, TempState}; bitflags! { @@ -147,7 +145,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { return_qualif: Option, qualif: Qualif, const_fn_arg_vars: BitVector, - location: Location, temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -178,10 +175,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { return_qualif: None, qualif: Qualif::empty(), const_fn_arg_vars: BitVector::new(mir.var_decls.len()), - location: Location { - block: START_BLOCK, - statement_index: 0 - }, temp_promotion_state: temps, promotion_candidates: vec![] } @@ -293,7 +286,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } /// Assign the current qualification to the given destination. - fn assign(&mut self, dest: &Lvalue<'tcx>) { + fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) { let qualif = self.qualif; let span = self.span; let store = |slot: &mut Option| { @@ -331,7 +324,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // This must be an explicit assignment. _ => { // Catch more errors in the destination. - self.visit_lvalue(dest, LvalueContext::Store); + self.visit_lvalue(dest, LvalueContext::Store, location); self.statement_like(); } } @@ -399,7 +392,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { self.qualif = Qualif::NOT_CONST; for index in 0..mir.var_decls.len() { if !self.const_fn_arg_vars.contains(index) { - self.assign(&Lvalue::Var(Var::new(index))); + self.assign(&Lvalue::Var(Var::new(index)), Location { + block: BasicBlock::new(0), + statement_index: 0 + }); } } @@ -445,7 +441,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// For functions (constant or not), it also records /// candidates for promotion in promotion_candidates. impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) { + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { match *lvalue { Lvalue::Arg(_) => { self.add(Qualif::FN_ARGUMENT); @@ -477,7 +473,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } Lvalue::Projection(ref proj) => { self.nest(|this| { - this.super_lvalue(lvalue, context); + this.super_lvalue(lvalue, context, location); match proj.elem { ProjectionElem::Deref => { if !this.try_consume() { @@ -523,11 +519,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_operand(&mut self, operand: &Operand<'tcx>) { + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { match *operand { Operand::Consume(_) => { self.nest(|this| { - this.super_operand(operand); + this.super_operand(operand, location); this.try_consume(); }); } @@ -566,9 +562,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { // Recurse through operands and lvalues. - self.super_rvalue(rvalue); + self.super_rvalue(rvalue, location); match *rvalue { Rvalue::Use(_) | @@ -644,7 +640,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } // We might have a candidate for promotion. - let candidate = Candidate::Ref(self.location); + let candidate = Candidate::Ref(location); if self.mode == Mode::Fn || self.mode == Mode::ConstFn { if !self.qualif.intersects(Qualif::NEVER_PROMOTE) { // We can only promote direct borrows of temps. @@ -724,9 +720,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_terminator_kind(&mut self, bb: BasicBlock, kind: &TerminatorKind<'tcx>) { + fn visit_terminator_kind(&mut self, + bb: BasicBlock, + kind: &TerminatorKind<'tcx>, + location: Location) { if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind { - self.visit_operand(func); + self.visit_operand(func, location); let fn_ty = func.ty(self.mir, self.tcx); let (is_shuffle, is_const_fn) = match fn_ty.sty { @@ -740,7 +739,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { for (i, arg) in args.iter().enumerate() { self.nest(|this| { - this.visit_operand(arg); + this.visit_operand(arg, location); if is_shuffle && i == 2 && this.mode == Mode::Fn { let candidate = Candidate::ShuffleIndices(bb); if !this.qualif.intersects(Qualif::NEVER_PROMOTE) { @@ -818,16 +817,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.deny_drop(); } } - self.assign(dest); + self.assign(dest, location); } } else { // Qualify any operands inside other terminators. - self.super_terminator_kind(bb, kind); + self.super_terminator_kind(bb, kind, location); } } - fn visit_assign(&mut self, _: BasicBlock, dest: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) { - self.visit_rvalue(rvalue); + fn visit_assign(&mut self, + _: BasicBlock, + dest: &Lvalue<'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location) { + self.visit_rvalue(rvalue, location); // Check the allowed const fn argument forms. if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) { @@ -848,38 +851,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - self.assign(dest); + self.assign(dest, location); } fn visit_source_info(&mut self, source_info: &SourceInfo) { self.span = source_info.span; } - fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) { - assert_eq!(self.location.block, bb); - self.nest(|this| { - this.visit_source_info(&statement.source_info); - match statement.kind { - StatementKind::Assign(ref lvalue, ref rvalue) => { - this.visit_assign(bb, lvalue, rvalue); - } - StatementKind::SetDiscriminant { .. } | - StatementKind::StorageLive(_) | - StatementKind::StorageDead(_) => {} - } - }); - self.location.statement_index += 1; - } - - fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) { - assert_eq!(self.location.block, bb); - self.nest(|this| this.super_terminator(bb, terminator)); + fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) { + self.nest(|this| this.super_statement(bb, statement, location)); } - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.location.statement_index = 0; - self.location.block = bb; - self.super_basic_block_data(bb, data); + fn visit_terminator(&mut self, + bb: BasicBlock, + terminator: &Terminator<'tcx>, + location: Location) { + self.nest(|this| this.super_terminator(bb, terminator, location)); } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index bbd2a93659b0a..21d4ae595e8ac 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -68,17 +68,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: visit::LvalueContext) { - self.sanitize_lvalue(lvalue); + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + _context: visit::LvalueContext, + location: Location) { + self.sanitize_lvalue(lvalue, location); } - fn visit_constant(&mut self, constant: &Constant<'tcx>) { - self.super_constant(constant); + fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + self.super_constant(constant, location); self.sanitize_type(constant, constant.ty); } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { - self.super_rvalue(rvalue); + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); if let Some(ty) = rvalue.ty(self.mir, self.tcx()) { self.sanitize_type(rvalue, ty); } @@ -124,7 +127,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> { + fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); match *lvalue { Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty }, @@ -136,14 +139,14 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { LvalueTy::Ty { ty: self.mir.return_ty } } Lvalue::Projection(ref proj) => { - let base_ty = self.sanitize_lvalue(&proj.base); + let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { if ty.references_error() { assert!(self.errors_reported); return LvalueTy::Ty { ty: self.tcx().types.err }; } } - self.sanitize_projection(base_ty, &proj.elem, lvalue) + self.sanitize_projection(base_ty, &proj.elem, lvalue, location) } } } @@ -151,7 +154,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn sanitize_projection(&mut self, base: LvalueTy<'tcx>, pi: &LvalueElem<'tcx>, - lvalue: &Lvalue<'tcx>) + lvalue: &Lvalue<'tcx>, + location: Location) -> LvalueTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue); let tcx = self.tcx(); @@ -168,7 +172,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } ProjectionElem::Index(ref i) => { - self.visit_operand(i); + self.visit_operand(i, location); let index_ty = i.ty(self.mir, tcx); if index_ty != tcx.types.usize { LvalueTy::Ty { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 76910304eebb0..c11e696302d34 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -201,6 +201,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::repr as mir; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; +use rustc::mir::repr::Location; use rustc_const_eval as const_eval; @@ -446,7 +447,7 @@ struct MirNeighborCollector<'a, 'tcx: 'a> { impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { debug!("visiting rvalue {:?}", *rvalue); match *rvalue { @@ -517,12 +518,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => { /* not interesting */ } } - self.super_rvalue(rvalue); + self.super_rvalue(rvalue, location); } fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: mir_visit::LvalueContext) { + context: mir_visit::LvalueContext, + location: Location) { debug!("visiting lvalue {:?}", *lvalue); if let mir_visit::LvalueContext::Drop = context { @@ -537,10 +539,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } - self.super_lvalue(lvalue, context); + self.super_lvalue(lvalue, context, location); } - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) { + fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { debug!("visiting operand {:?}", *operand); let callee = match *operand { @@ -620,7 +622,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } } - self.super_operand(operand); + self.super_operand(operand, location); fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -654,7 +656,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // we would not register drop-glues. fn visit_terminator_kind(&mut self, block: mir::BasicBlock, - kind: &mir::TerminatorKind<'tcx>) { + kind: &mir::TerminatorKind<'tcx>, + location: Location) { let tcx = self.scx.tcx(); match *kind { mir::TerminatorKind::Call { @@ -682,7 +685,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => { /* Nothing to do. */ } } - self.super_terminator_kind(block, kind); + self.super_terminator_kind(block, kind, location); fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index e0d959f4774a6..cf32aeabee527 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -15,6 +15,7 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::repr as mir; use rustc::mir::repr::TerminatorKind; +use rustc::mir::repr::Location; use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common::{self, Block, BlockAndBuilder}; @@ -98,7 +99,8 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { fn visit_assign(&mut self, block: mir::BasicBlock, lvalue: &mir::Lvalue<'tcx>, - rvalue: &mir::Rvalue<'tcx>) { + rvalue: &mir::Rvalue<'tcx>, + location: Location) { debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue); if let Some(index) = self.mir.local_index(lvalue) { @@ -107,15 +109,16 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { self.mark_as_lvalue(index); } } else { - self.visit_lvalue(lvalue, LvalueContext::Store); + self.visit_lvalue(lvalue, LvalueContext::Store, location); } - self.visit_rvalue(rvalue); + self.visit_rvalue(rvalue, location); } fn visit_terminator_kind(&mut self, block: mir::BasicBlock, - kind: &mir::TerminatorKind<'tcx>) { + kind: &mir::TerminatorKind<'tcx>, + location: Location) { match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(mir::Constant { @@ -127,18 +130,19 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. if let mir::Operand::Consume(ref lvalue) = args[0] { - self.visit_lvalue(lvalue, LvalueContext::Drop); + self.visit_lvalue(lvalue, LvalueContext::Drop, location); } } _ => {} } - self.super_terminator_kind(block, kind); + self.super_terminator_kind(block, kind, location); } fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: LvalueContext) { + context: LvalueContext, + location: Location) { debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context); // Allow uses of projections of immediate pair fields. @@ -190,11 +194,11 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { // A deref projection only reads the pointer, never needs the lvalue. if let mir::Lvalue::Projection(ref proj) = *lvalue { if let mir::ProjectionElem::Deref = proj.elem { - return self.visit_lvalue(&proj.base, LvalueContext::Consume); + return self.visit_lvalue(&proj.base, LvalueContext::Consume, location); } } - self.super_lvalue(lvalue, context); + self.super_lvalue(lvalue, context, location); } } diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs index 604933d40a12c..f7b046b30cad7 100644 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs @@ -19,7 +19,7 @@ extern crate rustc_const_math; extern crate syntax; use rustc::mir::transform::{self, MirPass, MirSource}; -use rustc::mir::repr::{Mir, Literal}; +use rustc::mir::repr::{Mir, Literal, Location}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use rustc::middle::const_val::ConstVal; @@ -40,7 +40,7 @@ impl<'tcx> MirPass<'tcx> for Pass { struct Visitor; impl<'tcx> MutVisitor<'tcx> for Visitor { - fn visit_literal(&mut self, literal: &mut Literal<'tcx>) { + fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) { if let Literal::Value { ref mut value } = *literal { if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value { *i = 42; From 06302cb983198bdf6b984510d24673f4d0f49a98 Mon Sep 17 00:00:00 2001 From: Andrew Cantino Date: Thu, 18 Aug 2016 15:06:05 -0400 Subject: [PATCH 150/768] Fix minor typo --- src/doc/book/closures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index d332cac7d8d16..3ed85c1a90b69 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -340,7 +340,7 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32 where F: Fn(&'a i32) -> i32 { ``` -However this presents a problem with in our case. When you specify the explicit +However this presents a problem in our case. When you specify the explicit lifetime on a function it binds that lifetime to the *entire* scope of the function instead of just the invocation scope of our closure. This means that the borrow checker will see a mutable reference in the same lifetime as our immutable reference and fail From 9563f14eb5d77d992f7cde5db227f8c83351427b Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 16:04:53 -0400 Subject: [PATCH 151/768] demonstrate `RHS != Self` use cases for `Mul` and `Div` Vector-scalar multipication is a good usecase for this. Thanks #rust! --- src/libcore/ops.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..aefafa1b739cb 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -295,6 +295,37 @@ sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo * Foo; /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. Here is an +/// implementation which enables multiplication of vectors by scalars, as is +/// done in linear algebra. +/// +/// ``` +/// use std::ops::Mul; +/// +/// struct Scalar {value: usize}; +/// +/// #[derive(Debug)] +/// struct Vector {value: Vec}; +/// +/// impl Mul for Scalar { +/// type Output = Vector; +/// +/// fn mul(self, rhs: Vector) -> Vector { +/// Vector {value: rhs.value.iter().map(|v| self.value * v).collect()} +/// } +/// } +/// +/// impl PartialEq for Vector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } +/// } +/// +/// let scalar = Scalar{value: 3}; +/// let vector = Vector{value: vec![2, 4, 6]}; +/// assert_eq!(scalar * vector, Vector{value: vec![6, 12, 18]}); +/// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Mul { @@ -349,6 +380,37 @@ mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo / Foo; /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. Here is an +/// implementation which enables division of vectors by scalars, as is done in +/// linear algebra. +/// +/// ``` +/// use std::ops::Div; +/// +/// struct Scalar {value: f32}; +/// +/// #[derive(Debug)] +/// struct Vector {value: Vec}; +/// +/// impl Div for Vector { +/// type Output = Vector; +/// +/// fn div(self, rhs: Scalar) -> Vector { +/// Vector {value: self.value.iter().map(|v| v / rhs.value).collect()} +/// } +/// } +/// +/// impl PartialEq for Vector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } +/// } +/// +/// let scalar = Scalar{value: 2f32}; +/// let vector = Vector{value: vec![2f32, 4f32, 6f32]}; +/// assert_eq!(vector / scalar, Vector{value: vec![1f32, 2f32, 3f32]}); +/// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Div { From 469b7fd1c09e5759f8cbce0f4e42be91c6f1b81a Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 16:12:40 -0400 Subject: [PATCH 152/768] split example into three sections with explanation --- src/libcore/ops.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index cee374ccc7bc5..932e5f086cbbe 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1462,13 +1462,24 @@ pub trait IndexMut: Index { /// /// # Examples /// +/// The `..` syntax is a `RangeFull`: +/// /// ``` /// assert_eq!((..), std::ops::RangeFull); +/// ``` /// -/// // for i in .. { -/// // println!("This errors because .. has no IntoIterator impl"); -/// // } +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: /// +/// ```ignore +/// for i in .. { +/// // ... +/// } +/// ``` +/// +/// Used as a slicing index, `RangeFull` produces the full array as a slice. +/// +/// ``` /// let arr = [0, 1, 2, 3]; /// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull /// assert_eq!(arr[ ..3], [0,1,2 ]); From 301401e568e6ed297ab0b06c5cf60d8ba8109750 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 16 Aug 2016 14:25:12 +1200 Subject: [PATCH 153/768] Redirect --- src/librustdoc/html/render.rs | 10 ++++++++++ src/test/rustdoc/macros.rs | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d654429146d83..e02cfb96dddf1 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1426,6 +1426,16 @@ impl Context { .open(&redir_dst) { try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); } + + // If the item is a macro, redirect from the old macro URL (with !) + // to the new one (without). + // FIXME(#35705) remove this redirect. + if item_type == ItemType::Macro { + let redir_name = format!("{}.{}!.html", item_type, name); + let redir_dst = self.dst.join(redir_name); + let mut redirect_out = try_err!(File::create(&redir_dst), &redir_dst); + try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); + } } } Ok(()) diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs index f4115d8229a54..9aeeb71707c90 100644 --- a/src/test/rustdoc/macros.rs +++ b/src/test/rustdoc/macros.rs @@ -12,6 +12,8 @@ // @has - //pre '() => { ... };' // @has - //pre '($a:tt) => { ... };' // @has - //pre '($e:expr) => { ... };' +// @has macros/macro.my_macro!.html +// @has - //a 'macro.my_macro.html' #[macro_export] macro_rules! my_macro { () => []; From 161cb36159337edfeba546c9ead24262bc5a5dfc Mon Sep 17 00:00:00 2001 From: pliniker Date: Thu, 18 Aug 2016 16:27:33 -0400 Subject: [PATCH 154/768] Update error message for E0084 --- src/librustc_typeck/check/mod.rs | 7 +++++-- src/test/compile-fail/E0084.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ff0b86aa59540..78d311865aa87 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1245,8 +1245,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny); if hint != attr::ReprAny && vs.is_empty() { - span_err!(ccx.tcx.sess, sp, E0084, - "unsupported representation for zero-variant enum"); + struct_span_err!( + ccx.tcx.sess, sp, E0084, + "unsupported representation for zero-variant enum") + .span_label(sp, &format!("unsupported enum representation")) + .emit(); } let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx); diff --git a/src/test/compile-fail/E0084.rs b/src/test/compile-fail/E0084.rs index c579101325f5d..c7c5662f1feda 100644 --- a/src/test/compile-fail/E0084.rs +++ b/src/test/compile-fail/E0084.rs @@ -9,7 +9,9 @@ // except according to those terms. #[repr(i32)] -enum Foo {} //~ ERROR E0084 +enum Foo {} +//~^ ERROR E0084 +//~| unsupported enum representation fn main() { } From a516dbb7d946fc26ed036ae4bd23f4c7abdff3a2 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Tue, 16 Aug 2016 04:33:59 -0400 Subject: [PATCH 155/768] note that calling drop() explicitly is a compiler error Part of #29365 explain that std::mem::drop in prelude will invoke Drop change "prelude" -> "the prelude"; change links to reference-style move link references to links' section --- src/libcore/ops.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..daa5ebb61f96d 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -102,6 +102,13 @@ pub trait Drop { /// /// After this function is over, the memory of `self` will be deallocated. /// + /// This function cannot be called explicitly. This is compiler error + /// [0040]. However, the [`std::mem::drop`] function in the prelude can be + /// used to call the argument's `Drop` implementation. + /// + /// [0040]: https://doc.rust-lang.org/error-index.html#E0040 + /// [`std::mem::drop`]: https://doc.rust-lang.org/std/mem/fn.drop.html + /// /// # Panics /// /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in From 61c4f5b61074e322b8853019fe6864a1d6dc72af Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Thu, 18 Aug 2016 16:54:20 -0400 Subject: [PATCH 156/768] port to new Location --- src/librustc_borrowck/borrowck/mir/gather_moves.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 15153bc861bca..01bf8ed0e4b57 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -616,7 +616,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Return => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; debug!("gather_moves Return on_move_out_lval return {:?}", source); bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); } From 6c66eaa035e5fc47ebbff44b81d2cb3cf1d7d568 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 16:54:33 -0400 Subject: [PATCH 157/768] replace `AddAssign` example with something more evocative of addition This is analogous to PR #35709 for the `Add` trait. --- src/libcore/ops.rs | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..1a203a898f73e 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -894,25 +894,36 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// /// # Examples /// -/// A trivial implementation of `AddAssign`. When `Foo += Foo` happens, it ends up -/// calling `add_assign`, and therefore, `main` prints `Adding!`. +/// This example creates a `Point` struct that implements the `AddAssign` +/// trait, and then demonstrates add-assigning to a mutable `Point`. /// /// ``` /// use std::ops::AddAssign; /// -/// struct Foo; +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } /// -/// impl AddAssign for Foo { -/// fn add_assign(&mut self, _rhs: Foo) { -/// println!("Adding!"); +/// impl AddAssign for Point { +/// fn add_assign(&mut self, other: Point) { +/// *self = Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// }; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo += Foo; +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } /// } +/// +/// let mut point = Point { x: 1, y: 0 }; +/// point += Point { x: 2, y: 3 }; +/// assert_eq!(point, Point { x: 3, y: 3 }); /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] From ffbb8600fbba009598cbebf7149d0bd7a736b928 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 18 Aug 2016 15:22:23 -0700 Subject: [PATCH 158/768] Add workaround to detect correct compiler version --- src/bootstrap/bin/rustc.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index c64cbb9a74e09..175e32125f272 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -38,13 +38,19 @@ fn main() { // is passed (a bit janky...) let target = args.windows(2).find(|w| &*w[0] == "--target") .and_then(|w| w[1].to_str()); + let version = args.iter().find(|w| &**w == "-vV"); // Build scripts always use the snapshot compiler which is guaranteed to be // able to produce an executable, whereas intermediate compilers may not // have the standard library built yet and may not be able to produce an // executable. Otherwise we just use the standard compiler we're // bootstrapping with. - let (rustc, libdir) = if target.is_none() { + // + // Also note that cargo will detect the version of the compiler to trigger + // a rebuild when the compiler changes. If this happens, we want to make + // sure to use the actual compiler instead of the snapshot compiler becase + // that's the one that's actually changing. + let (rustc, libdir) = if target.is_none() && version.is_none() { ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR") } else { ("RUSTC_REAL", "RUSTC_LIBDIR") From 39f318bb4d7144a8deb10f520a01164133c1b6ec Mon Sep 17 00:00:00 2001 From: Michael Layne Date: Thu, 18 Aug 2016 14:40:59 -0700 Subject: [PATCH 159/768] Update error format for E0232 --- src/librustc_typeck/check/mod.rs | 9 ++++++--- src/test/compile-fail/E0232.rs | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ff0b86aa59540..3a21ffb5e7d93 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -903,9 +903,12 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } else { - span_err!(ccx.tcx.sess, attr.span, E0232, - "this attribute must have a value, \ - eg `#[rustc_on_unimplemented = \"foo\"]`") + struct_span_err!( + ccx.tcx.sess, attr.span, E0232, + "this attribute must have a value") + .span_label(attr.span, &format!("attribute requires a value")) + .note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`")) + .emit(); } } } diff --git a/src/test/compile-fail/E0232.rs b/src/test/compile-fail/E0232.rs index efeb869d71fa5..ce4f4638dac59 100644 --- a/src/test/compile-fail/E0232.rs +++ b/src/test/compile-fail/E0232.rs @@ -10,7 +10,10 @@ #![feature(on_unimplemented)] -#[rustc_on_unimplemented] //~ ERROR E0232 +#[rustc_on_unimplemented] +//~^ ERROR E0232 +//~| NOTE attribute requires a value +//~| NOTE eg `#[rustc_on_unimplemented = "foo"]` trait Bar {} fn main() { From 5aa89d8bf6dcf3f7c08f3db8f48b54676b6203b8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 9 Aug 2016 17:54:24 +1200 Subject: [PATCH 160/768] Remove the Option and bool impls for carrier and add a dummy impl The dummy impl should ensure the same type checking behaviour as having other (real) Carrier impls. --- src/libcore/ops.rs | 67 ++----------------- .../compile-fail/question-mark-type-infer.rs | 27 ++++++++ src/test/run-pass/try-operator.rs | 17 ----- 3 files changed, 34 insertions(+), 77 deletions(-) create mode 100644 src/test/compile-fail/question-mark-type-infer.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index a869b3c4f98c5..0e32d71172b04 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -76,7 +76,6 @@ use cmp::PartialOrd; use fmt; use marker::{Sized, Unsize}; use result::Result::{self, Ok, Err}; -use option::Option::{self, Some, None}; /// The `Drop` trait is used to run some code when a value goes out of scope. /// This is sometimes called a 'destructor'. @@ -2203,75 +2202,23 @@ impl Carrier for Result { } } -#[unstable(feature = "question_mark_carrier", issue = "31436")] -impl Carrier for Option { - type Success = U; - type Error = (); - - fn from_success(u: U) -> Option { - Some(u) - } +struct _DummyErrorType; - fn from_error(_: ()) -> Option { - None - } - - fn translate(self) -> T - where T: Carrier - { - match self { - Some(u) => T::from_success(u), - None => T::from_error(()), - } - } -} - -// Implementing Carrier for bools means it's easy to write short-circuiting -// functions. E.g., -// ``` -// fn foo() -> bool { -// if !(f() || g()) { -// return false; -// } -// -// some_computation(); -// if h() { -// return false; -// } -// -// more_computation(); -// i() -// } -// ``` -// becomes -// ``` -// fn foo() -> bool { -// (f() || g())?; -// some_computation(); -// (!h())?; -// more_computation(); -// i() -// } -// ``` -#[unstable(feature = "question_mark_carrier", issue = "31436")] -impl Carrier for bool { +impl Carrier for _DummyErrorType { type Success = (); type Error = (); - fn from_success(_: ()) -> bool { - true + fn from_success(_: ()) -> _DummyErrorType { + _DummyErrorType } - fn from_error(_: ()) -> bool { - false + fn from_error(_: ()) -> _DummyErrorType { + _DummyErrorType } fn translate(self) -> T where T: Carrier { - match self { - true => T::from_success(()), - false => T::from_error(()), - } + T::from_success(()) } } diff --git a/src/test/compile-fail/question-mark-type-infer.rs b/src/test/compile-fail/question-mark-type-infer.rs new file mode 100644 index 0000000000000..e15c9af41e082 --- /dev/null +++ b/src/test/compile-fail/question-mark-type-infer.rs @@ -0,0 +1,27 @@ +// 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. + +#![feature(question_mark, question_mark_carrier)] + +// Test that type inference fails where there are multiple possible return types +// for the `?` operator. + +fn f(x: &i32) -> Result { + Ok(*x) +} + +fn g() -> Result, ()> { + let l = [1, 2, 3, 4]; + l.iter().map(f).collect()? //~ ERROR type annotations required: cannot resolve +} + +fn main() { + g(); +} diff --git a/src/test/run-pass/try-operator.rs b/src/test/run-pass/try-operator.rs index 8076e00fd08ac..de5ccf09c5923 100644 --- a/src/test/run-pass/try-operator.rs +++ b/src/test/run-pass/try-operator.rs @@ -144,23 +144,6 @@ fn merge_error() -> Result { Ok(s.parse::()? + 1) } -fn option() -> Option { - let x = Some(42); - let y = x?; - Some(y + 2) -} - -fn bool() -> bool { - let x = true; - let y = false; - let z = true; - - (x || y)?; - let a: () = z?; - x?; - true -} - fn main() { assert_eq!(Ok(3), on_method()); From 2128d31a41346c726d2271845d92533ccae882e7 Mon Sep 17 00:00:00 2001 From: Chiu-Hsiang Hsu Date: Fri, 19 Aug 2016 11:58:26 +0800 Subject: [PATCH 161/768] Fix label messages for E0133 Issue #35789 --- src/librustc/middle/effect.rs | 2 +- src/test/compile-fail/E0133.rs | 2 +- src/test/compile-fail/issue-28776.rs | 2 +- src/test/compile-fail/trait-safety-fn-body.rs | 2 +- src/test/compile-fail/unsafe-const-fn.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 3ca6cf0399797..250ad80f5af6c 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { struct_span_err!( self.tcx.sess, span, E0133, "{} requires unsafe function or block", description) - .span_label(span, &format!("unsafe call requires unsafe function or block")) + .span_label(span, &description) .emit(); } UnsafeBlock(block_id) => { diff --git a/src/test/compile-fail/E0133.rs b/src/test/compile-fail/E0133.rs index b8a4476fc5967..f60d9a5083f6f 100644 --- a/src/test/compile-fail/E0133.rs +++ b/src/test/compile-fail/E0133.rs @@ -13,5 +13,5 @@ unsafe fn f() { return; } fn main() { f(); //~^ ERROR E0133 - //~| NOTE unsafe call requires unsafe function or block + //~| NOTE call to unsafe function } diff --git a/src/test/compile-fail/issue-28776.rs b/src/test/compile-fail/issue-28776.rs index 52b0eba96cbdf..4a36bc88fa7d9 100644 --- a/src/test/compile-fail/issue-28776.rs +++ b/src/test/compile-fail/issue-28776.rs @@ -13,5 +13,5 @@ use std::ptr; fn main() { (&ptr::write)(1 as *mut _, 42); //~^ ERROR E0133 - //~| NOTE unsafe call requires unsafe function or block + //~| NOTE call to unsafe function } diff --git a/src/test/compile-fail/trait-safety-fn-body.rs b/src/test/compile-fail/trait-safety-fn-body.rs index 0df7ee8cabed2..65732a8ff69e5 100644 --- a/src/test/compile-fail/trait-safety-fn-body.rs +++ b/src/test/compile-fail/trait-safety-fn-body.rs @@ -20,7 +20,7 @@ unsafe impl UnsafeTrait for *mut isize { // Unsafe actions are not made legal by taking place in an unsafe trait: *self += 1; //~^ ERROR E0133 - //~| NOTE unsafe call requires unsafe function or block + //~| NOTE dereference of raw pointer } } diff --git a/src/test/compile-fail/unsafe-const-fn.rs b/src/test/compile-fail/unsafe-const-fn.rs index 174939b09009c..91e16592be472 100644 --- a/src/test/compile-fail/unsafe-const-fn.rs +++ b/src/test/compile-fail/unsafe-const-fn.rs @@ -18,7 +18,7 @@ const unsafe fn dummy(v: u32) -> u32 { const VAL: u32 = dummy(0xFFFF); //~^ ERROR E0133 -//~| NOTE unsafe call requires unsafe function or block +//~| NOTE call to unsafe function fn main() { assert_eq!(VAL, 0xFFFF0000); From 8dae1b662588ed18017a50c2cbc5c6b2880ae27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 19 Aug 2016 14:00:20 +0200 Subject: [PATCH 162/768] Document that Condvar makes the best effort to use monotonic clock. --- src/libstd/sync/condvar.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index ca1a9905ebe67..5ee42a09e12ae 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -144,6 +144,10 @@ impl Condvar { /// differences that may not cause the maximum amount of time /// waited to be precisely `ms`. /// + /// Note that the best effort is made to ensure that the time waited is + /// measured with a monotonic clock, and not affected by the changes made to + /// the system time. + /// /// The returned boolean is `false` only if the timeout is known /// to have elapsed. /// @@ -168,6 +172,10 @@ impl Condvar { /// preemption or platform differences that may not cause the maximum /// amount of time waited to be precisely `dur`. /// + /// Note that the best effort is made to ensure that the time waited is + /// measured with a monotonic clock, and not affected by the changes made to + /// the system time. + /// /// The returned `WaitTimeoutResult` value indicates if the timeout is /// known to have elapsed. /// From 2c190ad0d2a20719e45fd34e4fc50f9b3184ea4d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 19 Aug 2016 16:44:29 +0200 Subject: [PATCH 163/768] Update block codes' flags --- src/librustc_metadata/diagnostics.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index ae9f500c5de59..099ec62b38de7 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -14,7 +14,7 @@ register_long_diagnostics! { E0454: r##" A link name was given with an empty name. Erroneous code example: -``` +```compile_fail,E0454 #[link(name = "")] extern {} // error: #[link(name = "")] given with empty name ``` @@ -32,7 +32,7 @@ as frameworks are specific to that operating system. Erroneous code example: -```compile_fail" +```compile_fail,E0455 #[link(name = "FooCoreServices", kind = "framework")] extern {} // OS used to compile is Linux for example ``` @@ -50,7 +50,7 @@ See more: https://doc.rust-lang.org/book/conditional-compilation.html E0458: r##" An unknown "kind" was specified for a link attribute. Erroneous code example: -``` +```compile_fail,E0458 #[link(kind = "wonderful_unicorn")] extern {} // error: unknown kind: `wonderful_unicorn` ``` @@ -64,7 +64,7 @@ Please specify a valid "kind" value, from one of the following: E0459: r##" A link was used without a name parameter. Erroneous code example: -``` +```compile_fail,E0459 #[link(kind = "dylib")] extern {} // error: #[link(...)] specified without `name = "foo"` ``` @@ -80,7 +80,7 @@ you want. Example: E0463: r##" A plugin/crate was declared but cannot be found. Erroneous code example: -``` +```compile_fail,E0463 #![feature(plugin)] #![plugin(cookie_monster)] // error: can't find crate for `cookie_monster` extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie` From f551674c6d3340822c8f5cf7159263df44718937 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 19 Aug 2016 16:44:47 +0200 Subject: [PATCH 164/768] Add new error code tests --- src/test/compile-fail/E0441.rs | 21 +++++++++++++++++++++ src/test/compile-fail/E0442.rs | 29 +++++++++++++++++++++++++++++ src/test/compile-fail/E0443.rs | 23 +++++++++++++++++++++++ src/test/compile-fail/E0444.rs | 21 +++++++++++++++++++++ src/test/compile-fail/E0445.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0446.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0449.rs | 24 ++++++++++++++++++++++++ src/test/compile-fail/E0450.rs | 17 +++++++++++++++++ src/test/compile-fail/E0451.rs | 20 ++++++++++++++++++++ src/test/compile-fail/E0452.rs | 14 ++++++++++++++ src/test/compile-fail/E0453.rs | 15 +++++++++++++++ src/test/compile-fail/E0454.rs | 14 ++++++++++++++ src/test/compile-fail/E0455.rs | 14 ++++++++++++++ src/test/compile-fail/E0458.rs | 15 +++++++++++++++ src/test/compile-fail/E0459.rs | 14 ++++++++++++++ src/test/compile-fail/E0463.rs | 16 ++++++++++++++++ 16 files changed, 295 insertions(+) create mode 100644 src/test/compile-fail/E0441.rs create mode 100644 src/test/compile-fail/E0442.rs create mode 100644 src/test/compile-fail/E0443.rs create mode 100644 src/test/compile-fail/E0444.rs create mode 100644 src/test/compile-fail/E0445.rs create mode 100644 src/test/compile-fail/E0446.rs create mode 100644 src/test/compile-fail/E0449.rs create mode 100644 src/test/compile-fail/E0450.rs create mode 100644 src/test/compile-fail/E0451.rs create mode 100644 src/test/compile-fail/E0452.rs create mode 100644 src/test/compile-fail/E0453.rs create mode 100644 src/test/compile-fail/E0454.rs create mode 100644 src/test/compile-fail/E0455.rs create mode 100644 src/test/compile-fail/E0458.rs create mode 100644 src/test/compile-fail/E0459.rs create mode 100644 src/test/compile-fail/E0463.rs diff --git a/src/test/compile-fail/E0441.rs b/src/test/compile-fail/E0441.rs new file mode 100644 index 0000000000000..967ff64327235 --- /dev/null +++ b/src/test/compile-fail/E0441.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); + +extern "platform-intrinsic" { + fn x86_mm_adds_ep16(x: i16x8, y: i16x8) -> i16x8; //~ ERROR E0441 +} + +fn main() {} diff --git a/src/test/compile-fail/E0442.rs b/src/test/compile-fail/E0442.rs new file mode 100644 index 0000000000000..ddd927054be1d --- /dev/null +++ b/src/test/compile-fail/E0442.rs @@ -0,0 +1,29 @@ +// 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. + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, + i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +struct i64x2(i64, i64); + +extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: i8x16, y: i32x4) -> i64x2; + //~^ ERROR E0442 + //~| ERROR E0442 + //~| ERROR E0442 +} + +fn main() {} diff --git a/src/test/compile-fail/E0443.rs b/src/test/compile-fail/E0443.rs new file mode 100644 index 0000000000000..24d1ee01dd46e --- /dev/null +++ b/src/test/compile-fail/E0443.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +struct i64x8(i64, i64, i64, i64, i64, i64, i64, i64); + +extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: i16x8, y: i16x8) -> i64x8; //~ ERROR E0443 +} + +fn main() {} diff --git a/src/test/compile-fail/E0444.rs b/src/test/compile-fail/E0444.rs new file mode 100644 index 0000000000000..a424a3ca20ec0 --- /dev/null +++ b/src/test/compile-fail/E0444.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +struct f64x2(f64, f64); + +extern "platform-intrinsic" { + fn x86_mm_movemask_pd(x: f64x2, y: f64x2, z: f64x2) -> i32; //~ ERROR E0444 +} + +fn main() {} diff --git a/src/test/compile-fail/E0445.rs b/src/test/compile-fail/E0445.rs new file mode 100644 index 0000000000000..6b360c60a0f90 --- /dev/null +++ b/src/test/compile-fail/E0445.rs @@ -0,0 +1,19 @@ +// 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. + +trait Foo { + fn dummy(&self) { } +} + +pub trait Bar : Foo {} //~ ERROR E0445 +pub struct Bar2(pub T); //~ ERROR E0445 +pub fn foo (t: T) {} //~ ERROR E0445 + +fn main() {} diff --git a/src/test/compile-fail/E0446.rs b/src/test/compile-fail/E0446.rs new file mode 100644 index 0000000000000..c576661828471 --- /dev/null +++ b/src/test/compile-fail/E0446.rs @@ -0,0 +1,19 @@ +// 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. + +mod Foo { + struct Bar(u32); + + pub fn bar() -> Bar { //~ ERROR E0446 + Bar(0) + } +} + +fn main() {} diff --git a/src/test/compile-fail/E0449.rs b/src/test/compile-fail/E0449.rs new file mode 100644 index 0000000000000..ac365db33e5cd --- /dev/null +++ b/src/test/compile-fail/E0449.rs @@ -0,0 +1,24 @@ +// 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. + +struct Bar; + +trait Foo { + fn foo(); +} + +pub impl Bar {} //~ ERROR E0449 + +pub impl Foo for Bar { //~ ERROR E0449 + pub fn foo() {} //~ ERROR E0449 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0450.rs b/src/test/compile-fail/E0450.rs new file mode 100644 index 0000000000000..3d76cb9377316 --- /dev/null +++ b/src/test/compile-fail/E0450.rs @@ -0,0 +1,17 @@ +// 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. + +mod Bar { + pub struct Foo(isize); +} + +fn main() { + let f = Bar::Foo(0); //~ ERROR E0450 +} diff --git a/src/test/compile-fail/E0451.rs b/src/test/compile-fail/E0451.rs new file mode 100644 index 0000000000000..9e4a8713a33e0 --- /dev/null +++ b/src/test/compile-fail/E0451.rs @@ -0,0 +1,20 @@ +// 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. + +mod Bar { + pub struct Foo { + pub a: isize, + b: isize, + } +} + +fn main() { + let f = Bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451 +} diff --git a/src/test/compile-fail/E0452.rs b/src/test/compile-fail/E0452.rs new file mode 100644 index 0000000000000..1665bbdd4c2c1 --- /dev/null +++ b/src/test/compile-fail/E0452.rs @@ -0,0 +1,14 @@ +// 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. + +#![allow(foo = "")] //~ ERROR E0452 + +fn main() { +} diff --git a/src/test/compile-fail/E0453.rs b/src/test/compile-fail/E0453.rs new file mode 100644 index 0000000000000..629b373cd7f12 --- /dev/null +++ b/src/test/compile-fail/E0453.rs @@ -0,0 +1,15 @@ +// 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. + +#![forbid(non_snake_case)] + +#[allow(non_snake_case)] //~ ERROR E0453 +fn main() { +} diff --git a/src/test/compile-fail/E0454.rs b/src/test/compile-fail/E0454.rs new file mode 100644 index 0000000000000..1439c3133d9ca --- /dev/null +++ b/src/test/compile-fail/E0454.rs @@ -0,0 +1,14 @@ +// 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 = "")] extern {} //~ ERROR E0454 + +fn main() { +} diff --git a/src/test/compile-fail/E0455.rs b/src/test/compile-fail/E0455.rs new file mode 100644 index 0000000000000..a90f97f89f490 --- /dev/null +++ b/src/test/compile-fail/E0455.rs @@ -0,0 +1,14 @@ +// 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 = "FooCoreServices", kind = "framework")] extern {} //~ ERROR E0455 + +fn main() { +} diff --git a/src/test/compile-fail/E0458.rs b/src/test/compile-fail/E0458.rs new file mode 100644 index 0000000000000..21bedc6b84c2b --- /dev/null +++ b/src/test/compile-fail/E0458.rs @@ -0,0 +1,15 @@ +// 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(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458 + //~^ ERROR E0459 + +fn main() { +} diff --git a/src/test/compile-fail/E0459.rs b/src/test/compile-fail/E0459.rs new file mode 100644 index 0000000000000..dc7ac714f2239 --- /dev/null +++ b/src/test/compile-fail/E0459.rs @@ -0,0 +1,14 @@ +// 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(kind = "dylib")] extern {} //~ ERROR E0459 + +fn main() { +} diff --git a/src/test/compile-fail/E0463.rs b/src/test/compile-fail/E0463.rs new file mode 100644 index 0000000000000..3eff107365af1 --- /dev/null +++ b/src/test/compile-fail/E0463.rs @@ -0,0 +1,16 @@ +// 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. + +#![feature(plugin)] +#![plugin(cookie_monster)] //~ ERROR E0463 +extern crate cake_is_a_lie; + +fn main() { +} From 06147ac29152877830454330c16fd82f23d050df Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Fri, 19 Aug 2016 12:35:54 -0400 Subject: [PATCH 165/768] replace `Not` example with something more evocative --- src/libcore/ops.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..67c25d42f1f4d 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -538,26 +538,31 @@ neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Not`. When `!Foo` happens, it ends up calling -/// `not`, and therefore, `main` prints `Not-ing!`. +/// An implementation of `Not` for `Answer`, which enables the use of `!` to +/// invert its value. /// /// ``` /// use std::ops::Not; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// enum Answer { +/// Yes, +/// No, +/// } /// -/// impl Not for Foo { -/// type Output = Foo; +/// impl Not for Answer { +/// type Output = Answer; /// -/// fn not(self) -> Foo { -/// println!("Not-ing!"); -/// self +/// fn not(self) -> Answer { +/// match self { +/// Answer::Yes => Answer::No, +/// Answer::No => Answer::Yes +/// } /// } /// } /// -/// fn main() { -/// !Foo; -/// } +/// assert_eq!(!Answer::Yes, Answer::No); +/// assert_eq!(!Answer::No, Answer::Yes); /// ``` #[lang = "not"] #[stable(feature = "rust1", since = "1.0.0")] From c0eccb120326bc559a4cbe30ace4935d83420073 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Fri, 19 Aug 2016 12:46:11 -0400 Subject: [PATCH 166/768] replace `Neg` example with something more evocative of negation --- src/libcore/ops.rs | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..73979d84ad314 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -470,26 +470,37 @@ rem_impl_float! { f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Neg`. When `-Foo` happens, it ends up calling -/// `neg`, and therefore, `main` prints `Negating!`. +/// An implementation of `Neg` for `Sign`, which allows the use of `-` to +/// negate its value. /// /// ``` /// use std::ops::Neg; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// enum Sign { +/// Negative, +/// Zero, +/// Positive, +/// } /// -/// impl Neg for Foo { -/// type Output = Foo; +/// impl Neg for Sign { +/// type Output = Sign; /// -/// fn neg(self) -> Foo { -/// println!("Negating!"); -/// self +/// fn neg(self) -> Sign { +/// match self { +/// Sign::Negative => Sign::Positive, +/// Sign::Zero => Sign::Zero, +/// Sign::Positive => Sign::Negative, +/// } /// } /// } /// -/// fn main() { -/// -Foo; -/// } +/// // a negative positive is a negative +/// assert_eq!(-Sign::Positive, Sign::Negative); +/// // a double negative is a positive +/// assert_eq!(-Sign::Negative, Sign::Positive); +/// // zero is its own negation +/// assert_eq!(-Sign::Zero, Sign::Zero); /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] From 1cf510d1decf5a1a450c9c60e6dd71f402b4c307 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 18 Aug 2016 17:55:22 -0700 Subject: [PATCH 167/768] rustc: Don't enable NEON by default on armv7 Linux One of the primary platforms for the `armv7-unknown-linux-gnueabihf` target, Linux distributions, do not enable NEON extensions by default. This PR disables that feature by defualt but enables the `d16` feature which enables VFP3D16 that distributions do enable. Closes #35590 --- src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 52269f0cd4a08..7e0306a03e2f6 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -23,8 +23,9 @@ pub fn target() -> TargetResult { target_vendor: "unknown".to_string(), options: TargetOptions { - features: "+v7,+vfp3,+neon".to_string(), - cpu: "cortex-a8".to_string(), + // Info about features at https://wiki.debian.org/ArmHardFloatPort + features: "+v7,+vfp3,+d16,+thumb2".to_string(), + cpu: "generic".to_string(), max_atomic_width: 64, .. base } From 3b64cf669cef3aec090b2c6fa6ba7b8b23d4ba97 Mon Sep 17 00:00:00 2001 From: trixnz Date: Fri, 19 Aug 2016 19:19:34 +0200 Subject: [PATCH 168/768] Update E0428 to new format --- src/librustc_resolve/lib.rs | 6 +++++- src/test/compile-fail/E0428.rs | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b91ede5b2fa8a..af39f8a415c67 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3382,7 +3382,11 @@ impl<'a> Resolver<'a> { }, (true, _) | (_, true) => struct_span_err!(self.session, span, E0260, "{}", msg), _ => match (old_binding.is_import(), binding.is_import()) { - (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), + (false, false) => { + let mut e = struct_span_err!(self.session, span, E0428, "{}", msg); + e.span_label(span, &format!("already defined")); + e + }, (true, true) => { let mut e = struct_span_err!(self.session, span, E0252, "{}", msg); e.span_label(span, &format!("already imported")); diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs index 42e237d31cbee..63b4efb73f0c5 100644 --- a/src/test/compile-fail/E0428.rs +++ b/src/test/compile-fail/E0428.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Bar; +struct Bar; //~ previous definition of `Bar` here + //~| previous definition of `Bar` here struct Bar; //~ ERROR E0428 - //~^ ERROR E0428 + //~| NOTE already defined + //~| ERROR E0428 + //~| NOTE already defined fn main () { } From afeeadeae5094a374821a32cc78a47109c7304ea Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Aug 2016 14:08:24 -0700 Subject: [PATCH 169/768] std: Stabilize APIs for the 1.12 release Stabilized * `Cell::as_ptr` * `RefCell::as_ptr` * `IpAddr::is_{unspecified,loopback,multicast}` * `Ipv6Addr::octets` * `LinkedList::contains` * `VecDeque::contains` * `ExitStatusExt::from_raw` - both on Unix and Windows * `Receiver::recv_timeout` * `RecvTimeoutError` * `BinaryHeap::peek_mut` * `PeekMut` * `iter::Product` * `iter::Sum` * `OccupiedEntry::remove_entry` * `VacantEntry::into_key` Deprecated * `Cell::as_unsafe_cell` * `RefCell::as_unsafe_cell` * `OccupiedEntry::remove_pair` Closes #27708 cc #27709 Closes #32313 Closes #32630 Closes #32713 Closes #34029 Closes #34392 Closes #34285 Closes #34529 --- src/libcollections/binary_heap.rs | 11 ++++---- src/libcollections/btree/map.rs | 19 ++++++++------ src/libcollections/linked_list.rs | 5 +--- src/libcollections/vec_deque.rs | 5 +--- src/libcollectionstest/lib.rs | 3 --- src/libcore/cell.rs | 36 +++++++++++++++++++++++++++ src/libcore/iter/traits.rs | 22 ++++++++-------- src/libcoretest/cell.rs | 10 ++++---- src/libcoretest/lib.rs | 1 - src/libstd/collections/hash/map.rs | 19 ++++++++------ src/libstd/net/ip.rs | 15 ++++------- src/libstd/sync/mpsc/mod.rs | 8 +++--- src/libstd/sys/unix/ext/process.rs | 2 +- src/libstd/sys/windows/ext/process.rs | 3 ++- src/libtest/lib.rs | 1 - 15 files changed, 94 insertions(+), 66 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b9f5c6fcab909..fe9b60c393f09 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -223,19 +223,19 @@ pub struct BinaryHeap { /// on `BinaryHeap`. See its documentation for details. /// /// [`peek_mut()`]: struct.BinaryHeap.html#method.peek_mut -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap } -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] impl<'a, T: Ord> Drop for PeekMut<'a, T> { fn drop(&mut self) { self.heap.sift_down(0); } } -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] impl<'a, T: Ord> Deref for PeekMut<'a, T> { type Target = T; fn deref(&self) -> &T { @@ -243,7 +243,7 @@ impl<'a, T: Ord> Deref for PeekMut<'a, T> { } } -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] impl<'a, T: Ord> DerefMut for PeekMut<'a, T> { fn deref_mut(&mut self) -> &mut T { &mut self.heap.data[0] @@ -366,7 +366,6 @@ impl BinaryHeap { /// Basic usage: /// /// ``` - /// #![feature(binary_heap_peek_mut)] /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); /// assert!(heap.peek_mut().is_none()); @@ -380,7 +379,7 @@ impl BinaryHeap { /// } /// assert_eq!(heap.peek(), Some(&2)); /// ``` - #[unstable(feature = "binary_heap_peek_mut", issue = "34392")] + #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index c3a7d4023754a..a2e2ad37acb84 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1981,8 +1981,6 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::BTreeMap; /// use std::collections::btree_map::Entry; /// @@ -1992,7 +1990,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// v.into_key(); /// } /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn into_key(self) -> K { self.key } @@ -2074,13 +2072,18 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { self.handle.reborrow().into_kv().0 } + /// Deprecated, renamed to `remove_entry` + #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] + pub fn remove_pair(self) -> (K, V) { + self.remove_entry() + } + /// Take ownership of the key and value from the map. /// /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::BTreeMap; /// use std::collections::btree_map::Entry; /// @@ -2089,14 +2092,14 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// /// if let Entry::Occupied(o) = map.entry("poneyland") { /// // We delete the entry from the map. - /// o.remove_pair(); + /// o.remove_entry(); /// } /// /// // If now try to get the value, it will panic: /// // println!("{}", map["poneyland"]); /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - pub fn remove_pair(self) -> (K, V) { + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { self.remove_kv() } diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 6842f02e0e19b..73aa67849fd2a 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -379,8 +379,6 @@ impl LinkedList { /// # Examples /// /// ``` - /// #![feature(linked_list_contains)] - /// /// use std::collections::LinkedList; /// /// let mut list: LinkedList = LinkedList::new(); @@ -392,8 +390,7 @@ impl LinkedList { /// assert_eq!(list.contains(&0), true); /// assert_eq!(list.contains(&10), false); /// ``` - #[unstable(feature = "linked_list_contains", reason = "recently added", - issue = "32630")] + #[stable(feature = "linked_list_contains", since = "1.12.0")] pub fn contains(&self, x: &T) -> bool where T: PartialEq { diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 812a67a7e78ed..ce5635714b5b8 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -939,8 +939,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vec_deque_contains)] - /// /// use std::collections::VecDeque; /// /// let mut vector: VecDeque = VecDeque::new(); @@ -951,8 +949,7 @@ impl VecDeque { /// assert_eq!(vector.contains(&1), true); /// assert_eq!(vector.contains(&10), false); /// ``` - #[unstable(feature = "vec_deque_contains", reason = "recently added", - issue = "32630")] + #[stable(feature = "vec_deque_contains", since = "1.12.0")] pub fn contains(&self, x: &T) -> bool where T: PartialEq { diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index ab3231b2b9955..f448fcf2dbf99 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -11,7 +11,6 @@ #![deny(warnings)] #![feature(binary_heap_extras)] -#![feature(binary_heap_peek_mut)] #![feature(box_syntax)] #![feature(btree_range)] #![feature(collections)] @@ -19,7 +18,6 @@ #![feature(const_fn)] #![feature(fn_traits)] #![feature(enumset)] -#![feature(linked_list_contains)] #![feature(pattern)] #![feature(rand)] #![feature(step_by)] @@ -27,7 +25,6 @@ #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(vec_deque_contains)] #![feature(vec_into_iter_as_slice)] extern crate collections; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 17ec325e257b0..a388012e1daf2 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -233,10 +233,28 @@ impl Cell { /// ``` #[inline] #[unstable(feature = "as_unsafe_cell", issue = "27708")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] pub fn as_unsafe_cell(&self) -> &UnsafeCell { &self.value } + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + /// Returns a mutable reference to the underlying data. /// /// This call borrows `Cell` mutably (at compile-time) which guarantees @@ -653,10 +671,28 @@ impl RefCell { /// ``` #[inline] #[unstable(feature = "as_unsafe_cell", issue = "27708")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell { &self.value } + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::RefCell; + /// + /// let c = RefCell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + /// Returns a mutable reference to the underlying data. /// /// This call borrows `RefCell` mutably (at compile-time) so there is no diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 4cbabe3f5edaf..cb509156e325e 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -563,10 +563,11 @@ impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {} /// implement the trait can be generated by the `sum` method. Like /// `FromIterator` this trait should rarely be called directly and instead /// interacted with through `Iterator::sum`. -#[unstable(feature = "iter_arith_traits", issue = "34529")] +#[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// "summing up" the items. + #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn sum>(iter: I) -> Self; } @@ -577,16 +578,17 @@ pub trait Sum: Sized { /// which implement the trait can be generated by the `product` method. Like /// `FromIterator` this trait should rarely be called directly and instead /// interacted with through `Iterator::product`. -#[unstable(feature = "iter_arith_traits", issue = "34529")] +#[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// multiplying the items. + #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn product>(iter: I) -> Self; } macro_rules! integer_sum_product { ($($a:ident)*) => ($( - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum>(iter: I) -> $a { iter.fold(0, |a, b| { @@ -595,7 +597,7 @@ macro_rules! integer_sum_product { } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { iter.fold(1, |a, b| { @@ -604,7 +606,7 @@ macro_rules! integer_sum_product { } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { iter.fold(0, |a, b| { @@ -613,7 +615,7 @@ macro_rules! integer_sum_product { } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { iter.fold(1, |a, b| { @@ -626,28 +628,28 @@ macro_rules! integer_sum_product { macro_rules! float_sum_product { ($($a:ident)*) => ($( - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum>(iter: I) -> $a { iter.fold(0.0, |a, b| a + b) } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { iter.fold(1.0, |a, b| a * b) } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { iter.fold(0.0, |a, b| a + *b) } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { iter.fold(1.0, |a, b| a * *b) diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index a635620d12abd..a7c230ba979be 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -176,21 +176,21 @@ fn ref_mut_map_accessor() { } #[test] -fn as_unsafe_cell() { +fn as_ptr() { let c1: Cell = Cell::new(0); c1.set(1); - assert_eq!(1, unsafe { *c1.as_unsafe_cell().get() }); + assert_eq!(1, unsafe { *c1.as_ptr() }); let c2: Cell = Cell::new(0); - unsafe { *c2.as_unsafe_cell().get() = 1; } + unsafe { *c2.as_ptr() = 1; } assert_eq!(1, c2.get()); let r1: RefCell = RefCell::new(0); *r1.borrow_mut() = 1; - assert_eq!(1, unsafe { *r1.as_unsafe_cell().get() }); + assert_eq!(1, unsafe { *r1.as_ptr() }); let r2: RefCell = RefCell::new(0); - unsafe { *r2.as_unsafe_cell().get() = 1; } + unsafe { *r2.as_ptr() = 1; } assert_eq!(1, *r2.borrow()); } diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 9428b4096bfec..9116344c57938 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(as_unsafe_cell)] #![feature(borrow_state)] #![feature(box_syntax)] #![feature(cell_extras)] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index cf6f76f914a15..3d3e3941bac1f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1640,13 +1640,18 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { self.elem.read().0 } + /// Deprecated, renamed to `remove_entry` + #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] + pub fn remove_pair(self) -> (K, V) { + self.remove_entry() + } + /// Take the ownership of the key and value from the map. /// /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -1655,13 +1660,13 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// if let Entry::Occupied(o) = map.entry("poneyland") { /// // We delete the entry from the map. - /// o.remove_pair(); + /// o.remove_entry(); /// } /// /// assert_eq!(map.contains_key("poneyland"), false); /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - pub fn remove_pair(self) -> (K, V) { + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { pop_internal(self.elem) } @@ -1808,8 +1813,6 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -1819,7 +1822,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// v.into_key(); /// } /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn into_key(self) -> K { self.key } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 2a8bd0c88beb6..4c3b993497cf5 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -63,8 +63,7 @@ impl IpAddr { /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified - #[unstable(feature="ip", issue="27709", - reason="recently added and depends on unstable Ipv4Addr.is_unspecified()")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_unspecified(), @@ -75,7 +74,7 @@ impl IpAddr { /// Returns true if this is a loopback address ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback - #[unstable(feature="ip", reason="recently added", issue="27709")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_loopback(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_loopback(), @@ -86,8 +85,6 @@ impl IpAddr { /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global - #[unstable(feature="ip", issue="27709", - reason="recently added and depends on unstable Ip{v4,v6}Addr.is_global()")] pub fn is_global(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_global(), @@ -98,7 +95,7 @@ impl IpAddr { /// Returns true if this is a multicast address ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast - #[unstable(feature="ip", reason="recently added", issue="27709")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_multicast(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_multicast(), @@ -109,8 +106,6 @@ impl IpAddr { /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation - #[unstable(feature="ip", issue="27709", - reason="recently added and depends on unstable Ipv6Addr.is_documentation()")] pub fn is_documentation(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_documentation(), @@ -147,6 +142,7 @@ impl Ipv4Addr { /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7] /// [ip7][http://man7.org/linux/man-pages/man7/ip.7.html] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 } @@ -515,8 +511,7 @@ impl Ipv6Addr { } /// Returns the sixteen eight-bit integers the IPv6 address consists of. - #[unstable(feature = "ipv6_to_octets", reason = "needs some testing", - issue = "32313")] + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] pub fn octets(&self) -> [u8; 16] { self.inner.s6_addr } diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 11f785dffd16a..d8b8c6a77a266 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -394,13 +394,15 @@ pub enum TryRecvError { /// This enumeration is the list of possible errors that `recv_timeout` could /// not return data when called. #[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[unstable(feature = "mpsc_recv_timeout", issue = "34029")] +#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { /// This channel is currently empty, but the sender(s) have not yet /// disconnected, so data may yet become available. + #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Timeout, /// This channel's sending half has become disconnected, and there will /// never be any more data received on this channel + #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Disconnected, } @@ -912,8 +914,6 @@ impl Receiver { /// # Examples /// /// ```no_run - /// #![feature(mpsc_recv_timeout)] - /// /// use std::sync::mpsc::{self, RecvTimeoutError}; /// use std::time::Duration; /// @@ -922,7 +922,7 @@ impl Receiver { /// let timeout = Duration::from_millis(100); /// assert_eq!(Err(RecvTimeoutError::Timeout), recv.recv_timeout(timeout)); /// ``` - #[unstable(feature = "mpsc_recv_timeout", issue = "34029")] + #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub fn recv_timeout(&self, timeout: Duration) -> Result { // Do an optimistic try_recv to avoid the performance impact of // Instant::now() in the full-channel case. diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 430ec5f94a6f8..dd70ba2e490ad 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -114,7 +114,7 @@ impl CommandExt for process::Command { pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of /// a process. - #[unstable(feature = "exit_status_from", issue = "32713")] + #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: i32) -> Self; /// If the process was terminated by a signal, returns that signal. diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 56c6a73d4f82b..98166bf8cda09 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -83,10 +83,11 @@ impl IntoRawHandle for process::ChildStderr { } /// Windows-specific extensions to `std::process::ExitStatus` -#[unstable(feature = "exit_status_from", issue = "32713")] +#[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of /// a process. + #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: u32) -> Self; } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 850127d9f2950..2b4193306ddf5 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -42,7 +42,6 @@ #![feature(staged_api)] #![feature(question_mark)] #![feature(panic_unwind)] -#![feature(mpsc_recv_timeout)] extern crate getopts; extern crate term; From fce605e1f28563b115ad8c18372bd4d8e3b8f1a6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 18 Aug 2016 17:08:25 +0000 Subject: [PATCH 170/768] Remove old stage0 compatibility --- src/libcore/cmp.rs | 45 +++++++++++++------------------- src/libcore/fmt/mod.rs | 29 +++++++------------- src/libcore/lib.rs | 6 +---- src/libpanic_unwind/gcc.rs | 24 ----------------- src/libpanic_unwind/seh64_gnu.rs | 15 ----------- 5 files changed, 29 insertions(+), 90 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index bb7c971111853..9bba6cd38e556 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -699,38 +699,29 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } - // Note: This macro is a temporary hack that can be remove once we are building with a compiler - // that supports `!` - macro_rules! not_stage0 { - () => { - #[unstable(feature = "never_type", issue = "35121")] - impl PartialEq for ! { - fn eq(&self, _: &!) -> bool { - *self - } - } + #[unstable(feature = "never_type", issue = "35121")] + impl PartialEq for ! { + fn eq(&self, _: &!) -> bool { + *self + } + } - #[unstable(feature = "never_type", issue = "35121")] - impl Eq for ! {} + #[unstable(feature = "never_type", issue = "35121")] + impl Eq for ! {} - #[unstable(feature = "never_type", issue = "35121")] - impl PartialOrd for ! { - fn partial_cmp(&self, _: &!) -> Option { - *self - } - } - - #[unstable(feature = "never_type", issue = "35121")] - impl Ord for ! { - fn cmp(&self, _: &!) -> Ordering { - *self - } - } + #[unstable(feature = "never_type", issue = "35121")] + impl PartialOrd for ! { + fn partial_cmp(&self, _: &!) -> Option { + *self } } - #[cfg(not(stage0))] - not_stage0!(); + #[unstable(feature = "never_type", issue = "35121")] + impl Ord for ! { + fn cmp(&self, _: &!) -> Ordering { + *self + } + } // & pointers diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index dbd715c722e13..7688da971eb1d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1363,28 +1363,19 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -// Note: This macro is a temporary hack that can be remove once we are building with a compiler -// that supports `!` -macro_rules! not_stage0 { - () => { - #[unstable(feature = "never_type", issue = "35121")] - impl Debug for ! { - fn fmt(&self, _: &mut Formatter) -> Result { - *self - } - } - - #[unstable(feature = "never_type", issue = "35121")] - impl Display for ! { - fn fmt(&self, _: &mut Formatter) -> Result { - *self - } - } +#[unstable(feature = "never_type", issue = "35121")] +impl Debug for ! { + fn fmt(&self, _: &mut Formatter) -> Result { + *self } } -#[cfg(not(stage0))] -not_stage0!(); +#[unstable(feature = "never_type", issue = "35121")] +impl Display for ! { + fn fmt(&self, _: &mut Formatter) -> Result { + *self + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Debug for bool { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 2a9678203e178..fbeddf26b939a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -67,8 +67,6 @@ #![deny(missing_debug_implementations)] #![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(stage0, allow(unused_attributes))] - #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_type_defaults)] @@ -92,9 +90,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(question_mark)] - -// NOTE: remove the cfg_attr next snapshot -#![cfg_attr(not(stage0), feature(never_type))] +#![feature(never_type)] #[macro_use] mod macros; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index fdae8f69a9c0e..bd0c2f5126d13 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -264,30 +264,6 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction { eh::find_eh_action(lsda, &eh_context) } -// *** Delete after a new snapshot *** -#[cfg(all(stage0, any(target_os = "ios", not(target_arch = "arm"))))] -#[lang = "eh_personality_catch"] -#[no_mangle] -pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - rust_eh_personality(version, actions, exception_class, ue_header, context) -} - -// *** Delete after a new snapshot *** -#[cfg(all(stage0, target_arch = "arm", not(target_os = "ios")))] -#[lang = "eh_personality_catch"] -#[no_mangle] -pub unsafe extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - rust_eh_personality(state, ue_header, context) -} - // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 3642e2488958e..e6d3920b29cb0 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -81,21 +81,6 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { // This is considered acceptable, because the behavior of throwing exceptions // through a C ABI boundary is undefined. -// *** Delete after a new snapshot *** -#[cfg(stage0)] -#[lang = "eh_personality_catch"] -#[cfg(not(test))] -unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD, - establisherFrame: c::LPVOID, - contextRecord: *mut c::CONTEXT, - dispatcherContext: *mut c::DISPATCHER_CONTEXT) - -> c::EXCEPTION_DISPOSITION { - rust_eh_personality(exceptionRecord, - establisherFrame, - contextRecord, - dispatcherContext) -} - #[lang = "eh_personality"] #[cfg(not(test))] unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECORD, From 5d02b030598bc1a4e7a0b1255c0eae0f21a5413a Mon Sep 17 00:00:00 2001 From: crypto-universe Date: Fri, 19 Aug 2016 22:31:31 +0200 Subject: [PATCH 171/768] New format for E0426 Issue #35799 as a part of issue #35233 ?r jonathandturner --- src/librustc_resolve/lib.rs | 12 +++++++----- src/test/compile-fail/E0426.rs | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b91ede5b2fa8a..af727de4256ee 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -390,11 +390,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::UndeclaredLabel(name) => { - struct_span_err!(resolver.session, - span, - E0426, - "use of undeclared label `{}`", - name) + let mut err = struct_span_err!(resolver.session, + span, + E0426, + "use of undeclared label `{}`", + name); + err.span_label(span, &format!("undeclared label `{}`",&name)); + err } ResolutionError::SelfImportsOnlyAllowedWithin => { struct_span_err!(resolver.session, diff --git a/src/test/compile-fail/E0426.rs b/src/test/compile-fail/E0426.rs index 2eb4c2d3b5e04..be21421cb0781 100644 --- a/src/test/compile-fail/E0426.rs +++ b/src/test/compile-fail/E0426.rs @@ -10,6 +10,8 @@ fn main () { loop { - break 'a; //~ ERROR E0426 + break 'a; + //~^ ERROR E0426 + //~| NOTE undeclared label `'a` } } From 54d0acd2fc6414930ff27c01c8640f4e9c666ad5 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 19 Aug 2016 16:05:37 -0700 Subject: [PATCH 172/768] wording fixes in error messages --- src/librustc/ty/error.rs | 4 ++-- src/librustc_errors/emitter.rs | 4 +++- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/compare_method.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 9 ++++----- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/diagnostics.rs | 2 +- src/test/compile-fail/E0040.rs | 2 +- src/test/compile-fail/E0053.rs | 6 +++--- src/test/compile-fail/E0087.rs | 2 +- .../compile-fail/associated-const-impl-wrong-type.rs | 2 +- src/test/compile-fail/coerce-mut.rs | 2 +- src/test/compile-fail/fn-variance-1.rs | 4 ++-- src/test/compile-fail/impl-wrong-item-for-trait.rs | 6 +++--- src/test/compile-fail/mut-pattern-mismatched.rs | 4 ++-- src/test/compile-fail/ptr-coercion.rs | 6 +++--- src/test/compile-fail/slice-mut.rs | 2 +- .../trait-impl-fn-incompatibility.stderr | 6 +++--- 18 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 17f9b6c25995c..32c87fb615a53 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -98,9 +98,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { values.expected, values.found) } - Mutability => write!(f, "values differ in mutability"), + Mutability => write!(f, "types differ in mutability"), BoxMutability => { - write!(f, "boxed values differ in mutability") + write!(f, "boxed types differ in mutability") } VecMutability => write!(f, "vectors differ in mutability"), PtrMutability => write!(f, "pointers differ in mutability"), diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 5fd9226aba9d4..793155cfa8f8f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -426,7 +426,9 @@ impl EmitterWriter { continue; } // Check to make sure we're not in any <*macros> - if !cm.span_to_filename(def_site).contains("macros>") { + if !cm.span_to_filename(def_site).contains("macros>") && + !trace.macro_decl_name.starts_with("#[") + { new_labels.push((trace.call_site, "in this macro invocation".to_string())); break; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 985c3be149617..acb6653214dcb 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -29,7 +29,7 @@ use rustc::hir; pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) { if ccx.tcx.lang_items.drop_trait() == Some(trait_id) { struct_span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method") - .span_label(span, &format!("call to destructor method")) + .span_label(span, &format!("explicit destructor calls not allowed")) .emit(); } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 043883df035d0..0e42990a337d4 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -402,7 +402,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, infcx.note_type_err( &mut diag, origin, - trait_err_span.map(|sp| (sp, format!("original trait requirement"))), + trait_err_span.map(|sp| (sp, format!("type in trait"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_fty, found: impl_fty @@ -575,7 +575,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, infcx.note_type_err( &mut diag, origin, - Some((trait_c_span, format!("original trait requirement"))), + Some((trait_c_span, format!("type in trait"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_ty, found: impl_ty diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ff0b86aa59540..ca78345556926 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1013,7 +1013,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // We can only get the spans from local trait definition // Same for E0324 and E0325 if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { - err.span_label(trait_span, &format!("original trait requirement")); + err.span_label(trait_span, &format!("item in trait")); } err.emit() } @@ -1041,7 +1041,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { - err.span_label(trait_span, &format!("original trait requirement")); + err.span_label(trait_span, &format!("item in trait")); } err.emit() } @@ -1064,7 +1064,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { - err.span_label(trait_span, &format!("original trait requirement")); + err.span_label(trait_span, &format!("item in trait")); } err.emit() } @@ -4408,8 +4408,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected at most {}, found {}", count(type_defs.len()), count(types.len())) - .span_label(span, &format!("expected {}", - count(type_defs.len()))).emit(); + .span_label(span, &format!("too many type parameters")).emit(); // To prevent derived errors to accumulate due to extra // type parameters, we force instantiate_value_path to diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 7578ec3d813c1..a3c043fe7cbd3 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -37,7 +37,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "cannot define inherent `impl` for a type outside of the \ crate where the type is defined") .span_label(item.span, &format!("impl for type defined outside of crate.")) - .span_note(item.span, &format!("define and implement a trait or new type instead")) + .note("define and implement a trait or new type instead") .emit(); } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index fe1cb3d6badcd..8bb5efdcad2c3 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -572,7 +572,7 @@ impl Foo for Bar { // error, expected u16, found i16 fn foo(x: i16) { } - // error, values differ in mutability + // error, types differ in mutability fn bar(&mut self) { } } ``` diff --git a/src/test/compile-fail/E0040.rs b/src/test/compile-fail/E0040.rs index 80ff57c363595..edfe22186e162 100644 --- a/src/test/compile-fail/E0040.rs +++ b/src/test/compile-fail/E0040.rs @@ -22,5 +22,5 @@ fn main() { let mut x = Foo { x: -7 }; x.drop(); //~^ ERROR E0040 - //~| NOTE call to destructor method + //~| NOTE explicit destructor calls not allowed } diff --git a/src/test/compile-fail/E0053.rs b/src/test/compile-fail/E0053.rs index 7022010714aa7..933462e553e3b 100644 --- a/src/test/compile-fail/E0053.rs +++ b/src/test/compile-fail/E0053.rs @@ -9,8 +9,8 @@ // except according to those terms. trait Foo { - fn foo(x: u16); //~ NOTE original trait requirement - fn bar(&self); //~ NOTE original trait requirement + fn foo(x: u16); //~ NOTE type in trait + fn bar(&self); //~ NOTE type in trait } struct Bar; @@ -21,7 +21,7 @@ impl Foo for Bar { //~| NOTE expected u16 fn bar(&mut self) { } //~^ ERROR method `bar` has an incompatible type for trait - //~| NOTE values differ in mutability + //~| NOTE types differ in mutability //~| NOTE expected type `fn(&Bar)` //~| NOTE found type `fn(&mut Bar)` } diff --git a/src/test/compile-fail/E0087.rs b/src/test/compile-fail/E0087.rs index 437ad3698a206..7c98de59e2797 100644 --- a/src/test/compile-fail/E0087.rs +++ b/src/test/compile-fail/E0087.rs @@ -12,5 +12,5 @@ fn foo() {} fn main() { foo::(); //~ ERROR E0087 - //~^ NOTE expected + //~^ NOTE too many type parameters } diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index b3776091682da..ec495c87b1a3f 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -11,7 +11,7 @@ #![feature(associated_consts)] trait Foo { - const BAR: u32; //~ NOTE original trait requirement + const BAR: u32; //~ NOTE type in trait } struct SignedBar; diff --git a/src/test/compile-fail/coerce-mut.rs b/src/test/compile-fail/coerce-mut.rs index 86702a7463fd0..bc3d58ef33db0 100644 --- a/src/test/compile-fail/coerce-mut.rs +++ b/src/test/compile-fail/coerce-mut.rs @@ -16,5 +16,5 @@ fn main() { //~^ ERROR mismatched types //~| expected type `&mut i32` //~| found type `&{integer}` - //~| values differ in mutability + //~| types differ in mutability } diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/compile-fail/fn-variance-1.rs index e9dd1cb719dbc..d0d911b6eb936 100644 --- a/src/test/compile-fail/fn-variance-1.rs +++ b/src/test/compile-fail/fn-variance-1.rs @@ -19,9 +19,9 @@ fn apply(t: T, f: F) where F: FnOnce(T) { fn main() { apply(&3, takes_imm); apply(&3, takes_mut); - //~^ ERROR (values differ in mutability) + //~^ ERROR (types differ in mutability) apply(&mut 3, takes_mut); apply(&mut 3, takes_imm); - //~^ ERROR (values differ in mutability) + //~^ ERROR (types differ in mutability) } diff --git a/src/test/compile-fail/impl-wrong-item-for-trait.rs b/src/test/compile-fail/impl-wrong-item-for-trait.rs index e0ea1a4cac58b..388c9a1729cca 100644 --- a/src/test/compile-fail/impl-wrong-item-for-trait.rs +++ b/src/test/compile-fail/impl-wrong-item-for-trait.rs @@ -12,9 +12,9 @@ trait Foo { fn bar(&self); - //~^ NOTE original trait requirement - //~| NOTE original trait requirement - const MY_CONST: u32; //~ NOTE original trait requirement + //~^ NOTE item in trait + //~| NOTE item in trait + const MY_CONST: u32; //~ NOTE item in trait } pub struct FooConstForMethod; diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs index 318d121e4c2df..7685a5c0808a2 100644 --- a/src/test/compile-fail/mut-pattern-mismatched.rs +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -16,7 +16,7 @@ fn main() { let &_ //~ ERROR mismatched types //~| expected type `&mut {integer}` //~| found type `&_` - //~| values differ in mutability + //~| types differ in mutability = foo; let &mut _ = foo; @@ -25,6 +25,6 @@ fn main() { let &mut _ //~ ERROR mismatched types //~| expected type `&{integer}` //~| found type `&mut _` - //~| values differ in mutability + //~| types differ in mutability = bar; } diff --git a/src/test/compile-fail/ptr-coercion.rs b/src/test/compile-fail/ptr-coercion.rs index ff627e69d4c58..1390c9507c1c2 100644 --- a/src/test/compile-fail/ptr-coercion.rs +++ b/src/test/compile-fail/ptr-coercion.rs @@ -17,17 +17,17 @@ pub fn main() { let x: *mut isize = x; //~ ERROR mismatched types //~| expected type `*mut isize` //~| found type `*const isize` - //~| values differ in mutability + //~| types differ in mutability // & -> *mut let x: *mut isize = &42; //~ ERROR mismatched types //~| expected type `*mut isize` //~| found type `&isize` - //~| values differ in mutability + //~| types differ in mutability let x: *const isize = &42; let x: *mut isize = x; //~ ERROR mismatched types //~| expected type `*mut isize` //~| found type `*const isize` - //~| values differ in mutability + //~| types differ in mutability } diff --git a/src/test/compile-fail/slice-mut.rs b/src/test/compile-fail/slice-mut.rs index 874cca8cb3fd0..bee3704a353d3 100644 --- a/src/test/compile-fail/slice-mut.rs +++ b/src/test/compile-fail/slice-mut.rs @@ -18,5 +18,5 @@ fn main() { //~^ ERROR mismatched types //~| expected type `&mut [_]` //~| found type `&[isize]` - //~| values differ in mutability + //~| types differ in mutability } diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index e5dfdc8e910df..4a0ccc46525d0 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -2,7 +2,7 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/trait-impl-fn-incompatibility.rs:21:15 | 14 | fn foo(x: u16); - | --- original trait requirement + | --- type in trait ... 21 | fn foo(x: i16) { } | ^^^ expected u16, found i16 @@ -11,10 +11,10 @@ error[E0053]: method `bar` has an incompatible type for trait --> $DIR/trait-impl-fn-incompatibility.rs:22:28 | 15 | fn bar(&mut self, bar: &mut Bar); - | -------- original trait requirement + | -------- type in trait ... 22 | fn bar(&mut self, bar: &Bar) { } - | ^^^^ values differ in mutability + | ^^^^ types differ in mutability | = note: expected type `fn(&mut Bar, &mut Bar)` = note: found type `fn(&mut Bar, &Bar)` From f7961126b5310a25d595304c3534d789b2df9d64 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Fri, 19 Aug 2016 21:12:36 -0400 Subject: [PATCH 173/768] Fix typos in unix/rwlock.rs --- src/libstd/sys/unix/rwlock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 08aeb5fb8ccde..c754d5b8359a9 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -45,10 +45,10 @@ impl RWLock { // We roughly maintain the deadlocking behavior by panicking to ensure // that this lock acquisition does not succeed. // - // We also check whether there this lock is already write locked. This + // We also check whether this lock is already write locked. This // is only possible if it was write locked by the current thread and // the implementation allows recursive locking. The POSIX standard - // doesn't require recursivly locking a rwlock to deadlock, but we can't + // doesn't require recursively locking a rwlock to deadlock, but we can't // allow that because it could lead to aliasing issues. if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); From be8df50c9f3a8e9801ede314e6ab96395c349711 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Fri, 19 Aug 2016 21:44:46 -0600 Subject: [PATCH 174/768] Check that executable file is in-tree before failing tidy check. --- src/tools/tidy/src/bins.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index e91b8fb0967a8..876ae404bbaed 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -24,6 +24,7 @@ pub fn check(_path: &Path, _bad: &mut bool) {} #[cfg(unix)] pub fn check(path: &Path, bad: &mut bool) { use std::fs; + use std::process::{Command, Stdio}; use std::os::unix::prelude::*; super::walk(path, @@ -37,8 +38,22 @@ pub fn check(path: &Path, bad: &mut bool) { let metadata = t!(fs::symlink_metadata(&file), &file); if metadata.mode() & 0o111 != 0 { - println!("binary checked into source: {}", file.display()); - *bad = true; + let rel_path = file.strip_prefix(path).unwrap(); + let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); + let ret_code = Command::new("git") + .arg("ls-files") + .arg(&git_friendly_path) + .current_dir(path) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .unwrap_or_else(|e| { + panic!("could not run git ls-files: {}", e); + }); + if ret_code.success() { + println!("binary checked into source: {}", file.display()); + *bad = true; + } } }) } From c08b7b9f754c6969e3cc630cfea76a8b8ce8876b Mon Sep 17 00:00:00 2001 From: Nikita Baksalyar Date: Sat, 13 Aug 2016 14:09:43 +0500 Subject: [PATCH 175/768] Fix linker on Solaris/Illumos Solaris linker doesn't support the `--retain-symbols-file` option, so this patch provides version scripts as an alternative on that platform. --- src/librustc_trans/back/linker.rs | 58 +++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index cb990ead8e81e..f2d5b128d2705 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -247,29 +247,49 @@ impl<'a> Linker for GnuLinker<'a> { return } + let mut arg = OsString::new(); let path = tmpdir.join("list"); - let prefix = if self.sess.target.target.options.is_like_osx { - "_" - } else { - "" - }; - let res = (|| -> io::Result<()> { - let mut f = BufWriter::new(File::create(&path)?); - for sym in &self.info.cdylib_exports { - writeln!(f, "{}{}", prefix, sym)?; + + if self.sess.target.target.options.is_like_solaris { + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + writeln!(f, "{{\n global:")?; + for sym in &self.info.cdylib_exports { + writeln!(f, " {};", sym)?; + } + writeln!(f, "\n local:\n *;\n}};")?; + Ok(()) + })(); + if let Err(e) = res { + self.sess.fatal(&format!("failed to write version script: {}", e)); } - Ok(()) - })(); - if let Err(e) = res { - self.sess.fatal(&format!("failed to write lib.def file: {}", e)); - } - let mut arg = OsString::new(); - if self.sess.target.target.options.is_like_osx { - arg.push("-Wl,-exported_symbols_list,"); + + arg.push("-Wl,-M,"); + arg.push(&path); } else { - arg.push("-Wl,--retain-symbols-file="); + let prefix = if self.sess.target.target.options.is_like_osx { + "_" + } else { + "" + }; + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + for sym in &self.info.cdylib_exports { + writeln!(f, "{}{}", prefix, sym)?; + } + Ok(()) + })(); + if let Err(e) = res { + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); + } + if self.sess.target.target.options.is_like_osx { + arg.push("-Wl,-exported_symbols_list,"); + } else { + arg.push("-Wl,--retain-symbols-file="); + } + arg.push(&path); } - arg.push(&path); + self.cmd.arg(arg); } } From d791aa1b3f2d67720f1baba31bf1f1a5e7988b8f Mon Sep 17 00:00:00 2001 From: trixnz Date: Sat, 20 Aug 2016 12:10:41 +0200 Subject: [PATCH 176/768] Fix broken tests for E0428 --- src/test/compile-fail/enum-and-module-in-same-scope.rs | 3 ++- src/test/compile-fail/issue-21546.rs | 6 ++++++ src/test/compile-fail/trait-duplicate-methods.rs | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/enum-and-module-in-same-scope.rs b/src/test/compile-fail/enum-and-module-in-same-scope.rs index a6793ee8b9fbd..527ac7505a654 100644 --- a/src/test/compile-fail/enum-and-module-in-same-scope.rs +++ b/src/test/compile-fail/enum-and-module-in-same-scope.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Foo { //~ NOTE previous definition +enum Foo { //~ NOTE previous definition of `Foo` here X } mod Foo { //~ ERROR a type named `Foo` has already been defined + //~| NOTE already defined pub static X: isize = 42; fn f() { f() } // Check that this does not result in a resolution error } diff --git a/src/test/compile-fail/issue-21546.rs b/src/test/compile-fail/issue-21546.rs index 11d05ceb9a019..d103d45bc4cb7 100644 --- a/src/test/compile-fail/issue-21546.rs +++ b/src/test/compile-fail/issue-21546.rs @@ -17,6 +17,7 @@ mod Foo { } #[allow(dead_code)] struct Foo; //~^ ERROR a module named `Foo` has already been defined in this module +//~| NOTE already defined #[allow(non_snake_case)] mod Bar { } @@ -25,6 +26,7 @@ mod Bar { } #[allow(dead_code)] struct Bar(i32); //~^ ERROR a module named `Bar` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -34,6 +36,7 @@ struct Baz(i32); #[allow(non_snake_case)] mod Baz { } //~^ ERROR a type named `Baz` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -43,6 +46,7 @@ struct Qux { x: bool } #[allow(non_snake_case)] mod Qux { } //~^ ERROR a type named `Qux` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -52,6 +56,7 @@ struct Quux; #[allow(non_snake_case)] mod Quux { } //~^ ERROR a type named `Quux` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -61,5 +66,6 @@ enum Corge { A, B } #[allow(non_snake_case)] mod Corge { } //~^ ERROR a type named `Corge` has already been defined +//~| NOTE already defined fn main() { } diff --git a/src/test/compile-fail/trait-duplicate-methods.rs b/src/test/compile-fail/trait-duplicate-methods.rs index 41700b25bbb72..7bcab1f6ac56b 100644 --- a/src/test/compile-fail/trait-duplicate-methods.rs +++ b/src/test/compile-fail/trait-duplicate-methods.rs @@ -11,6 +11,7 @@ trait Foo { fn orange(&self); //~ NOTE previous definition of `orange` here fn orange(&self); //~ ERROR a value named `orange` has already been defined in this trait + //~| NOTE already define } fn main() {} From 6bd80d11163771293ea7bf75a4513af76b754a41 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 19 Aug 2016 07:23:36 -0400 Subject: [PATCH 177/768] compute and cache HIR hashes at beginning This avoids the compile-time overhead of computing them twice. It also fixes an issue where the hash computed after typeck is differen than the hash before, because typeck mutates the def-map in place. Fixes #35549. Fixes #35593. --- src/librustc/hir/mod.rs | 2 +- src/librustc_driver/driver.rs | 33 ++-- src/librustc_driver/pretty.rs | 4 +- src/librustc_incremental/calculate_svh/mod.rs | 160 ++++++++++-------- .../calculate_svh/svh_visitor.rs | 48 +++--- src/librustc_incremental/lib.rs | 3 +- src/librustc_incremental/persist/hash.rs | 33 ++-- src/librustc_incremental/persist/load.rs | 21 ++- src/librustc_incremental/persist/save.rs | 5 +- src/librustc_trans/back/link.rs | 12 +- src/librustc_trans/base.rs | 6 +- src/librustdoc/core.rs | 2 +- src/test/incremental/string_constant.rs | 10 +- 13 files changed, 182 insertions(+), 157 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d41cdfabdf4c0..99fb2d6a44905 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1621,7 +1621,7 @@ pub type FreevarMap = NodeMap>; pub type CaptureModeMap = NodeMap; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct TraitCandidate { pub def_id: DefId, pub import_id: Option, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c6100004786be..825a84d075bb5 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -26,7 +26,7 @@ use rustc::util::common::time; use rustc::util::nodemap::NodeSet; use rustc_back::sha2::{Sha256, Digest}; use rustc_borrowck as borrowck; -use rustc_incremental; +use rustc_incremental::{self, HashesMap}; use rustc_resolve::{MakeGlobMap, Resolver}; use rustc_metadata::macro_import; use rustc_metadata::creader::read_local_crates; @@ -172,7 +172,7 @@ pub fn compile_input(sess: &Session, resolutions, &arenas, &crate_name, - |tcx, mir_map, analysis, result| { + |tcx, mir_map, analysis, hashes_map, result| { { // Eventually, we will want to track plugins. let _ignore = tcx.dep_graph.in_ignore(); @@ -202,7 +202,8 @@ pub fn compile_input(sess: &Session, } let trans = phase_4_translate_to_llvm(tcx, mir_map.unwrap(), - analysis); + analysis, + &hashes_map); if log_enabled!(::log::INFO) { println!("Post-trans"); @@ -797,14 +798,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, Option>, ty::CrateAnalysis, + HashesMap, CompileResult) -> R { macro_rules! try_with_f { - ($e: expr, ($t: expr, $m: expr, $a: expr)) => { + ($e: expr, ($t: expr, $m: expr, $a: expr, $h: expr)) => { match $e { Ok(x) => x, Err(x) => { - f($t, $m, $a, Err(x)); + f($t, $m, $a, $h, Err(x)); return Err(x); } } @@ -860,12 +862,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, index, name, |tcx| { + let hashes_map = + time(time_passes, + "compute_hashes_map", + || rustc_incremental::compute_hashes_map(tcx)); time(time_passes, "load_dep_graph", - || rustc_incremental::load_dep_graph(tcx)); + || rustc_incremental::load_dep_graph(tcx, &hashes_map)); // passes are timed inside typeck - try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis)); + try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis, hashes_map)); time(time_passes, "const checking", @@ -935,7 +941,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis if sess.err_count() > 0 { - return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count()))); + return Ok(f(tcx, Some(mir_map), analysis, hashes_map, Err(sess.err_count()))); } analysis.reachable = @@ -963,17 +969,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // The above three passes generate errors w/o aborting if sess.err_count() > 0 { - return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count()))); + return Ok(f(tcx, Some(mir_map), analysis, hashes_map, Err(sess.err_count()))); } - Ok(f(tcx, Some(mir_map), analysis, Ok(()))) + Ok(f(tcx, Some(mir_map), analysis, hashes_map, Ok(()))) }) } /// Run the translation phase to LLVM, after which the AST and analysis can pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mut mir_map: MirMap<'tcx>, - analysis: ty::CrateAnalysis) + analysis: ty::CrateAnalysis, + hashes_map: &HashesMap) -> trans::CrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -1007,7 +1014,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let translation = time(time_passes, "translation", - move || trans::trans_crate(tcx, &mir_map, analysis)); + move || trans::trans_crate(tcx, &mir_map, analysis, &hashes_map)); time(time_passes, "assert dep graph", @@ -1015,7 +1022,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(time_passes, "serialize dep graph", - move || rustc_incremental::save_dep_graph(tcx)); + move || rustc_incremental::save_dep_graph(tcx, &hashes_map)); translation } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index e3e06963ad43b..1ffeaf322bf57 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -234,7 +234,7 @@ impl PpSourceMode { resolutions.clone(), arenas, id, - |tcx, _, _, _| { + |tcx, _, _, _, _| { let annotation = TypedAnnotation { tcx: tcx, }; @@ -951,7 +951,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions.clone(), arenas, crate_name, - |tcx, mir_map, _, _| { + |tcx, mir_map, _, _, _| { match ppm { PpmMir | PpmMirCFG => { if let Some(mir_map) = mir_map { diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index d7caf8c882f0b..7b1b0ce4cf14d 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -8,106 +8,122 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Calculation of a Strict Version Hash for crates. For a length -//! comment explaining the general idea, see `librustc/middle/svh.rs`. - +//! Calculation of the (misnamed) "strict version hash" for crates and +//! items. This hash is used to tell when the HIR changed in such a +//! way that results from previous compilations may no longer be +//! applicable and hence must be recomputed. It should probably be +//! renamed to the ICH (incremental compilation hash). +//! +//! The hashes for all items are computed once at the beginning of +//! compilation and stored into a map. In addition, a hash is computed +//! of the **entire crate**. +//! +//! Storing the hashes in a map avoids the need to compute them twice +//! (once when loading prior incremental results and once when +//! saving), but it is also important for correctness: at least as of +//! the time of this writing, the typeck passes rewrites entries in +//! the dep-map in-place to accommodate UFCS resolutions. Since name +//! resolution is part of the hash, the result is that hashes computed +//! at the end of compilation would be different from those computed +//! at the beginning. + +use syntax::ast; use syntax::attr::AttributeMethods; use std::hash::{Hash, SipHasher, Hasher}; +use rustc::dep_graph::DepNode; +use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::map::{NodeItem, NodeForeignItem}; -use rustc::hir::svh::Svh; +use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; -use rustc::hir::intravisit::{self, Visitor}; +use rustc_data_structures::fnv::FnvHashMap; use self::svh_visitor::StrictVersionHashVisitor; mod svh_visitor; -pub trait SvhCalculate { - /// Calculate the SVH for an entire krate. - fn calculate_krate_hash(self) -> Svh; +pub type HashesMap = FnvHashMap, u64>; - /// Calculate the SVH for a particular item. - fn calculate_item_hash(self, def_id: DefId) -> u64; +pub fn compute_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> HashesMap { + let _ignore = tcx.dep_graph.in_ignore(); + let krate = tcx.map.krate(); + let mut visitor = HashItemsVisitor { tcx: tcx, hashes: FnvHashMap() }; + visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); + krate.visit_all_items(&mut visitor); + visitor.compute_crate_hash(); + visitor.hashes } -impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { - fn calculate_krate_hash(self) -> Svh { - // FIXME (#14132): This is better than it used to be, but it still not - // ideal. We now attempt to hash only the relevant portions of the - // Crate AST as well as the top-level crate attributes. (However, - // the hashing of the crate attributes should be double-checked - // to ensure it is not incorporating implementation artifacts into - // the hash that are not otherwise visible.) +struct HashItemsVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + hashes: HashesMap, +} - let crate_disambiguator = self.sess.local_crate_disambiguator(); - let krate = self.map.krate(); +impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { + fn calculate_node_id(&mut self, id: ast::NodeId, walk_op: W) + where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'tcx>) + { + let def_id = self.tcx.map.local_def_id(id); + self.calculate_def_id(def_id, walk_op) + } - // FIXME: this should use SHA1, not SipHash. SipHash is not built to - // avoid collisions. + fn calculate_def_id(&mut self, def_id: DefId, mut walk_op: W) + where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'tcx>) + { + assert!(def_id.is_local()); + debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); + // FIXME: this should use SHA1, not SipHash. SipHash is not + // built to avoid collisions. let mut state = SipHasher::new(); - debug!("state: {:?}", state); + walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx)); + let item_hash = state.finish(); + self.hashes.insert(DepNode::Hir(def_id), item_hash); + debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash); + } + + fn compute_crate_hash(&mut self) { + let krate = self.tcx.map.krate(); - // FIXME(#32753) -- at (*) we `to_le` for endianness, but is - // this enough, and does it matter anyway? - "crate_disambiguator".hash(&mut state); - crate_disambiguator.len().to_le().hash(&mut state); // (*) - crate_disambiguator.hash(&mut state); + let mut crate_state = SipHasher::new(); - debug!("crate_disambiguator: {:?}", crate_disambiguator); - debug!("state: {:?}", state); + let crate_disambiguator = self.tcx.sess.local_crate_disambiguator(); + "crate_disambiguator".hash(&mut crate_state); + crate_disambiguator.len().hash(&mut crate_state); + crate_disambiguator.hash(&mut crate_state); + // add each item (in some deterministic order) to the overall + // crate hash. + // + // FIXME -- it'd be better to sort by the hash of the def-path, + // so that reordering items would not affect the crate hash. { - let mut visit = StrictVersionHashVisitor::new(&mut state, self); - krate.visit_all_items(&mut visit); + let mut keys: Vec<_> = self.hashes.keys().collect(); + keys.sort(); + for key in keys { + self.hashes[key].hash(&mut crate_state); + } } - // FIXME (#14132): This hash is still sensitive to e.g. the - // spans of the crate Attributes and their underlying - // MetaItems; we should make ContentHashable impl for those - // types and then use hash_content. But, since all crate - // attributes should appear near beginning of the file, it is - // not such a big deal to be sensitive to their spans for now. - // - // We hash only the MetaItems instead of the entire Attribute - // to avoid hashing the AttrId for attr in &krate.attrs { debug!("krate attr {:?}", attr); - attr.meta().hash(&mut state); + attr.meta().hash(&mut crate_state); } - Svh::new(state.finish()) + let crate_hash = crate_state.finish(); + self.hashes.insert(DepNode::Krate, crate_hash); + debug!("calculate_crate_hash: crate_hash={:?}", crate_hash); } +} - fn calculate_item_hash(self, def_id: DefId) -> u64 { - assert!(def_id.is_local()); - - debug!("calculate_item_hash(def_id={:?})", def_id); - - let mut state = SipHasher::new(); - - { - let mut visit = StrictVersionHashVisitor::new(&mut state, self); - if def_id.index == CRATE_DEF_INDEX { - // the crate root itself is not registered in the map - // as an item, so we have to fetch it this way - let krate = self.map.krate(); - intravisit::walk_crate(&mut visit, krate); - } else { - let node_id = self.map.as_local_node_id(def_id).unwrap(); - match self.map.find(node_id) { - Some(NodeItem(item)) => visit.visit_item(item), - Some(NodeForeignItem(item)) => visit.visit_foreign_item(item), - r => bug!("calculate_item_hash: expected an item for node {} not {:?}", - node_id, r), - } - } - } - - let hash = state.finish(); - debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash); +impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + self.calculate_node_id(item.id, |v| v.visit_item(item)); + visit::walk_item(self, item); + } - hash + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { + self.calculate_node_id(item.id, |v| v.visit_foreign_item(item)); + visit::walk_foreign_item(self, item); } } + diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 42e7abeeaca8f..c06b223ce211a 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -187,20 +187,20 @@ pub enum SawStmtComponent { SawStmtSemi, } -impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'tcx> { fn visit_nested_item(&mut self, _: ItemId) { // Each item is hashed independently; ignore nested items. } - fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, - g: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, + g: &'tcx Generics, _: NodeId, _: Span) { debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); visit::walk_generics(self, g); visit::walk_struct_def(self, s) } - fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) { debug!("visit_variant: st={:?}", self.st); SawVariant.hash(self.st); // walk_variant does not call walk_generics, so do it here. @@ -227,12 +227,12 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { SawIdent(name.as_str()).hash(self.st); } - fn visit_lifetime(&mut self, l: &'a Lifetime) { + fn visit_lifetime(&mut self, l: &'tcx Lifetime) { debug!("visit_lifetime: st={:?}", self.st); SawLifetime(l.name.as_str()).hash(self.st); } - fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) { + fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { debug!("visit_lifetime_def: st={:?}", self.st); SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); } @@ -242,12 +242,12 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { // monomorphization and cross-crate inlining generally implies // that a change to a crate body will require downstream // crates to be recompiled. - fn visit_expr(&mut self, ex: &'a Expr) { + fn visit_expr(&mut self, ex: &'tcx Expr) { debug!("visit_expr: st={:?}", self.st); SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) } - fn visit_stmt(&mut self, s: &'a Stmt) { + fn visit_stmt(&mut self, s: &'tcx Stmt) { debug!("visit_stmt: st={:?}", self.st); // We don't want to modify the hash for decls, because @@ -265,7 +265,7 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { visit::walk_stmt(self, s) } - fn visit_foreign_item(&mut self, i: &'a ForeignItem) { + fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { debug!("visit_foreign_item: st={:?}", self.st); // FIXME (#14132) ideally we would incorporate privacy (or @@ -275,7 +275,7 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i) } - fn visit_item(&mut self, i: &'a Item) { + fn visit_item(&mut self, i: &'tcx Item) { debug!("visit_item: {:?} st={:?}", i, self.st); // FIXME (#14132) ideally would incorporate reachability @@ -285,63 +285,63 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { SawItem.hash(self.st); visit::walk_item(self, i) } - fn visit_mod(&mut self, m: &'a Mod, _s: Span, n: NodeId) { + fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) { debug!("visit_mod: st={:?}", self.st); SawMod.hash(self.st); visit::walk_mod(self, m, n) } - fn visit_ty(&mut self, t: &'a Ty) { + fn visit_ty(&mut self, t: &'tcx Ty) { debug!("visit_ty: st={:?}", self.st); SawTy.hash(self.st); visit::walk_ty(self, t) } - fn visit_generics(&mut self, g: &'a Generics) { + fn visit_generics(&mut self, g: &'tcx Generics) { debug!("visit_generics: st={:?}", self.st); SawGenerics.hash(self.st); visit::walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, - b: &'a Block, s: Span, n: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl, + b: &'tcx Block, s: Span, n: NodeId) { debug!("visit_fn: st={:?}", self.st); SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n) } - fn visit_trait_item(&mut self, ti: &'a TraitItem) { + fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { debug!("visit_trait_item: st={:?}", self.st); SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &'a ImplItem) { + fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { debug!("visit_impl_item: st={:?}", self.st); SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) } - fn visit_struct_field(&mut self, s: &'a StructField) { + fn visit_struct_field(&mut self, s: &'tcx StructField) { debug!("visit_struct_field: st={:?}", self.st); SawStructField.hash(self.st); visit::walk_struct_field(self, s) } - fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) { + fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); SawPath.hash(self.st); visit::walk_path(self, path) } - fn visit_block(&mut self, b: &'a Block) { + fn visit_block(&mut self, b: &'tcx Block) { debug!("visit_block: st={:?}", self.st); SawBlock.hash(self.st); visit::walk_block(self, b) } - fn visit_pat(&mut self, p: &'a Pat) { + fn visit_pat(&mut self, p: &'tcx Pat) { debug!("visit_pat: st={:?}", self.st); SawPat.hash(self.st); visit::walk_pat(self, p) } - fn visit_local(&mut self, l: &'a Local) { + fn visit_local(&mut self, l: &'tcx Local) { debug!("visit_local: st={:?}", self.st); SawLocal.hash(self.st); visit::walk_local(self, l) } - fn visit_arm(&mut self, a: &'a Arm) { + fn visit_arm(&mut self, a: &'tcx Arm) { debug!("visit_arm: st={:?}", self.st); SawArm.hash(self.st); visit::walk_arm(self, a) } @@ -369,10 +369,12 @@ impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { // variant it is above when we visit the HIR). if let Some(def) = self.tcx.def_map.borrow().get(&id) { + debug!("hash_resolve: id={:?} def={:?} st={:?}", id, def, self.st); self.hash_partial_def(def); } if let Some(traits) = self.tcx.trait_map.get(&id) { + debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st); traits.len().hash(self.st); for candidate in traits { self.hash_def_id(candidate.def_id); diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 0d11b0794feac..b9c56c45386c4 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -38,7 +38,8 @@ mod calculate_svh; mod persist; pub use assert_dep_graph::assert_dep_graph; -pub use calculate_svh::SvhCalculate; +pub use calculate_svh::compute_hashes_map; +pub use calculate_svh::HashesMap; pub use persist::load_dep_graph; pub use persist::save_dep_graph; pub use persist::save_trans_partition; diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 344b05f095457..49ad6c36804e2 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use calculate_svh::SvhCalculate; use rbml::Error; use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; @@ -21,19 +20,22 @@ use std::io::{ErrorKind, Read}; use std::fs::File; use syntax::ast; +use HashesMap; use super::data::*; use super::util::*; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + hashes_map: &'a HashesMap, item_metadata_hashes: FnvHashMap, crate_hashes: FnvHashMap, } impl<'a, 'tcx> HashContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, hashes_map: &'a HashesMap) -> Self { HashContext { tcx: tcx, + hashes_map: hashes_map, item_metadata_hashes: FnvHashMap(), crate_hashes: FnvHashMap(), } @@ -51,7 +53,17 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { match *dep_node { // HIR nodes (which always come from our crate) are an input: DepNode::Hir(def_id) => { - Some((def_id, self.hir_hash(def_id))) + assert!(def_id.is_local(), + "cannot hash HIR for non-local def-id {:?} => {:?}", + def_id, + self.tcx.item_path_str(def_id)); + + assert!(!self.tcx.map.is_inlined_def_id(def_id), + "cannot hash HIR for inlined def-id {:?} => {:?}", + def_id, + self.tcx.item_path_str(def_id)); + + Some((def_id, self.hashes_map[dep_node])) } // MetaData from other crates is an *input* to us. @@ -72,21 +84,6 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - fn hir_hash(&mut self, def_id: DefId) -> u64 { - assert!(def_id.is_local(), - "cannot hash HIR for non-local def-id {:?} => {:?}", - def_id, - self.tcx.item_path_str(def_id)); - - assert!(!self.tcx.map.is_inlined_def_id(def_id), - "cannot hash HIR for inlined def-id {:?} => {:?}", - def_id, - self.tcx.item_path_str(def_id)); - - // FIXME(#32753) -- should we use a distinct hash here - self.tcx.calculate_item_hash(def_id) - } - fn metadata_hash(&mut self, def_id: DefId) -> u64 { debug!("metadata_hash(def_id={:?})", def_id); diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index c736437df1a9e..a2ba566f75e0e 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -22,6 +22,7 @@ use std::io::Read; use std::fs::{self, File}; use std::path::{Path}; +use HashesMap; use super::data::*; use super::directory::*; use super::dirty_clean; @@ -38,16 +39,18 @@ type CleanEdges = Vec<(DepNode, DepNode)>; /// early in compilation, before we've really done any work, but /// actually it doesn't matter all that much.) See `README.md` for /// more general overview. -pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + hashes: &HashesMap) { if tcx.sess.opts.incremental.is_none() { return; } let _ignore = tcx.dep_graph.in_ignore(); - load_dep_graph_if_exists(tcx); + load_dep_graph_if_exists(tcx, hashes); } -fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + hashes: &HashesMap) { let dep_graph_path = dep_graph_path(tcx).unwrap(); let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) { Some(p) => p, @@ -60,7 +63,7 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { None => return // no file }; - match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) { + match decode_dep_graph(tcx, hashes, &dep_graph_data, &work_products_data) { Ok(dirty_nodes) => dirty_nodes, Err(err) => { tcx.sess.warn( @@ -97,6 +100,7 @@ fn load_data(sess: &Session, path: &Path) -> Option> { /// Decode the dep graph and load the edges/nodes that are still clean /// into `tcx.dep_graph`. pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + hashes: &HashesMap, dep_graph_data: &[u8], work_products_data: &[u8]) -> Result<(), Error> @@ -133,7 +137,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // reason for this is that this way we can include nodes that have // been removed (which no longer have a `DefId` in the current // compilation). - let dirty_raw_source_nodes = dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced); + let dirty_raw_source_nodes = dirty_nodes(tcx, hashes, &serialized_dep_graph.hashes, &retraced); // Create a list of (raw-source-node -> // retracted-target-node) edges. In the process of retracing the @@ -206,13 +210,14 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Computes which of the original set of def-ids are dirty. Stored in /// a bit vector where the index is the DefPathIndex. fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: &[SerializedHash], + hashes: &HashesMap, + serialized_hashes: &[SerializedHash], retraced: &RetracedDefIdDirectory) -> DirtyNodes { - let mut hcx = HashContext::new(tcx); + let mut hcx = HashContext::new(tcx, hashes); let mut dirty_nodes = FnvHashSet(); - for hash in hashes { + for hash in serialized_hashes { if let Some(dep_node) = retraced.map(&hash.dep_node) { let (_, current_hash) = hcx.hash(&dep_node).unwrap(); if current_hash == hash.hash { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index a9523a81fbaf7..b81afe44f60e7 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -21,20 +21,21 @@ use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; +use HashesMap; use super::data::*; use super::directory::*; use super::hash::*; use super::preds::*; use super::util::*; -pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hashes_map: &HashesMap) { debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); let sess = tcx.sess; if sess.opts.incremental.is_none() { return; } - let mut hcx = HashContext::new(tcx); + let mut hcx = HashContext::new(tcx, hashes_map); let mut builder = DefIdDirectoryBuilder::new(tcx); let query = tcx.dep_graph.query(); let preds = Predecessors::new(&query, &mut hcx); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 68a176a378172..d47a5ddb22456 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -26,10 +26,10 @@ use CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; use rustc::dep_graph::DepNode; -use rustc::ty::TyCtxt; +use rustc::hir::svh::Svh; use rustc_back::tempdir::TempDir; +use rustc_incremental::HashesMap; -use rustc_incremental::SvhCalculate; use std::ascii; use std::char; use std::env; @@ -125,12 +125,12 @@ pub fn find_crate_name(sess: Option<&Session>, } -pub fn build_link_meta<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - name: &str) - -> LinkMeta { +pub fn build_link_meta(hashes_map: &HashesMap, + name: &str) + -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: tcx.calculate_krate_hash(), + crate_hash: Svh::new(hashes_map[&DepNode::Krate]), }; info!("{:?}", r); return r; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f190fbeb6feb9..f2d0bbae942d2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -48,6 +48,7 @@ use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::mir::mir_map::MirMap; use rustc_data_structures::graph::OUTGOING; +use rustc_incremental::HashesMap; use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; use _match; @@ -2481,7 +2482,8 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &MirMap<'tcx>, - analysis: ty::CrateAnalysis) + analysis: ty::CrateAnalysis, + hashes_map: &HashesMap) -> CrateTranslation { let _task = tcx.dep_graph.in_task(DepNode::TransCrate); @@ -2506,7 +2508,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.sess.opts.debug_assertions }; - let link_meta = link::build_link_meta(tcx, name); + let link_meta = link::build_link_meta(hashes_map, name); let shared_ccx = SharedCrateContext::new(tcx, &mir_map, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 10736d2c827cd..8032b5c31046e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -159,7 +159,7 @@ pub fn run_core(search_paths: SearchPaths, resolutions, &arenas, &name, - |tcx, _, analysis, result| { + |tcx, _, analysis, _, result| { if let Err(_) = result { sess.fatal("Compilation failed, aborting rustdoc"); } diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 72072248ec05f..ba8d3cc934bfc 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -17,10 +17,6 @@ // Here the only thing which changes is the string constant in `x`. // Therefore, the compiler deduces (correctly) that typeck is not // needed even for callers of `x`. -// -// It is not entirely clear why `TransCrateItem` invalidates `y` and -// `z`, actually, I think it's because of the structure of -// trans. -nmatsakis fn main() { } @@ -41,10 +37,8 @@ mod x { mod y { use x; - // FIXME(#35078) -- when body of `x` changes, we treat it as - // though signature changed. - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] - #[rustc_dirty(label="TransCrateItem", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TransCrateItem", cfg="rpass2")] pub fn y() { x::x(); } From 4b87c7e3b419345e2d0fd35987a2e012b1e95a5e Mon Sep 17 00:00:00 2001 From: philipp Date: Sat, 20 Aug 2016 15:12:50 +0200 Subject: [PATCH 178/768] Introduce max_by/min_by on iterators --- src/libcore/iter/iterator.rs | 51 ++++++++++++++++++++++++++++++++++++ src/libcoretest/iter.rs | 12 +++++++++ src/libcoretest/lib.rs | 2 ++ 3 files changed, 65 insertions(+) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6b01ccaceea2f..e25920fae0744 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1664,6 +1664,31 @@ pub trait Iterator { .map(|(_, x)| x) } + /// Returns the element that gives the maximum value with respect to the + /// specified comparison function. + /// + /// Returns the rightmost element if the comparison determines two elements + /// to be equally maximum. + /// + /// # Examples + /// + /// ``` + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); + /// ``` + #[inline] + #[unstable(feature = "iter_max_by", issue="1722")] + fn max_by(self, mut compare: F) -> Option + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + select_fold1(self, + |_| (), + // switch to y even if it is only equal, to preserve + // stability. + |_, x, _, y| Ordering::Greater != compare(x, y)) + .map(|(_, x)| x) + } + /// Returns the element that gives the minimum value from the /// specified function. /// @@ -1688,6 +1713,32 @@ pub trait Iterator { .map(|(_, x)| x) } + /// Returns the element that gives the minimum value with respect to the + /// specified comparison function. + /// + /// Returns the latest element if the comparison determines two elements + /// to be equally minimum. + /// + /// # Examples + /// + /// ``` + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); + /// ``` + #[inline] + #[unstable(feature = "iter_min_by", issue="1722")] + fn min_by(self, mut compare: F) -> Option + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + select_fold1(self, + |_| (), + // switch to y even if it is strictly smaller, to + // preserve stability. + |_, x, _, y| Ordering::Greater == compare(x, y)) + .map(|(_, x)| x) + } + + /// Reverses an iterator's direction. /// /// Usually, iterators iterate from left to right. After using `rev()`, diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index a2848faa105e9..27eb25537f31b 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -664,12 +664,24 @@ fn test_max_by_key() { assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10); } +#[test] +fn test_max_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10); +} + #[test] fn test_min_by_key() { let xs: &[isize] = &[-3, 0, 1, 5, -10]; assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0); } +#[test] +fn test_min_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0); +} + #[test] fn test_by_ref() { let mut xs = 0..10; diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 9428b4096bfec..b4c94509477a3 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -33,6 +33,8 @@ #![feature(try_from)] #![feature(unicode)] #![feature(unique)] +#![feature(iter_max_by)] +#![feature(iter_min_by)] extern crate core; extern crate test; From 0595a3a8fa762af28caf4cec9eecd59ea3003163 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Aug 2016 11:52:01 -0400 Subject: [PATCH 179/768] hash the traits-in-scope determinstically Experimentally, this fixes the poor re-use observed in libsyntex-syntax. I'm not sure how to make a regression test for this, though, given the non-deterministic nature of it. --- .../calculate_svh/svh_visitor.rs | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c06b223ce211a..1e00e0fc56260 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -25,25 +25,33 @@ use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, FnKind}; -use rustc::hir::map::DefPath; use rustc::ty::TyCtxt; +use rustc::util::nodemap::DefIdMap; use std::hash::{Hash, SipHasher}; pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub st: &'a mut SipHasher, + + // collect a deterministic hash of def-ids that we have seen + def_id_hashes: DefIdMap, } impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { pub fn new(st: &'a mut SipHasher, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - StrictVersionHashVisitor { st: st, tcx: tcx } + StrictVersionHashVisitor { st: st, tcx: tcx, def_id_hashes: DefIdMap() } } - fn hash_def_path(&mut self, path: &DefPath) { - path.deterministic_hash_to(self.tcx, self.st); + fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { + let tcx = self.tcx; + *self.def_id_hashes.entry(def_id) + .or_insert_with(|| { + let def_path = tcx.def_path(def_id); + def_path.deterministic_hash(tcx) + }) } } @@ -376,15 +384,22 @@ impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { if let Some(traits) = self.tcx.trait_map.get(&id) { debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st); traits.len().hash(self.st); - for candidate in traits { - self.hash_def_id(candidate.def_id); - } + + // The ordering of the candidates is not fixed. So we hash + // the def-ids and then sort them and hash the collection. + let mut candidates: Vec<_> = + traits.iter() + .map(|&TraitCandidate { def_id, import_id: _ }| { + self.compute_def_id_hash(def_id) + }) + .collect(); + candidates.sort(); + candidates.hash(self.st); } } fn hash_def_id(&mut self, def_id: DefId) { - let def_path = self.tcx.def_path(def_id); - self.hash_def_path(&def_path); + self.compute_def_id_hash(def_id).hash(self.st); } fn hash_partial_def(&mut self, def: &PathResolution) { From 26591986032abbad0490a45da6ba7252178c1c82 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Wed, 17 Aug 2016 19:07:39 -0400 Subject: [PATCH 180/768] show how iterating over `RangeTo` and `RangeToInclusive` fails Feedback on PR #35701 seems to be positive, so this does the same thing for `RangeTo` and `RangeToInclusive`. --- src/libcore/ops.rs | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 4ac1b8394f450..92d41c03e9aeb 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1610,17 +1610,33 @@ impl> RangeFrom { /// /// It cannot serve as an iterator because it doesn't have a starting point. /// +/// # Examples +/// +/// The `..{integer}` syntax is a `RangeTo`: +/// +/// ``` +/// assert_eq!((..5), std::ops::RangeTo{ end: 5 }); /// ``` -/// fn main() { -/// assert_eq!((..5), std::ops::RangeTo{ end: 5 }); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); // RangeTo -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```ignore +/// for i in ..5 { +/// // ... /// } /// ``` +/// +/// When used as a slicing index, `RangeTo` produces a slice of all array +/// elements before the index indicated by `end`. +/// +/// ``` +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); +/// assert_eq!(arr[ ..3], [0,1,2 ]); // RangeTo +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo { @@ -1748,16 +1764,31 @@ impl> RangeInclusive { /// /// # Examples /// +/// The `...{integer}` syntax is a `RangeToInclusive`: +/// /// ``` /// #![feature(inclusive_range,inclusive_range_syntax)] -/// fn main() { -/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 }); +/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 }); +/// ``` /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive -/// assert_eq!(arr[1...2], [ 1,2 ]); +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```ignore +/// for i in ...5 { +/// // ... /// } /// ``` +/// +/// When used as a slicing index, `RangeToInclusive` produces a slice of all +/// array elements up to and including the index indicated by `end`. +/// +/// ``` +/// #![feature(inclusive_range_syntax)] +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive +/// assert_eq!(arr[1...2], [ 1,2 ]); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] pub struct RangeToInclusive { From e4dd785b591b771882b1c61a541048d57dc86442 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 20 Aug 2016 15:20:22 -0400 Subject: [PATCH 181/768] Correct formatting docs: fmt::Result != io::Result<()> --- src/libcollections/fmt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index b7cbfb60ec4e9..428ed319ce941 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -165,9 +165,9 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is `fmt::Result` which is a -//! typedef to `Result<(), std::io::Error>` (also known as `std::io::Result<()>`). -//! Formatting implementations should ensure that they return errors from `write!` -//! correctly (propagating errors upward). +//! typedef to `Result<(), std::fmt::Error>`. Formatting implementations should +//! ensure that they return errors from `write!` correctly (propagating errors +//! upward). //! //! An example of implementing the formatting traits would look //! like: From 825fd11bd6b06bdd7195e2d946c6120d9b15a78c Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sat, 20 Aug 2016 15:21:36 -0400 Subject: [PATCH 182/768] replace `Rem` example with something more evocative r? @steveklabnik --- src/libcore/ops.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 5a1993e741c60..9a3649bf864dc 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -485,26 +485,34 @@ div_impl_float! { f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Rem`. When `Foo % Foo` happens, it ends up -/// calling `rem`, and therefore, `main` prints `Remainder-ing!`. +/// This example implements `Rem` on a `SplitSlice` object. After `Rem` is +/// implemented, one can use the `%` operator to find out what the remaining +/// elements of the slice would be after splitting it into equal slices of a +/// given length. /// /// ``` /// use std::ops::Rem; /// -/// struct Foo; +/// #[derive(PartialEq, Debug)] +/// struct SplitSlice<'a, T: 'a> { +/// slice: &'a [T], +/// } /// -/// impl Rem for Foo { -/// type Output = Foo; +/// impl<'a, T> Rem for SplitSlice<'a, T> { +/// type Output = SplitSlice<'a, T>; /// -/// fn rem(self, _rhs: Foo) -> Foo { -/// println!("Remainder-ing!"); -/// self +/// fn rem(self, modulus: usize) -> Self { +/// let len = self.slice.len(); +/// let rem = len % modulus; +/// let start = len - rem; +/// SplitSlice {slice: &self.slice[start..]} /// } /// } /// -/// fn main() { -/// Foo % Foo; -/// } +/// // If we were to divide &[0, 1, 2, 3, 4, 5, 6, 7] into slices of size 3, +/// // the remainder would be &[6, 7] +/// assert_eq!(SplitSlice { slice: &[0, 1, 2, 3, 4, 5, 6, 7] } % 3, +/// SplitSlice { slice: &[6, 7] }); /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] From ff44f088d7b46d1ecfc88984362140766b211d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sat, 20 Aug 2016 02:41:51 +0200 Subject: [PATCH 183/768] Update E0424 to the new error format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #35797. Signed-off-by: Johannes Löthberg --- src/librustc_resolve/lib.rs | 8 +++++--- src/test/compile-fail/E0424.rs | 5 ++++- src/test/compile-fail/issue-2356.rs | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b91ede5b2fa8a..655c4f1f263fe 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -344,11 +344,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, path_name) } ResolutionError::SelfNotAvailableInStaticMethod => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0424, - "`self` is not available in a static method. Maybe a `self` \ - argument is missing?") + "`self` is not available in a static method"); + err.span_label(span, &format!("not available in static method")); + err.note(&format!("maybe a `self` argument is missing?")); + err } ResolutionError::UnresolvedName { path, message: msg, context, is_static_method, is_field, def } => { diff --git a/src/test/compile-fail/E0424.rs b/src/test/compile-fail/E0424.rs index 445d0c5f3edc0..911007113d3d6 100644 --- a/src/test/compile-fail/E0424.rs +++ b/src/test/compile-fail/E0424.rs @@ -14,7 +14,10 @@ impl Foo { fn bar(self) {} fn foo() { - self.bar(); //~ ERROR E0424 + self.bar(); + //~^ ERROR `self` is not available in a static method [E0424] + //~| NOTE not available in static method + //~| NOTE maybe a `self` argument is missing? } } diff --git a/src/test/compile-fail/issue-2356.rs b/src/test/compile-fail/issue-2356.rs index d7ec1ed67397f..da92161967dbd 100644 --- a/src/test/compile-fail/issue-2356.rs +++ b/src/test/compile-fail/issue-2356.rs @@ -59,7 +59,9 @@ impl cat { impl cat { fn meow() { if self.whiskers > 3 { - //~^ ERROR: `self` is not available in a static method. Maybe a `self` argument is missing? + //~^ ERROR `self` is not available in a static method [E0424] + //~| NOTE not available in static method + //~| NOTE maybe a `self` argument is missing? println!("MEOW"); } } From 1dfc5db7dba9964641accfa02f138df59d5893c1 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sat, 20 Aug 2016 16:39:40 -0400 Subject: [PATCH 184/768] replace `Index` example with something more evocative of indexing r? @steveklabnik --- src/libcore/ops.rs | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 4ac1b8394f450..bb63bc4320551 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1381,28 +1381,44 @@ shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// /// # Examples /// -/// A trivial implementation of `Index`. When `Foo[Bar]` happens, it ends up -/// calling `index`, and therefore, `main` prints `Indexing!`. +/// This example implements `Index` on a read-only `NucleotideCount` container, +/// enabling individual counts to be retrieved with index syntax. /// /// ``` /// use std::ops::Index; /// -/// #[derive(Copy, Clone)] -/// struct Foo; -/// struct Bar; +/// enum Nucleotide { +/// A, +/// C, +/// G, +/// T, +/// } /// -/// impl Index for Foo { -/// type Output = Foo; +/// struct NucleotideCount { +/// a: usize, +/// c: usize, +/// g: usize, +/// t: usize, +/// } /// -/// fn index<'a>(&'a self, _index: Bar) -> &'a Foo { -/// println!("Indexing!"); -/// self +/// impl Index for NucleotideCount { +/// type Output = usize; +/// +/// fn index(&self, nucleotide: Nucleotide) -> &usize { +/// match nucleotide { +/// Nucleotide::A => &self.a, +/// Nucleotide::C => &self.c, +/// Nucleotide::G => &self.g, +/// Nucleotide::T => &self.t, +/// } /// } /// } /// -/// fn main() { -/// Foo[Bar]; -/// } +/// let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12}; +/// assert_eq!(nucleotide_count[Nucleotide::A], 14); +/// assert_eq!(nucleotide_count[Nucleotide::C], 9); +/// assert_eq!(nucleotide_count[Nucleotide::G], 10); +/// assert_eq!(nucleotide_count[Nucleotide::T], 12); /// ``` #[lang = "index"] #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] From f2655e23ff1b377f09cfbb19253a7ea50cd2c4f3 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 20 Aug 2016 15:27:37 -0400 Subject: [PATCH 185/768] Note that formatters should not return spurious errors. Doing otherwise would break traits like `ToString`. --- src/libcollections/fmt.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 428ed319ce941..a1b4461949c6e 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -166,8 +166,14 @@ //! //! Additionally, the return value of this function is `fmt::Result` which is a //! typedef to `Result<(), std::fmt::Error>`. Formatting implementations should -//! ensure that they return errors from `write!` correctly (propagating errors -//! upward). +//! ensure that they propagate errors from the `Formatter` (e.g., when calling +//! `write!`) however, they should never return errors spuriously. That is, a +//! formatting implementation must and may only return an error if the passed-in +//! `Formatter` returns an error. This is because, contrary to what the function +//! signature might suggest, string formatting is an infallible operation. +//! This function only returns a result because writing to the underlying stream +//! might fail and it must provide a way to propagate the fact that an error has +//! occurred back up the stack. //! //! An example of implementing the formatting traits would look //! like: From 9bb8b65bddad92030c77c7eefbe930b40611c300 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 20 Aug 2016 21:07:19 -0400 Subject: [PATCH 186/768] Update E0503 to the new format Fixes #35703 Part of #35233 --- src/librustc_borrowck/borrowck/check_loans.rs | 5 ++++- .../compile-fail/borrowck/borrowck-box-insensitivity.rs | 2 ++ src/test/compile-fail/issue-25793.rs | 1 + src/test/compile-fail/regions-escape-loop-via-vec.rs | 9 +++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 9cae270984f00..c1f162e5772bf 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -647,10 +647,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { struct_span_err!(self.bccx, span, E0503, "cannot use `{}` because it was mutably borrowed", &self.bccx.loan_path_to_string(copy_path)) - .span_note(loan_span, + .span_label(loan_span, &format!("borrow of `{}` occurs here", &self.bccx.loan_path_to_string(&loan_path)) ) + .span_label(span, + &format!("use of borrowed `{}`", + &self.bccx.loan_path_to_string(&loan_path))) .emit(); } } diff --git a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs index 3fd71f715647d..530822f6c5baf 100644 --- a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs +++ b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs @@ -71,6 +71,7 @@ fn copy_after_mut_borrow() { let _x = &mut a.x; //~^ NOTE borrow of `a.x` occurs here let _y = a.y; //~ ERROR cannot use + //~^ NOTE use of borrowed `a.x` } fn move_after_mut_borrow() { @@ -141,6 +142,7 @@ fn copy_after_mut_borrow_nested() { let _x = &mut a.x.x; //~^ NOTE borrow of `a.x.x` occurs here let _y = a.y; //~ ERROR cannot use + //~^ NOTE use of borrowed `a.x.x` } fn move_after_mut_borrow_nested() { diff --git a/src/test/compile-fail/issue-25793.rs b/src/test/compile-fail/issue-25793.rs index 44b3ada97fea8..ceefd583a5ca6 100644 --- a/src/test/compile-fail/issue-25793.rs +++ b/src/test/compile-fail/issue-25793.rs @@ -12,6 +12,7 @@ macro_rules! width( ($this:expr) => { $this.width.unwrap() //~^ ERROR cannot use `self.width` because it was mutably borrowed + //~| NOTE use of borrowed `*self` } ); diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs index 89350f1616760..8c026df7d9754 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs @@ -12,11 +12,20 @@ fn broken() { let mut x = 3; let mut _y = vec!(&mut x); + //~^ NOTE borrow of `x` occurs here + //~| NOTE borrow of `x` occurs here + //~| NOTE borrow of `x` occurs here while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed + //~^ NOTE use of borrowed `x` let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed + //~^ NOTE use of borrowed `x` _y.push(&mut z); //~ ERROR `z` does not live long enough + //~^ NOTE does not live long enough x += 1; //~ ERROR cannot assign + //~^ NOTE assignment to borrowed `x` occurs here } + //~^ NOTE borrowed value only valid until here } +//~^ NOTE borrowed value must be valid until here fn main() { } From dfeb20ce60b288d62796e17831f4d5cadf6afadf Mon Sep 17 00:00:00 2001 From: philipp Date: Sun, 21 Aug 2016 13:23:39 +0200 Subject: [PATCH 187/768] Added #![feature] declarations --- src/libcore/iter/iterator.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index e25920fae0744..48ea306ce5fd0 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1673,6 +1673,7 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_max_by)] /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); /// ``` @@ -1722,6 +1723,7 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_min_by)] /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); /// ``` From 876c02cc1ab537703c4d6f19693dd9a42b131442 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 21 Aug 2016 13:33:28 +0200 Subject: [PATCH 188/768] cstring: avoid excessive growth just to 0-terminate Based on following what happens in CString::new("string literal"): 1. Using `Into>`, a Vec is allocated with capacity exactly equal to the string's input length. 2. By `v.push(0)`, the Vec is grown to twice capacity, since it was full. 3. By `v.into_boxed_slice()`, the Vec capacity is shrunk to fit the length again. If we use `.reserve_exact(1)` just before the push, then we avoid the capacity doubling that we're going to have to shrink anyway. Growing by just 1 byte means that the step (2) is less likely to have to move the memory to a larger allocation chunk, and that the step (3) does not have to reallocate. --- src/libstd/ffi/c_str.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 77b90c0846bbe..6f217be31fe67 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -213,6 +213,7 @@ impl CString { /// byte vector, not anything that can be converted to one with Into. #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.reserve_exact(1); v.push(0); CString { inner: v.into_boxed_slice() } } From 738b91e9976a41c7b0ab8cbf544cd971202bfa98 Mon Sep 17 00:00:00 2001 From: Shyam Sundar B Date: Sun, 21 Aug 2016 18:43:58 +0530 Subject: [PATCH 189/768] Update lib.rs Update lib.rs Update lib.rs Update E0438.rs Update E0437.rs Update E0435.rs --- src/librustc_resolve/lib.rs | 18 ++++++++++++------ src/test/compile-fail/E0435.rs | 1 + src/test/compile-fail/E0437.rs | 1 + src/test/compile-fail/E0438.rs | 1 + 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b91ede5b2fa8a..d9132dc5c82a7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -251,20 +251,24 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0437, "type `{}` is not a member of trait `{}`", type_, - trait_) + trait_); + err.span_label(span, &format!("not a member of trait `Foo`")); + err } ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0438, "const `{}` is not a member of trait `{}`", const_, - trait_) + trait_); + err.span_label(span, &format!("not a member of trait `Foo`")); + err } ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => { struct_span_err!(resolver.session, @@ -438,10 +442,12 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, closure form instead") } ResolutionError::AttemptToUseNonConstantValueInConstant => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0435, - "attempt to use a non-constant value in a constant") + "attempt to use a non-constant value in a constant"); + err.span_label(span, &format!("non-constant used with constant")); + err } ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => { let shadows_what = PathResolution::new(binding.def().unwrap()).kind_name(); diff --git a/src/test/compile-fail/E0435.rs b/src/test/compile-fail/E0435.rs index f6cba15a0bff8..f687633d34d86 100644 --- a/src/test/compile-fail/E0435.rs +++ b/src/test/compile-fail/E0435.rs @@ -11,4 +11,5 @@ fn main () { let foo = 42u32; const FOO : u32 = foo; //~ ERROR E0435 + //~| NOTE non-constant used with constant } diff --git a/src/test/compile-fail/E0437.rs b/src/test/compile-fail/E0437.rs index 7440a82773e7a..62ee8dc346492 100644 --- a/src/test/compile-fail/E0437.rs +++ b/src/test/compile-fail/E0437.rs @@ -12,6 +12,7 @@ trait Foo {} impl Foo for i32 { type Bar = bool; //~ ERROR E0437 + //~| NOTE not a member of trait `Foo` } fn main () { diff --git a/src/test/compile-fail/E0438.rs b/src/test/compile-fail/E0438.rs index b3d453072049e..f549d62aebfea 100644 --- a/src/test/compile-fail/E0438.rs +++ b/src/test/compile-fail/E0438.rs @@ -14,6 +14,7 @@ trait Foo {} impl Foo for i32 { const BAR: bool = true; //~ ERROR E0438 + //~| NOTE not a member of trait `Foo` } fn main () { From 8b18e781abaa7ead1cf23080bb6361a4824ba288 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sun, 21 Aug 2016 16:49:09 -0400 Subject: [PATCH 190/768] replace `println!` statements with `assert!`ions in `std::ptr` examples r? @steveklabnik --- src/libcore/ptr.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 925cdfec900db..8cb485872b3f3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -128,7 +128,9 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// let x = 12; /// let y = &x as *const i32; /// -/// unsafe { println!("{}", std::ptr::read(y)); } +/// unsafe { +/// assert_eq!(std::ptr::read(y), 12); +/// } /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] @@ -178,7 +180,7 @@ pub unsafe fn read_and_drop(dest: *mut T) -> T { /// /// unsafe { /// std::ptr::write(y, z); -/// println!("{}", std::ptr::read(y)); +/// assert_eq!(std::ptr::read(y), 12); /// } /// ``` #[inline] @@ -220,7 +222,9 @@ pub unsafe fn write(dst: *mut T, src: T) { /// let x = 12; /// let y = &x as *const i32; /// -/// unsafe { println!("{}", std::ptr::read_volatile(y)); } +/// unsafe { +/// assert_eq!(std::ptr::read_volatile(y), 12); +/// } /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] @@ -266,7 +270,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// unsafe { /// std::ptr::write_volatile(y, z); -/// println!("{}", std::ptr::read_volatile(y)); +/// assert_eq!(std::ptr::read_volatile(y), 12); /// } /// ``` #[inline] From 18445cd6cc7b05014157a8889214ccc236fe1715 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Sun, 21 Aug 2016 22:51:37 +0200 Subject: [PATCH 191/768] Fix "Furthermore" Typo in String Docs It used to say "Furtheremore" instead of "Furthermore". --- src/libcollections/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 788c838cd3fc8..a7dc2875320b7 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -132,7 +132,7 @@ use boxed::Box; /// [`OsString`]: ../../std/ffi/struct.OsString.html /// /// Indexing is intended to be a constant-time operation, but UTF-8 encoding -/// does not allow us to do this. Furtheremore, it's not clear what sort of +/// does not allow us to do this. Furthermore, it's not clear what sort of /// thing the index should return: a byte, a codepoint, or a grapheme cluster. /// The [`as_bytes()`] and [`chars()`] methods return iterators over the first /// two, respectively. From 5310d1110dd245ff4e12cd7b483bec53640bf58b Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sun, 21 Aug 2016 17:18:21 -0400 Subject: [PATCH 192/768] add example for `Rc::would_unwrap` Part of #29372 r? @steveklabnik --- src/liballoc/rc.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 2beb652aa017a..3a158240c3a26 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -263,6 +263,23 @@ impl Rc { } /// Checks if `Rc::try_unwrap` would return `Ok`. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_would_unwrap)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert!(Rc::would_unwrap(&x)); + /// assert_eq!(Rc::try_unwrap(x), Ok(3)); + /// + /// let x = Rc::new(4); + /// let _y = x.clone(); + /// assert!(!Rc::would_unwrap(&x)); + /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4))); + /// ``` #[unstable(feature = "rc_would_unwrap", reason = "just added for niche usecase", issue = "28356")] From 17f9937cec3682ae73b7ce6e6417522544b86c8a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 22 Aug 2016 00:21:13 +0300 Subject: [PATCH 193/768] rustc: Fix outdated comment --- src/librustc/middle/privacy.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 478f662d0962a..189150d426463 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -23,9 +23,8 @@ use syntax::ast::NodeId; pub enum AccessLevel { // Exported items + items participating in various kinds of public interfaces, // but not directly nameable. For example, if function `fn f() -> T {...}` is - // public, then type `T` is exported. Its values can be obtained by other crates - // even if the type itseld is not nameable. - // FIXME: Mostly unimplemented. Only `type` aliases export items currently. + // public, then type `T` is reachable. Its values can be obtained by other crates + // even if the type itself is not nameable. Reachable, // Public items + items accessible to other crates with help of `pub use` reexports Exported, From c32456da8f14a7c4206278c55b90a535c4d98e20 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 22 Aug 2016 09:31:26 +1200 Subject: [PATCH 194/768] Fix type error with `?` in existing code. --- src/librustc/ty/relate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index abf863f953664..8975a799be143 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -151,13 +151,13 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, let b_ty = &b_subst.types[i]; let variance = variances.map_or(ty::Invariant, |v| v.types[i]); relation.relate_with_variance(variance, a_ty, b_ty) - }).collect()?; + }).collect::>()?; let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| { let b_r = &b_subst.regions[i]; let variance = variances.map_or(ty::Invariant, |v| v.regions[i]); relation.relate_with_variance(variance, a_r, b_r) - }).collect()?; + }).collect::>()?; Ok(Substs::new(tcx, types, regions)) } From 98ce875b58a87164b763e83be82b5ed32f4398a9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Aug 2016 09:01:22 +0000 Subject: [PATCH 195/768] Refactor away variant `ast::PathListItemKind::Mod` and refactor `ast::PathListItemKind::Ident` -> `ast::PathListItem_`. --- src/librustc/hir/lowering.rs | 14 +++----- src/librustc_resolve/build_reduced_graph.rs | 25 +++++++------ src/librustc_resolve/check_unused.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 17 +++------ src/libsyntax/ast.rs | 40 ++++----------------- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/fold.rs | 16 +++------ src/libsyntax/parse/parser.rs | 15 ++++---- src/libsyntax/print/pprust.rs | 25 ++++--------- src/libsyntax/visit.rs | 4 +-- 10 files changed, 52 insertions(+), 108 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c2b211238b2f1..afb8f5de8eadd 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -218,16 +218,10 @@ impl<'a> LoweringContext<'a> { fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem { Spanned { - node: match path_list_ident.node { - PathListItemKind::Ident { id, name, rename } => hir::PathListIdent { - id: id, - name: name.name, - rename: rename.map(|x| x.name), - }, - PathListItemKind::Mod { id, rename } => hir::PathListMod { - id: id, - rename: rename.map(|x| x.name), - }, + node: hir::PathListIdent { + id: path_list_ident.node.id, + name: path_list_ident.node.name.name, + rename: path_list_ident.node.rename.map(|rename| rename.name), }, span: path_list_ident.span, } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 579853446525e..12c55b3ac172c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -32,9 +32,9 @@ use syntax::parse::token; use syntax::ast::{Block, Crate}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; -use syntax::ast::{Mutability, PathListItemKind}; -use syntax::ast::{StmtKind, TraitItemKind}; +use syntax::ast::{Mutability, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; +use syntax::parse::token::keywords; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; @@ -130,9 +130,10 @@ impl<'b> Resolver<'b> { ViewPathList(_, ref source_items) => { // Make sure there's at most one `mod` import in the list. let mod_spans = source_items.iter().filter_map(|item| { - match item.node { - PathListItemKind::Mod { .. } => Some(item.span), - _ => None, + if item.node.name.name == keywords::SelfValue.name() { + Some(item.span) + } else { + None } }).collect::>(); @@ -147,10 +148,12 @@ impl<'b> Resolver<'b> { } for source_item in source_items { - let (module_path, name, rename) = match source_item.node { - PathListItemKind::Ident { name, rename, .. } => - (module_path.clone(), name.name, rename.unwrap_or(name).name), - PathListItemKind::Mod { rename, .. } => { + let node = source_item.node; + let (module_path, name, rename) = { + if node.name.name != keywords::SelfValue.name() { + let rename = node.rename.unwrap_or(node.name).name; + (module_path.clone(), node.name.name, rename) + } else { let name = match module_path.last() { Some(name) => *name, None => { @@ -164,12 +167,12 @@ impl<'b> Resolver<'b> { } }; let module_path = module_path.split_last().unwrap().1; - let rename = rename.map(|i| i.name).unwrap_or(name); + let rename = node.rename.map(|i| i.name).unwrap_or(name); (module_path.to_vec(), name, rename) } }; let subclass = ImportDirectiveSubclass::single(rename, name); - let (span, id) = (source_item.span, source_item.node.id()); + let (span, id) = (source_item.span, source_item.node.id); self.add_import_directive(module_path, subclass, span, id, vis); } } diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 3084d9abbe1e4..bc923ba29ca47 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -101,7 +101,7 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { ViewPathList(_, ref list) => { for i in list { - self.check_import(i.node.id(), i.span); + self.check_import(i.node.id, i.span); } } ViewPathGlob(_) => { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5e967f3250f71..dbe956f021e4c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1102,18 +1102,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } ast::ViewPathList(ref path, ref list) => { for plid in list { - match plid.node { - ast::PathListItemKind::Ident { id, .. } => { - let scope = self.cur_scope; - if let Some(def_id) = self.lookup_type_ref(id) { - self.process_def_kind(id, - plid.span, - Some(plid.span), - def_id, - scope); - } - } - ast::PathListItemKind::Mod { .. } => (), + let scope = self.cur_scope; + let id = plid.node.id; + if let Some(def_id) = self.lookup_type_ref(id) { + let span = plid.span; + self.process_def_kind(id, span, Some(span), def_id, scope); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..8265798e796f3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1624,42 +1624,14 @@ pub struct Variant_ { pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum PathListItemKind { - Ident { - name: Ident, - /// renamed in list, e.g. `use foo::{bar as baz};` - rename: Option, - id: NodeId - }, - Mod { - /// renamed in list, e.g. `use foo::{self as baz};` - rename: Option, - id: NodeId - } -} - -impl PathListItemKind { - pub fn id(&self) -> NodeId { - match *self { - PathListItemKind::Ident { id, .. } | PathListItemKind::Mod { id, .. } => id - } - } - - pub fn name(&self) -> Option { - match *self { - PathListItemKind::Ident { name, .. } => Some(name), - PathListItemKind::Mod { .. } => None, - } - } - - pub fn rename(&self) -> Option { - match *self { - PathListItemKind::Ident { rename, .. } | PathListItemKind::Mod { rename, .. } => rename - } - } +pub struct PathListItem_ { + pub name: Ident, + /// renamed in list, e.g. `use foo::{bar as baz};` + pub rename: Option, + pub id: NodeId, } -pub type PathListItem = Spanned; +pub type PathListItem = Spanned; pub type ViewPath = Spanned; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..5d22930c4d59c 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1178,7 +1178,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn item_use_list(&self, sp: Span, vis: ast::Visibility, path: Vec, imports: &[ast::Ident]) -> P { let imports = imports.iter().map(|id| { - let item = ast::PathListItemKind::Ident { + let item = ast::PathListItem_ { name: *id, rename: None, id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b257ab98987dc..9eb6217e50995 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -307,18 +307,10 @@ pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P< ViewPathList(fld.fold_path(path), path_list_idents.move_map(|path_list_ident| { Spanned { - node: match path_list_ident.node { - PathListItemKind::Ident { id, name, rename } => - PathListItemKind::Ident { - id: fld.new_id(id), - rename: rename, - name: name - }, - PathListItemKind::Mod { id, rename } => - PathListItemKind::Mod { - id: fld.new_id(id), - rename: rename - } + node: PathListItem_ { + id: fld.new_id(path_list_ident.node.id), + rename: path_list_ident.node.rename, + name: path_list_ident.node.name, }, span: fld.new_span(path_list_ident.span) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9443df6321bd0..63dbd325075c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6017,13 +6017,16 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Brace), SeqSep::trailing_allowed(token::Comma), |this| { let lo = this.span.lo; - let node = if this.eat_keyword(keywords::SelfValue) { - let rename = this.parse_rename()?; - ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename } + let ident = if this.eat_keyword(keywords::SelfValue) { + keywords::SelfValue.ident() } else { - let ident = this.parse_ident()?; - let rename = this.parse_rename()?; - ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID } + this.parse_ident()? + }; + let rename = this.parse_rename()?; + let node = ast::PathListItem_ { + name: ident, + rename: rename, + id: ast::DUMMY_NODE_ID }; let hi = this.last_span.hi; Ok(spanned(lo, hi, node)) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..65a5e06028fea 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2878,26 +2878,13 @@ impl<'a> State<'a> { try!(word(&mut self.s, "::{")); } try!(self.commasep(Inconsistent, &idents[..], |s, w| { - match w.node { - ast::PathListItemKind::Ident { name, rename, .. } => { - try!(s.print_ident(name)); - if let Some(ident) = rename { - try!(space(&mut s.s)); - try!(s.word_space("as")); - try!(s.print_ident(ident)); - } - Ok(()) - }, - ast::PathListItemKind::Mod { rename, .. } => { - try!(word(&mut s.s, "self")); - if let Some(ident) = rename { - try!(space(&mut s.s)); - try!(s.word_space("as")); - try!(s.print_ident(ident)); - } - Ok(()) - } + try!(s.print_ident(w.node.name)); + if let Some(ident) = w.node.rename { + try!(space(&mut s.s)); + try!(s.word_space("as")); + try!(s.print_ident(ident)); } + Ok(()) })); word(&mut self.s, "}") } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 582412119caa8..1124a5414b86d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -367,8 +367,8 @@ pub fn walk_path(visitor: &mut V, path: &Path) { } pub fn walk_path_list_item(visitor: &mut V, _prefix: &Path, item: &PathListItem) { - walk_opt_ident(visitor, item.span, item.node.name()); - walk_opt_ident(visitor, item.span, item.node.rename()); + visitor.visit_ident(item.span, item.node.name); + walk_opt_ident(visitor, item.span, item.node.rename); } pub fn walk_path_segment(visitor: &mut V, path_span: Span, segment: &PathSegment) { From c4d577be1acf333ff9c51c85fd1dd19adc46cb59 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Aug 2016 09:15:02 +0000 Subject: [PATCH 196/768] Refactor away variant `hir::PathListItem_::Mod` and refacotor `hir::PathListItem_::Ident` -> `hir::PathListItem_`. --- src/librustc/hir/fold.rs | 14 +++-------- src/librustc/hir/intravisit.rs | 12 ++++----- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/mod.rs | 39 ++++------------------------- src/librustc/hir/print.rs | 11 +------- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_lint/unused.rs | 11 +++----- src/librustc_typeck/check_unused.rs | 2 +- 10 files changed, 25 insertions(+), 72 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 0edfd16bdfd1b..5e4ca82dd0090 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -271,16 +271,10 @@ pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P< ViewPathList(fld.fold_path(path), path_list_idents.move_map(|path_list_ident| { Spanned { - node: match path_list_ident.node { - PathListIdent { id, name, rename } => PathListIdent { - id: fld.new_id(id), - name: name, - rename: rename, - }, - PathListMod { id, rename } => PathListMod { - id: fld.new_id(id), - rename: rename, - }, + node: PathListItem_ { + id: fld.new_id(path_list_ident.node.id), + name: path_list_ident.node.name, + rename: path_list_ident.node.rename, }, span: fld.new_span(path_list_ident.span), } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 92b956788860e..bc1dff7c6fc31 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -444,12 +444,12 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { } } -pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, - _prefix: &'v Path, - item: &'v PathListItem) { - visitor.visit_id(item.node.id()); - walk_opt_name(visitor, item.span, item.node.name()); - walk_opt_name(visitor, item.span, item.node.rename()); +pub fn walk_path_list_item<'v, V>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem) + where V: Visitor<'v>, +{ + visitor.visit_id(item.node.id); + visitor.visit_name(item.span, item.node.name); + walk_opt_name(visitor, item.span, item.node.rename); } pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index afb8f5de8eadd..691396b9b7751 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -218,7 +218,7 @@ impl<'a> LoweringContext<'a> { fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem { Spanned { - node: hir::PathListIdent { + node: hir::PathListItem_ { id: path_list_ident.node.id, name: path_list_ident.node.name.name, rename: path_list_ident.node.rename.map(|rename| rename.name), diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index b70190181af8f..280c0f3048569 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -120,7 +120,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { match view_path.node { ViewPathList(_, ref paths) => { for path in paths { - this.insert(path.node.id(), NodeItem(i)); + this.insert(path.node.id, NodeItem(i)); } } _ => () diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d41cdfabdf4c0..d6b8a84698a87 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -20,7 +20,6 @@ pub use self::FunctionRetTy::*; pub use self::ForeignItem_::*; pub use self::Item_::*; pub use self::Mutability::*; -pub use self::PathListItem_::*; pub use self::PrimTy::*; pub use self::Stmt_::*; pub use self::TraitItem_::*; @@ -1337,39 +1336,11 @@ pub struct Variant_ { pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum PathListItem_ { - PathListIdent { - name: Name, - /// renamed in list, eg `use foo::{bar as baz};` - rename: Option, - id: NodeId, - }, - PathListMod { - /// renamed in list, eg `use foo::{self as baz};` - rename: Option, - id: NodeId, - }, -} - -impl PathListItem_ { - pub fn id(&self) -> NodeId { - match *self { - PathListIdent { id, .. } | PathListMod { id, .. } => id, - } - } - - pub fn name(&self) -> Option { - match *self { - PathListIdent { name, .. } => Some(name), - PathListMod { .. } => None, - } - } - - pub fn rename(&self) -> Option { - match *self { - PathListIdent { rename, .. } | PathListMod { rename, .. } => rename, - } - } +pub struct PathListItem_ { + pub name: Name, + /// renamed in list, eg `use foo::{bar as baz};` + pub rename: Option, + pub id: NodeId, } pub type PathListItem = Spanned; diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 66c1bc7642c56..cdd8a36fbad6c 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -2133,16 +2133,7 @@ impl<'a> State<'a> { self.print_path(path, false, 0)?; word(&mut self.s, "::{")?; } - self.commasep(Inconsistent, &segments[..], |s, w| { - match w.node { - hir::PathListIdent { name, .. } => { - s.print_name(name) - } - hir::PathListMod { .. } => { - word(&mut s.s, "self") - } - } - })?; + self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?; word(&mut self.s, "}") } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2a8594c59a837..cdd774e11d328 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -294,7 +294,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { } fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) { - self.lookup_and_handle_definition(item.node.id()); + self.lookup_and_handle_definition(item.node.id); intravisit::walk_path_list_item(self, path, item); } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index cbbc2c4f98f5e..6a57f510cdd9a 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -631,7 +631,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { - match tcx.expect_def(item.node.id()) { + match tcx.expect_def(item.node.id) { Def::PrimTy(..) => {} def => { maybe_do_stability_check(tcx, def.def_id(), item.span, cb); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 57705301aab4e..1ec0bba5f5bcd 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -20,6 +20,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; use syntax::attr::{self, AttrMetaMethods}; use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; +use syntax::parse::token::keywords; use syntax::ptr::P; use syntax_pos::Span; @@ -392,13 +393,9 @@ impl LateLintPass for UnusedImportBraces { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if let hir::ItemUse(ref view_path) = item.node { if let hir::ViewPathList(_, ref items) = view_path.node { - if items.len() == 1 { - if let hir::PathListIdent {ref name, ..} = items[0].node { - let m = format!("braces around {} is unnecessary", - name); - cx.span_lint(UNUSED_IMPORT_BRACES, item.span, - &m[..]); - } + if items.len() == 1 && items[0].node.name != keywords::SelfValue.name() { + let msg = format!("braces around {} is unnecessary", items[0].node.name); + cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg); } } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 2ee0927f3c8ea..f66f15b238e73 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { } hir::ViewPathList(_, ref path_list) => { for path_item in path_list { - self.check_import(path_item.node.id(), path_item.span); + self.check_import(path_item.node.id, path_item.span); } } } From 9d99fe98ad1980b8bc00678f27b2e324e584bea9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Aug 2016 23:09:41 +0000 Subject: [PATCH 197/768] Fix fallout in `rustdoc`. --- src/librustdoc/clean/mod.rs | 17 +++++------------ src/librustdoc/visit_ast.rs | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 39b1a04e98e69..ad2452de33cfe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2513,7 +2513,7 @@ impl Clean> for doctree::Import { let remaining = if !denied { let mut remaining = vec![]; for path in list { - match inline::try_inline(cx, path.node.id(), path.node.rename()) { + match inline::try_inline(cx, path.node.id, path.node.rename) { Some(items) => { ret.extend(items); } @@ -2581,17 +2581,10 @@ pub struct ViewListIdent { impl Clean for hir::PathListItem { fn clean(&self, cx: &DocContext) -> ViewListIdent { - match self.node { - hir::PathListIdent { id, name, rename } => ViewListIdent { - name: name.clean(cx), - rename: rename.map(|r| r.clean(cx)), - source: resolve_def(cx, id) - }, - hir::PathListMod { id, rename } => ViewListIdent { - name: "self".to_string(), - rename: rename.map(|r| r.clean(cx)), - source: resolve_def(cx, id) - } + ViewListIdent { + name: self.node.name.clean(cx), + rename: self.node.rename.map(|r| r.clean(cx)), + source: resolve_def(cx, self.node.id) } } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0334c5ef5c4f4..d2da97666af07 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -189,7 +189,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } hir::ViewPathList(p, paths) => { let mine = paths.into_iter().filter(|path| { - !self.maybe_inline_local(path.node.id(), path.node.rename(), + !self.maybe_inline_local(path.node.id, path.node.rename, false, om, please_inline) }).collect::>(); From ef6aab2935a504787d01b1d9165d41b184a6027c Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Fri, 29 Jul 2016 07:48:52 +0000 Subject: [PATCH 198/768] Reduce duplication in std::sys::unix::rand. There were a bunch of more-of-less the same few lines for doing a fill_bytes+transmute, and I didn't want to copy-paste it yet again. --- src/libstd/sys/unix/rand.rs | 54 +++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 25a7a3ce50dc4..4e6d801d19176 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -10,14 +10,28 @@ pub use self::imp::OsRng; +use mem; + +fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 { + let mut buf: [u8; 4] = [0; 4]; + fill_buf(&mut buf); + unsafe { mem::transmute::<[u8; 4], u32>(buf) } +} + +fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { + let mut buf: [u8; 8] = [0; 8]; + fill_buf(&mut buf); + unsafe { mem::transmute::<[u8; 8], u64>(buf) } +} + #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] mod imp { use self::OsRngInner::*; + use super::{next_u32, next_u64}; use fs::File; use io; use libc; - use mem; use rand::Rng; use rand::reader::ReaderRng; use sys::os::errno; @@ -87,18 +101,6 @@ mod imp { } } - fn getrandom_next_u32() -> u32 { - let mut buf: [u8; 4] = [0; 4]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 4], u32>(buf) } - } - - fn getrandom_next_u64() -> u64 { - let mut buf: [u8; 8] = [0; 8]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 8], u64>(buf) } - } - #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", @@ -163,13 +165,13 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { match self.inner { - OsGetrandomRng => getrandom_next_u32(), + OsGetrandomRng => next_u32(&mut getrandom_fill_bytes), OsReaderRng(ref mut rng) => rng.next_u32(), } } fn next_u64(&mut self) -> u64 { match self.inner { - OsGetrandomRng => getrandom_next_u64(), + OsGetrandomRng => next_u64(&mut getrandom_fill_bytes), OsReaderRng(ref mut rng) => rng.next_u64(), } } @@ -184,9 +186,10 @@ mod imp { #[cfg(target_os = "openbsd")] mod imp { + use super::{next_u32, next_u64}; + use io; use libc; - use mem; use sys::os::errno; use rand::Rng; @@ -205,14 +208,10 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u32(&mut |v| self.fill_bytes(v)) } fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u64(&mut |v| self.fill_bytes(v)) } fn fill_bytes(&mut self, v: &mut [u8]) { // getentropy(2) permits a maximum buffer size of 256 bytes @@ -230,8 +229,9 @@ mod imp { #[cfg(target_os = "ios")] mod imp { + use super::{next_u32, next_u64}; + use io; - use mem; use ptr; use rand::Rng; use libc::{c_int, size_t}; @@ -265,14 +265,10 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u32(&mut |v| self.fill_bytes(v)) } fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u64(&mut |v| self.fill_bytes(v)) } fn fill_bytes(&mut self, v: &mut [u8]) { let ret = unsafe { From 0a70944e043db082353ed05cfa80994f6c56feae Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 14 Aug 2016 08:27:11 +0000 Subject: [PATCH 199/768] Use the kernel arc4rand for FreeBSD OsRng. This means that /dev/urandom doesn't have to be opened. --- src/libstd/sys/unix/rand.rs | 53 ++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 4e6d801d19176..e4ca8344ee287 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -24,7 +24,10 @@ fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { unsafe { mem::transmute::<[u8; 8], u64>(buf) } } -#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] +#[cfg(all(unix, + not(target_os = "ios"), + not(target_os = "openbsd"), + not(target_os = "freebsd")))] mod imp { use self::OsRngInner::*; use super::{next_u32, next_u64}; @@ -282,3 +285,51 @@ mod imp { } } } + +#[cfg(target_os = "freebsd")] +mod imp { + use super::{next_u32, next_u64}; + + use io; + use libc; + use rand::Rng; + use ptr; + + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside + // of this module + _dummy: (), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + Ok(OsRng { _dummy: () }) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + // kern.arandom permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let mut s_len = s.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + s.as_mut_ptr() as *mut _, &mut s_len, + ptr::null(), 0) + }; + if ret == -1 || s_len != s.len() { + panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", + ret, s.len(), s_len); + } + } + } + } +} From b40754f0f75aebcd63ad3b91ac2f94d54bc1c423 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 21 Aug 2016 23:49:22 +0000 Subject: [PATCH 200/768] modify fds-are-cloexec test to open a file that exists Fixes #35753. --- src/test/run-pass/fds-are-cloexec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs index c2916ccd75b8e..b7ce622bf563e 100644 --- a/src/test/run-pass/fds-are-cloexec.rs +++ b/src/test/run-pass/fds-are-cloexec.rs @@ -34,7 +34,7 @@ fn main() { } fn parent() { - let file = File::open("Makefile").unwrap(); + let file = File::open("src/test/run-pass/fds-are-cloexec.rs").unwrap(); let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap(); let tcp2 = tcp1.try_clone().unwrap(); let addr = tcp1.local_addr().unwrap(); From 4b6477f062eb13e6b21011395f634696482a29f5 Mon Sep 17 00:00:00 2001 From: Amit Levy Date: Sun, 21 Aug 2016 22:42:33 -0400 Subject: [PATCH 201/768] Minor type in CONTRIBUTING.md A single missing article --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6093577078181..4e6cd6c9782a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -230,7 +230,7 @@ To find documentation-related issues, sort by the [A-docs label][adocs]. In many cases, you don't need a full `make doc`. You can use `rustdoc` directly to check small fixes. For example, `rustdoc src/doc/reference.md` will render reference to `doc/reference.html`. The CSS might be messed up, but you can -verify that HTML is right. +verify that the HTML is right. ## Issue Triage From a5a5c1074e67a5c12157eb88b7a4f055c8938108 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Sun, 21 Aug 2016 23:09:18 -0400 Subject: [PATCH 202/768] Add reference to `Self` in traits chapter (book) --- src/doc/book/traits.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index e685cb129b939..164a851edeff4 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -47,6 +47,28 @@ As you can see, the `trait` block looks very similar to the `impl` block, but we don’t define a body, only a type signature. When we `impl` a trait, we use `impl Trait for Item`, rather than only `impl Item`. +`Self` may be used in a type annotation to refer to an instance of the type +implementing this trait passed as a parameter. `Self`, `&Self` or `&mut Self` +may be used depending on the level of ownership required. + +```rust +trait HasArea { + fn area(&self) -> f64; + + fn is_larger(&self, &Self) -> bool; +} + +impl HasArea for Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } + + fn is_larger(&self, other: &Self) -> bool { + self.area() > other.area() + } +} +``` + ## Trait bounds on generic functions Traits are useful because they allow a type to make certain promises about its From 1d78f9eb89c9ad520a7f7f7163ddb0c1e1b674a6 Mon Sep 17 00:00:00 2001 From: Terry Sun Date: Mon, 22 Aug 2016 01:19:44 -0400 Subject: [PATCH 203/768] Add sublime-rust to CONFIGS.md. --- src/etc/CONFIGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/etc/CONFIGS.md b/src/etc/CONFIGS.md index cde7094cec41e..542b7bf797b35 100644 --- a/src/etc/CONFIGS.md +++ b/src/etc/CONFIGS.md @@ -6,6 +6,7 @@ These are some links to repos with configs which ease the use of rust. * [rust.vim](https://github.com/rust-lang/rust.vim) * [emacs rust-mode](https://github.com/rust-lang/rust-mode) +* [sublime-rust](https://github.com/rust-lang/sublime-rust) * [gedit-config](https://github.com/rust-lang/gedit-config) * [kate-config](https://github.com/rust-lang/kate-config) * [nano-config](https://github.com/rust-lang/nano-config) From 820c8101077c430e6fc10481782f5df0862c279c Mon Sep 17 00:00:00 2001 From: Knight Date: Mon, 22 Aug 2016 13:51:21 +0800 Subject: [PATCH 204/768] Updated E0054 to new format --- src/librustc_typeck/check/cast.rs | 1 + src/test/compile-fail/cast-rfc0401.rs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index fb78d3a37ca23..54e63497e6202 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -161,6 +161,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::CastToBool => { struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`") + .span_label(self.span, &format!("unsupported cast")) .help("compare with zero instead") .emit(); } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 05c531e91f128..7839fb45d1c34 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -59,10 +59,12 @@ fn main() //~^ ERROR casting //~^^ HELP through a usize first let _ = 3_i32 as bool; - //~^ ERROR cannot cast as `bool` + //~^ ERROR cannot cast as `bool` [E0054] + //~| unsupported cast //~| HELP compare with zero let _ = E::A as bool; - //~^ ERROR cannot cast as `bool` + //~^ ERROR cannot cast as `bool` [E0054] + //~| unsupported cast //~| HELP compare with zero let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast From a4c6307a157eaf8f9292f2456d7b5055a0b69ea4 Mon Sep 17 00:00:00 2001 From: Knight Date: Mon, 22 Aug 2016 13:57:10 +0800 Subject: [PATCH 205/768] Updated E0432 to new format --- src/librustc_resolve/lib.rs | 8 ++++++-- src/librustc_resolve/resolve_imports.rs | 6 +++--- src/test/compile-fail/import-from-missing.rs | 4 ++-- src/test/compile-fail/import.rs | 7 ++++--- src/test/compile-fail/import2.rs | 4 ++-- src/test/compile-fail/issue-12612.rs | 4 ++-- src/test/compile-fail/issue-13404.rs | 4 ++-- src/test/compile-fail/issue-1697.rs | 3 ++- src/test/compile-fail/issue-2937.rs | 3 ++- src/test/compile-fail/issue-30560.rs | 8 ++++++-- src/test/compile-fail/issue-32833.rs | 6 ++++-- src/test/compile-fail/issue-5035.rs | 3 ++- src/test/compile-fail/issue-8208.rs | 9 ++++++--- src/test/compile-fail/privacy2.rs | 6 ++++-- src/test/compile-fail/privacy3.rs | 3 ++- src/test/compile-fail/resolve_self_super_hint.rs | 12 ++++++++---- src/test/compile-fail/super-at-top-level.rs | 3 ++- src/test/compile-fail/unresolved-import.rs | 12 ++++++++---- src/test/compile-fail/use-from-trait.rs | 6 ++++-- src/test/compile-fail/use-keyword.rs | 11 ++++++++--- src/test/compile-fail/use-mod-2.rs | 6 ++++-- 21 files changed, 83 insertions(+), 45 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0c0582edcc051..e2c9e4aca57dc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -418,10 +418,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, } ResolutionError::UnresolvedImport(name) => { let msg = match name { - Some((n, p)) => format!("unresolved import `{}`{}", n, p), + Some((n, _)) => format!("unresolved import `{}`", n), None => "unresolved import".to_owned(), }; - struct_span_err!(resolver.session, span, E0432, "{}", msg) + let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg); + if let Some((_, p)) = name { + err.span_label(span, &p); + } + err } ResolutionError::FailedToResolve(msg) => { let mut err = struct_span_err!(resolver.session, span, E0433, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c0a9ee1c48380..8c6d89c29bde1 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -423,7 +423,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let Failed(err) = self.finalize_import(import) { errors = true; let (span, help) = match err { - Some((span, msg)) => (span, format!(". {}", msg)), + Some((span, msg)) => (span, msg), None => (import.span, String::new()), }; @@ -596,9 +596,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; let module_str = module_to_string(module); let msg = if &module_str == "???" { - format!("There is no `{}` in the crate root{}", name, lev_suggestion) + format!("no `{}` in the root{}", name, lev_suggestion) } else { - format!("There is no `{}` in `{}`{}", name, module_str, lev_suggestion) + format!("no `{}` in `{}`{}", name, module_str, lev_suggestion) }; Failed(Some((directive.span, msg))) } else { diff --git a/src/test/compile-fail/import-from-missing.rs b/src/test/compile-fail/import-from-missing.rs index bcd2cd816ed45..220b255bde419 100644 --- a/src/test/compile-fail/import-from-missing.rs +++ b/src/test/compile-fail/import-from-missing.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use spam::{ham, eggs}; -//~^ ERROR unresolved import `spam::eggs`. There is no `eggs` in `spam` +use spam::{ham, eggs}; //~ ERROR unresolved import `spam::eggs` [E0432] + //~^ no `eggs` in `spam` mod spam { pub fn ham() { } diff --git a/src/test/compile-fail/import.rs b/src/test/compile-fail/import.rs index ff93cd0f06624..1ca1c060410ad 100644 --- a/src/test/compile-fail/import.rs +++ b/src/test/compile-fail/import.rs @@ -9,13 +9,14 @@ // except according to those terms. use zed::bar; -use zed::baz; -//~^ ERROR unresolved import `zed::baz`. There is no `baz` in `zed` +use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] + //~^ no `baz` in `zed`. Did you mean to use `bar`? mod zed { pub fn bar() { println!("bar"); } - use foo; //~ ERROR unresolved import + use foo; //~ ERROR unresolved import `foo` [E0432] + //~^ no `foo` in the root } fn main() { diff --git a/src/test/compile-fail/import2.rs b/src/test/compile-fail/import2.rs index 1f25bce209314..f5b03f9b2e971 100644 --- a/src/test/compile-fail/import2.rs +++ b/src/test/compile-fail/import2.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use baz::zed::bar; -//~^ ERROR unresolved import `baz::zed::bar`. Could not find `zed` in `baz` +use baz::zed::bar; //~ ERROR unresolved import `baz::zed::bar` [E0432] + //~^ Could not find `zed` in `baz` mod baz {} mod zed { diff --git a/src/test/compile-fail/issue-12612.rs b/src/test/compile-fail/issue-12612.rs index f76d12d93fdf6..20943bd0ea077 100644 --- a/src/test/compile-fail/issue-12612.rs +++ b/src/test/compile-fail/issue-12612.rs @@ -15,8 +15,8 @@ extern crate issue_12612_1 as foo; use foo::bar; mod test { - use bar::foo; - //~^ ERROR unresolved import `bar::foo`. Maybe a missing `extern crate bar`? + use bar::foo; //~ ERROR unresolved import `bar::foo` [E0432] + //~^ Maybe a missing `extern crate bar`? } fn main() {} diff --git a/src/test/compile-fail/issue-13404.rs b/src/test/compile-fail/issue-13404.rs index 355be1562df2b..0059e92e07f07 100644 --- a/src/test/compile-fail/issue-13404.rs +++ b/src/test/compile-fail/issue-13404.rs @@ -9,8 +9,8 @@ // except according to those terms. use a::f; -use b::f; -//~^ ERROR: unresolved import `b::f`. There is no `f` in `b` +use b::f; //~ ERROR: unresolved import `b::f` [E0432] + //~^ no `f` in `b` mod a { pub fn f() {} } mod b { } diff --git a/src/test/compile-fail/issue-1697.rs b/src/test/compile-fail/issue-1697.rs index f2d858391cea2..dc09af0ada66f 100644 --- a/src/test/compile-fail/issue-1697.rs +++ b/src/test/compile-fail/issue-1697.rs @@ -10,6 +10,7 @@ // Testing that we don't fail abnormally after hitting the errors -use unresolved::*; //~ ERROR unresolved import `unresolved::*`. Maybe a missing `extern crate unres +use unresolved::*; //~ ERROR unresolved import `unresolved::*` [E0432] + //~^ Maybe a missing `extern crate unresolved`? fn main() {} diff --git a/src/test/compile-fail/issue-2937.rs b/src/test/compile-fail/issue-2937.rs index e4fae73b18991..0d684ec5ae19b 100644 --- a/src/test/compile-fail/issue-2937.rs +++ b/src/test/compile-fail/issue-2937.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use m::f as x; //~ ERROR unresolved import `m::f`. There is no `f` in `m` +use m::f as x; //~ ERROR unresolved import `m::f` [E0432] + //~^ no `f` in `m` mod m {} diff --git a/src/test/compile-fail/issue-30560.rs b/src/test/compile-fail/issue-30560.rs index 71c7e6009655b..b0cfd8714fc02 100644 --- a/src/test/compile-fail/issue-30560.rs +++ b/src/test/compile-fail/issue-30560.rs @@ -9,8 +9,12 @@ // except according to those terms. type Alias = (); -use Alias::*; //~ ERROR Not a module -use std::io::Result::*; //~ ERROR Not a module +use Alias::*; +//~^ ERROR unresolved import `Alias::*` [E0432] +//~| Not a module `Alias` +use std::io::Result::*; +//~^ ERROR unresolved import `std::io::Result::*` [E0432] +//~| Not a module `Result` trait T {} use T::*; //~ ERROR items in traits are not importable diff --git a/src/test/compile-fail/issue-32833.rs b/src/test/compile-fail/issue-32833.rs index 22261d98a128c..d610e8b483798 100644 --- a/src/test/compile-fail/issue-32833.rs +++ b/src/test/compile-fail/issue-32833.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use bar::Foo; //~ ERROR There is no `Foo` in `bar` [E0432] +use bar::Foo; //~ ERROR unresolved import `bar::Foo` [E0432] + //~^ no `Foo` in `bar` mod bar { - use Foo; //~ ERROR There is no `Foo` in the crate root [E0432] + use Foo; //~ ERROR unresolved import `Foo` [E0432] + //~^ no `Foo` in the root } fn main() {} diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index c2154e8a6c0b6..7a36012925eed 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -14,7 +14,8 @@ impl K for isize {} //~ ERROR: `K` is not a trait //~| NOTE: not a trait //~| NOTE: aliases cannot be used for traits -use ImportError; //~ ERROR unresolved +use ImportError; //~ ERROR unresolved import `ImportError` [E0432] + //~^ no `ImportError` in the root impl ImportError for () {} // check that this is not an additional error (c.f. #35142) fn main() {} diff --git a/src/test/compile-fail/issue-8208.rs b/src/test/compile-fail/issue-8208.rs index 318089b3030f6..670b6bd46e7d8 100644 --- a/src/test/compile-fail/issue-8208.rs +++ b/src/test/compile-fail/issue-8208.rs @@ -8,14 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::*; //~ ERROR: unresolved import `self::*`. Cannot glob-import a module into itself. +use self::*; //~ ERROR: unresolved import `self::*` [E0432] + //~^ Cannot glob-import a module into itself. mod foo { - use foo::*; //~ ERROR: unresolved import `foo::*`. Cannot glob-import a module into itself. + use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] + //~^ Cannot glob-import a module into itself. mod bar { use super::bar::*; - //~^ ERROR: unresolved import `super::bar::*`. Cannot glob-import a module into itself. + //~^ ERROR: unresolved import `super::bar::*` [E0432] + //~| Cannot glob-import a module into itself. } } diff --git a/src/test/compile-fail/privacy2.rs b/src/test/compile-fail/privacy2.rs index abf702204d16b..376e95312b8fb 100644 --- a/src/test/compile-fail/privacy2.rs +++ b/src/test/compile-fail/privacy2.rs @@ -25,12 +25,14 @@ pub fn foo() {} fn test1() { use bar::foo; - //~^ ERROR unresolved import `bar::foo`. There is no `foo` in `bar` + //~^ ERROR unresolved import `bar::foo` [E0432] + //~| no `foo` in `bar` } fn test2() { use bar::glob::foo; - //~^ ERROR unresolved import `bar::glob::foo`. There is no `foo` in `bar::glob` + //~^ ERROR unresolved import `bar::glob::foo` [E0432] + //~| no `foo` in `bar::glob` } #[start] fn main(_: isize, _: *const *const u8) -> isize { 3 } diff --git a/src/test/compile-fail/privacy3.rs b/src/test/compile-fail/privacy3.rs index 89f38fa143445..b841717bd11d8 100644 --- a/src/test/compile-fail/privacy3.rs +++ b/src/test/compile-fail/privacy3.rs @@ -26,7 +26,8 @@ pub fn foo() {} fn test1() { use bar::gpriv; - //~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar` + //~^ ERROR unresolved import `bar::gpriv` [E0432] + //~| no `gpriv` in `bar` // This should pass because the compiler will insert a fake name binding // for `gpriv` diff --git a/src/test/compile-fail/resolve_self_super_hint.rs b/src/test/compile-fail/resolve_self_super_hint.rs index ed143fdff687f..a23ac80fca620 100644 --- a/src/test/compile-fail/resolve_self_super_hint.rs +++ b/src/test/compile-fail/resolve_self_super_hint.rs @@ -11,16 +11,20 @@ mod a { extern crate collections; use collections::HashMap; -//~^ ERROR unresolved import `collections::HashMap`. Did you mean `self::collections`? + //~^ ERROR unresolved import `collections::HashMap` [E0432] + //~| Did you mean `self::collections`? mod b { use collections::HashMap; -//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`? + //~^ ERROR unresolved import `collections::HashMap` [E0432] + //~| Did you mean `a::collections`? mod c { use collections::HashMap; -//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`? + //~^ ERROR unresolved import `collections::HashMap` [E0432] + //~| Did you mean `a::collections`? mod d { use collections::HashMap; -//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`? + //~^ ERROR unresolved import `collections::HashMap` [E0432] + //~| Did you mean `a::collections`? } } } diff --git a/src/test/compile-fail/super-at-top-level.rs b/src/test/compile-fail/super-at-top-level.rs index f59caef463136..7d11ff6c9b54d 100644 --- a/src/test/compile-fail/super-at-top-level.rs +++ b/src/test/compile-fail/super-at-top-level.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::f; //~ ERROR unresolved import `super::f`. There are too many initial `super`s. +use super::f; //~ ERROR unresolved import `super::f` [E0432] + //~^ There are too many initial `super`s. fn main() { } diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index b60d19fcab4aa..d1254f3f5241b 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -10,13 +10,17 @@ // ignore-tidy-linelength -use foo::bar; //~ ERROR unresolved import `foo::bar`. Maybe a missing `extern crate foo`? +use foo::bar; //~ ERROR unresolved import `foo::bar` [E0432] + //~^ Maybe a missing `extern crate foo`? -use bar::Baz as x; //~ ERROR unresolved import `bar::Baz`. There is no `Baz` in `bar`. Did you mean to use `Bar`? +use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] + //~^ no `Baz` in `bar`. Did you mean to use `Bar`? -use food::baz; //~ ERROR unresolved import `food::baz`. There is no `baz` in `food`. Did you mean to use `bag`? +use food::baz; //~ ERROR unresolved import `food::baz` + //~^ no `baz` in `food`. Did you mean to use `bag`? -use food::{beens as Foo}; //~ ERROR unresolved import `food::beens`. There is no `beens` in `food`. Did you mean to use `beans`? +use food::{beens as Foo}; //~ ERROR unresolved import `food::beens` [E0432] + //~^ no `beens` in `food`. Did you mean to use `beans`? mod bar { pub struct Bar; diff --git a/src/test/compile-fail/use-from-trait.rs b/src/test/compile-fail/use-from-trait.rs index 28e933bc7aa0a..58e37bbfa3ea7 100644 --- a/src/test/compile-fail/use-from-trait.rs +++ b/src/test/compile-fail/use-from-trait.rs @@ -18,10 +18,12 @@ use Trait::C; //~^ ERROR `C` is not directly importable use Foo::new; -//~^ ERROR unresolved import `Foo::new`. Not a module `Foo` +//~^ ERROR unresolved import `Foo::new` [E0432] +//~| Not a module `Foo` use Foo::C2; -//~^ ERROR unresolved import `Foo::C2`. Not a module `Foo` +//~^ ERROR unresolved import `Foo::C2` [E0432] +//~| Not a module `Foo` pub trait Trait { fn foo(); diff --git a/src/test/compile-fail/use-keyword.rs b/src/test/compile-fail/use-keyword.rs index 040db0255678d..6df20d414a788 100644 --- a/src/test/compile-fail/use-keyword.rs +++ b/src/test/compile-fail/use-keyword.rs @@ -14,9 +14,14 @@ mod a { mod b { use self as A; //~ ERROR `self` imports are only allowed within a { } list - //~^ ERROR unresolved import `self`. There is no `self` in the crate root - use super as B; //~ ERROR unresolved import `super`. There is no `super` in the crate root - use super::{self as C}; //~ERROR unresolved import `super`. There is no `super` in the crate + //~^ ERROR unresolved import `self` [E0432] + //~| no `self` in the root + use super as B; + //~^ ERROR unresolved import `super` [E0432] + //~| no `super` in the root + use super::{self as C}; + //~^ ERROR unresolved import `super` [E0432] + //~| no `super` in the root } } diff --git a/src/test/compile-fail/use-mod-2.rs b/src/test/compile-fail/use-mod-2.rs index f2384912cdba3..5f8842a521abd 100644 --- a/src/test/compile-fail/use-mod-2.rs +++ b/src/test/compile-fail/use-mod-2.rs @@ -10,10 +10,12 @@ mod foo { use self::{self}; - //~^ ERROR unresolved import `self`. There is no `self` in the crate root + //~^ ERROR unresolved import `self` [E0432] + //~| no `self` in the root use super::{self}; - //~^ ERROR unresolved import `super`. There is no `super` in the crate root + //~^ ERROR unresolved import `super` [E0432] + //~| no `super` in the root } fn main() {} From 8fdc53144615760a6c6f532a20d487e5b948167a Mon Sep 17 00:00:00 2001 From: Knight Date: Mon, 22 Aug 2016 13:57:37 +0800 Subject: [PATCH 206/768] Updated E0423 to new format --- src/librustc_resolve/lib.rs | 6 ++++-- src/test/compile-fail/E0423.rs | 1 + src/test/compile-fail/issue-18252.rs | 4 +++- src/test/compile-fail/issue-19452.rs | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e2c9e4aca57dc..6bf4da438dd20 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -336,12 +336,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::StructVariantUsedAsFunction(path_name) => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0423, "`{}` is the name of a struct or struct variant, but this expression \ uses it like a function name", - path_name) + path_name); + err.span_label(span, &format!("struct called like a function")); + err } ResolutionError::SelfNotAvailableInStaticMethod => { struct_span_err!(resolver.session, diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs index f5fea77cf9639..98b700984a707 100644 --- a/src/test/compile-fail/E0423.rs +++ b/src/test/compile-fail/E0423.rs @@ -12,4 +12,5 @@ fn main () { struct Foo { a: bool }; let f = Foo(); //~ ERROR E0423 + //~^ struct called like a function } diff --git a/src/test/compile-fail/issue-18252.rs b/src/test/compile-fail/issue-18252.rs index e3e56c7f97ad5..8e3faca02b7d1 100644 --- a/src/test/compile-fail/issue-18252.rs +++ b/src/test/compile-fail/issue-18252.rs @@ -13,5 +13,7 @@ enum Foo { } fn main() { - let f = Foo::Variant(42); //~ ERROR uses it like a function + let f = Foo::Variant(42); + //~^ ERROR uses it like a function + //~| struct called like a function } diff --git a/src/test/compile-fail/issue-19452.rs b/src/test/compile-fail/issue-19452.rs index 2270ba594ad2b..15d5d2b80c31d 100644 --- a/src/test/compile-fail/issue-19452.rs +++ b/src/test/compile-fail/issue-19452.rs @@ -13,5 +13,7 @@ enum Homura { } fn main() { - let homura = Homura::Madoka; //~ ERROR uses it like a function + let homura = Homura::Madoka; + //~^ ERROR uses it like a function + //~| struct called like a function } From cdb4af848b4f17f2270ee4c10efc48f508e0ed91 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 22 Aug 2016 14:53:28 +0200 Subject: [PATCH 207/768] Remove E0455 test (for now) --- src/test/compile-fail/E0455.rs | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 src/test/compile-fail/E0455.rs diff --git a/src/test/compile-fail/E0455.rs b/src/test/compile-fail/E0455.rs deleted file mode 100644 index a90f97f89f490..0000000000000 --- a/src/test/compile-fail/E0455.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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 = "FooCoreServices", kind = "framework")] extern {} //~ ERROR E0455 - -fn main() { -} From 3da5f9327a3a54a280a299fd38ff8376d3d5d419 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Mon, 22 Aug 2016 12:10:02 -0400 Subject: [PATCH 208/768] Correct failing book test --- src/doc/book/traits.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index 164a851edeff4..9cbb514e28065 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -52,6 +52,12 @@ implementing this trait passed as a parameter. `Self`, `&Self` or `&mut Self` may be used depending on the level of ownership required. ```rust +struct Circle { + x: f64, + y: f64, + radius: f64, +} + trait HasArea { fn area(&self) -> f64; From 38f0bca8657fa330561edb4dca04efe8a898f6ea Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sat, 20 Aug 2016 14:14:04 -0400 Subject: [PATCH 209/768] replace `Mul` example with something more evocative of multiplication I may have gone a bit overboard on this one. Numbers are fun. tone down the error message --- src/libcore/ops.rs | 57 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..e928e970f7e85 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -274,26 +274,63 @@ sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Mul`. When `Foo * Foo` happens, it ends up -/// calling `mul`, and therefore, `main` prints `Multiplying!`. +/// Implementing a `Mul`tipliable rational number struct: /// /// ``` /// use std::ops::Mul; /// -/// struct Foo; +/// // The uniqueness of rational numbers in lowest terms is a consequence of +/// // the fundamental theorem of arithmetic. +/// #[derive(Eq)] +/// #[derive(PartialEq, Debug)] +/// struct Rational { +/// nominator: usize, +/// denominator: usize, +/// } +/// +/// impl Rational { +/// fn new(nominator: usize, denominator: usize) -> Self { +/// if denominator == 0 { +/// panic!("Zero is an invalid denominator!"); +/// } +/// +/// // Reduce to lowest terms by dividing by the greatest common +/// // divisor. +/// let gcd = gcd(nominator, denominator); +/// Rational { +/// nominator: nominator / gcd, +/// denominator: denominator / gcd, +/// } +/// } +/// } /// -/// impl Mul for Foo { -/// type Output = Foo; +/// impl Mul for Rational { +/// // The multiplication of rational numbers is a closed operation. +/// type Output = Self; /// -/// fn mul(self, _rhs: Foo) -> Foo { -/// println!("Multiplying!"); -/// self +/// fn mul(self, rhs: Self) -> Self { +/// let nominator = self.nominator * rhs.nominator; +/// let denominator = self.denominator * rhs.denominator; +/// Rational::new(nominator, denominator) /// } /// } /// -/// fn main() { -/// Foo * Foo; +/// // Euclid's two-thousand-year-old algorithm for finding the greatest common +/// // divisor. +/// fn gcd(x: usize, y: usize) -> usize { +/// let mut x = x; +/// let mut y = y; +/// while y != 0 { +/// let t = y; +/// y = x % y; +/// x = t; +/// } +/// x /// } +/// +/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); +/// assert_eq!(Rational::new(2, 3) * Rational::new(3, 4), +/// Rational::new(1, 2)); /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] From 9f88f8ae4831a6f78781dd7c06181c8f3d21ad75 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 17:19:17 -0400 Subject: [PATCH 210/768] replace `BitAnd` example with something more evocative of bitwise AND reformat method chain according to ubsan Rustic Style Guide https://ubsan.github.io/style/ --- src/libcore/ops.rs | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9347ac2a8c82f..da90bdbde04fa 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -591,26 +591,41 @@ not_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// /// # Examples /// -/// A trivial implementation of `BitAnd`. When `Foo & Foo` happens, it ends up -/// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`. +/// In this example, the `BitAnd` trait is implemented for a `BooleanVector` +/// struct. /// /// ``` /// use std::ops::BitAnd; /// -/// struct Foo; -/// -/// impl BitAnd for Foo { -/// type Output = Foo; -/// -/// fn bitand(self, _rhs: Foo) -> Foo { -/// println!("Bitwise And-ing!"); -/// self +/// #[derive(Debug)] +/// struct BooleanVector { +/// value: Vec, +/// }; +/// +/// impl BitAnd for BooleanVector { +/// type Output = Self; +/// +/// fn bitand(self, rhs: Self) -> Self { +/// BooleanVector { +/// value: self.value +/// .iter() +/// .zip(rhs.value.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect(), +/// } /// } /// } /// -/// fn main() { -/// Foo & Foo; +/// impl PartialEq for BooleanVector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } /// } +/// +/// let bv1 = BooleanVector { value: vec![true, true, false, false] }; +/// let bv2 = BooleanVector { value: vec![true, false, true, false] }; +/// let expected = BooleanVector { value: vec![true, false, false, false] }; +/// assert_eq!(bv1 & bv2, expected); /// ``` #[lang = "bitand"] #[stable(feature = "rust1", since = "1.0.0")] From eb6d44d697e00f561411a07f306702ddb2078b2d Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sun, 21 Aug 2016 16:01:27 -0400 Subject: [PATCH 211/768] more evocative examples for `Sub` and `SubAssign` These examples are exactly analogous to those in PRs #35709 and #35806. I'll probably remove the `fn main` wrappers for `Add` and `Sub` once this is merged in. Part of #29365. r? @steveklabnik --- src/libcore/ops.rs | 62 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 3a2d6c8bcf7d6..dffd9ca214ecb 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -245,25 +245,38 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Sub`. When `Foo - Foo` happens, it ends up -/// calling `sub`, and therefore, `main` prints `Subtracting!`. +/// This example creates a `Point` struct that implements the `Sub` trait, and +/// then demonstrates subtracting two `Point`s. /// /// ``` /// use std::ops::Sub; /// -/// struct Foo; +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } /// -/// impl Sub for Foo { -/// type Output = Foo; +/// impl Sub for Point { +/// type Output = Point; /// -/// fn sub(self, _rhs: Foo) -> Foo { -/// println!("Subtracting!"); -/// self +/// fn sub(self, other: Point) -> Point { +/// Point { +/// x: self.x - other.x, +/// y: self.y - other.y, +/// } +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y /// } /// } /// /// fn main() { -/// Foo - Foo; +/// assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 }, +/// Point { x: 1, y: 0 }); /// } /// ``` #[lang = "sub"] @@ -1053,25 +1066,36 @@ add_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `SubAssign`. When `Foo -= Foo` happens, it ends up -/// calling `sub_assign`, and therefore, `main` prints `Subtracting!`. +/// This example creates a `Point` struct that implements the `SubAssign` +/// trait, and then demonstrates sub-assigning to a mutable `Point`. /// /// ``` /// use std::ops::SubAssign; /// -/// struct Foo; +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } /// -/// impl SubAssign for Foo { -/// fn sub_assign(&mut self, _rhs: Foo) { -/// println!("Subtracting!"); +/// impl SubAssign for Point { +/// fn sub_assign(&mut self, other: Point) { +/// *self = Point { +/// x: self.x - other.x, +/// y: self.y - other.y, +/// }; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo -= Foo; +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } /// } +/// +/// let mut point = Point { x: 3, y: 3 }; +/// point -= Point { x: 2, y: 3 }; +/// assert_eq!(point, Point {x: 1, y: 0}); /// ``` #[lang = "sub_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] From bfbdff0e2d894cf1f88e93df864b2c02e940a99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Medzi=C5=84ski?= Date: Fri, 5 Aug 2016 11:27:59 +0200 Subject: [PATCH 212/768] Updated error message E0388 --- src/librustc_borrowck/borrowck/mod.rs | 6 ++++-- src/test/compile-fail/E0017.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 904cffac6b3cd..ada8a3d80b23a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -910,9 +910,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } mc::AliasableStatic | mc::AliasableStaticMut => { - struct_span_err!( + let mut err = struct_span_err!( self.tcx.sess, span, E0388, - "{} in a static location", prefix) + "{} in a static location", prefix); + err.span_label(span, &format!("cannot write data in a static definition")); + err } mc::AliasableBorrowed => { struct_span_err!( diff --git a/src/test/compile-fail/E0017.rs b/src/test/compile-fail/E0017.rs index 13f2c23d8c4a9..8f043d16c1134 100644 --- a/src/test/compile-fail/E0017.rs +++ b/src/test/compile-fail/E0017.rs @@ -16,6 +16,7 @@ const CR: &'static mut i32 = &mut C; //~ ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| ERROR E0017 //~| ERROR E0388 + //~| NOTE cannot write data in a static definition static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 From 6961d267298b6ca0507520de5541883374d31302 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Mon, 22 Aug 2016 16:51:37 -0700 Subject: [PATCH 213/768] Fix compiletest so it respects warnings for run-pass. --- src/test/run-pass-fulldeps/deprecated-derive.rs | 1 + src/test/run-pass-fulldeps/lint-group-plugin.rs | 1 + src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs | 2 ++ src/test/run-pass-fulldeps/lint-plugin.rs | 1 + src/test/run-pass/attr-before-view-item.rs | 2 -- src/test/run-pass/attr-before-view-item2.rs | 2 -- src/test/run-pass/deriving-meta-empty-trait-list.rs | 1 + src/test/run-pass/enum-size-variance.rs | 8 ++++---- src/test/run-pass/issue-19100.rs | 4 ++++ src/test/run-pass/issue-25757.rs | 2 +- src/test/run-pass/issue-2611-3.rs | 1 - src/test/run-pass/issue-27320.rs | 3 +++ .../run-pass/liveness-assign-imm-local-after-ret.rs | 4 ++-- src/test/run-pass/unreachable-code-1.rs | 4 ++-- src/tools/compiletest/src/runtest.rs | 10 ++++++++-- 15 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/test/run-pass-fulldeps/deprecated-derive.rs b/src/test/run-pass-fulldeps/deprecated-derive.rs index 69a7f888bbe09..be2a45ca79abd 100644 --- a/src/test/run-pass-fulldeps/deprecated-derive.rs +++ b/src/test/run-pass-fulldeps/deprecated-derive.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(rustc_private)] +#![allow(dead_code)] extern crate serialize; diff --git a/src/test/run-pass-fulldeps/lint-group-plugin.rs b/src/test/run-pass-fulldeps/lint-group-plugin.rs index 1a639cdb9ddfa..21942b84bff9c 100644 --- a/src/test/run-pass-fulldeps/lint-group-plugin.rs +++ b/src/test/run-pass-fulldeps/lint-group-plugin.rs @@ -14,6 +14,7 @@ #![feature(plugin)] #![plugin(lint_group_plugin_test)] +#![allow(dead_code)] fn lintme() { } //~ WARNING item is named 'lintme' fn pleaselintme() { } //~ WARNING item is named 'pleaselintme' diff --git a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs index 1af26094f2315..2a6daa5040b71 100644 --- a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs +++ b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs @@ -13,6 +13,8 @@ // ignore-pretty: Random space appears with the pretty test // compile-flags: -Z extra-plugins=lint_plugin_test +#![allow(dead_code)] + fn lintme() { } //~ WARNING item is named 'lintme' #[allow(test_lint)] diff --git a/src/test/run-pass-fulldeps/lint-plugin.rs b/src/test/run-pass-fulldeps/lint-plugin.rs index 8311e188f9229..b694a1c332079 100644 --- a/src/test/run-pass-fulldeps/lint-plugin.rs +++ b/src/test/run-pass-fulldeps/lint-plugin.rs @@ -14,6 +14,7 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] +#![allow(dead_code)] fn lintme() { } //~ WARNING item is named 'lintme' diff --git a/src/test/run-pass/attr-before-view-item.rs b/src/test/run-pass/attr-before-view-item.rs index cdd1b96de1e60..2a86489c69aa5 100644 --- a/src/test/run-pass/attr-before-view-item.rs +++ b/src/test/run-pass/attr-before-view-item.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:expected item - // pretty-expanded FIXME #23616 #![feature(custom_attribute, test)] diff --git a/src/test/run-pass/attr-before-view-item2.rs b/src/test/run-pass/attr-before-view-item2.rs index cd02b5a9e7310..c8683f2d14751 100644 --- a/src/test/run-pass/attr-before-view-item2.rs +++ b/src/test/run-pass/attr-before-view-item2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:expected item - // pretty-expanded FIXME #23616 #![feature(custom_attribute, test)] diff --git a/src/test/run-pass/deriving-meta-empty-trait-list.rs b/src/test/run-pass/deriving-meta-empty-trait-list.rs index 5b55ef6333534..ff513325d5e68 100644 --- a/src/test/run-pass/deriving-meta-empty-trait-list.rs +++ b/src/test/run-pass/deriving-meta-empty-trait-list.rs @@ -10,6 +10,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(dead_code)] #[derive] //~ WARNING empty trait list in `derive` struct Foo; diff --git a/src/test/run-pass/enum-size-variance.rs b/src/test/run-pass/enum-size-variance.rs index 0bf5df5d61021..21996c5fabf1a 100644 --- a/src/test/run-pass/enum-size-variance.rs +++ b/src/test/run-pass/enum-size-variance.rs @@ -10,7 +10,7 @@ // // ignore-pretty -#![deny(enum_size_variance)] +#![warn(variant_size_differences)] #![allow(dead_code)] enum Enum1 { } @@ -21,8 +21,8 @@ enum Enum3 { D(isize), E, F } enum Enum4 { H(isize), I(isize), J } -enum Enum5 { //~ ERROR three times larger - L(isize, isize, isize, isize), //~ NOTE this variant is the largest +enum Enum5 { + L(isize, isize, isize, isize), //~ WARNING three times larger M(isize), N } @@ -33,7 +33,7 @@ enum Enum6 { Q(isize) } -#[allow(enum_size_variance)] +#[allow(variant_size_differences)] enum Enum7 { R(isize, isize, isize, isize), S(isize), diff --git a/src/test/run-pass/issue-19100.rs b/src/test/run-pass/issue-19100.rs index 0fd4b4394dc27..7ff9ae996f525 100644 --- a/src/test/run-pass/issue-19100.rs +++ b/src/test/run-pass/issue-19100.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(unused_variables)] + #[derive(Copy, Clone)] enum Foo { Bar, diff --git a/src/test/run-pass/issue-25757.rs b/src/test/run-pass/issue-25757.rs index 8deb2e244ae08..d1fb75377050d 100644 --- a/src/test/run-pass/issue-25757.rs +++ b/src/test/run-pass/issue-25757.rs @@ -22,6 +22,6 @@ const FUNC: &'static Fn(&mut Foo) -> () = &Foo::x; fn main() { let mut foo = Foo { a: 137 }; - FUNC(&mut foo); //~ ERROR bad + FUNC(&mut foo); assert_eq!(foo.a, 5); } diff --git a/src/test/run-pass/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs index 242528dcb1474..e223d3412e049 100644 --- a/src/test/run-pass/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -22,7 +22,6 @@ struct E { impl A for E { fn b(&self, _x: F) -> F { panic!() } - //~^ ERROR in method `b`, type parameter 0 has 1 bound, but } pub fn main() {} diff --git a/src/test/run-pass/issue-27320.rs b/src/test/run-pass/issue-27320.rs index dde1d3bfe9389..e010b162cc406 100644 --- a/src/test/run-pass/issue-27320.rs +++ b/src/test/run-pass/issue-27320.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_variables)] +#![allow(dead_code)] + macro_rules! piece( ($piece:pat) => ($piece); ); diff --git a/src/test/run-pass/liveness-assign-imm-local-after-ret.rs b/src/test/run-pass/liveness-assign-imm-local-after-ret.rs index 6fc15478f7a55..76b44832a8a16 100644 --- a/src/test/run-pass/liveness-assign-imm-local-after-ret.rs +++ b/src/test/run-pass/liveness-assign-imm-local-after-ret.rs @@ -10,13 +10,13 @@ // pretty-expanded FIXME #23616 -#![allow(unreachable_code)] +#![allow(dead_code)] fn test() { let _v: isize; _v = 1; return; - _v = 2; //~ WARNING: unreachable statement + _v = 2; } pub fn main() { diff --git a/src/test/run-pass/unreachable-code-1.rs b/src/test/run-pass/unreachable-code-1.rs index 189c5cdb9b747..6448056fb11f4 100644 --- a/src/test/run-pass/unreachable-code-1.rs +++ b/src/test/run-pass/unreachable-code-1.rs @@ -9,14 +9,14 @@ // except according to those terms. -#![allow(unreachable_code)] #![allow(unused_variables)] +#![allow(dead_code)] fn id(x: bool) -> bool { x } fn call_id() { let c = panic!(); - id(c); //~ WARNING unreachable statement + id(c); } fn call_id_3() { id(return) && id(return); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 0d081b267bb70..60a0d8f0b865f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -197,6 +197,11 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("compilation failed!", &proc_res); } + let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); + if !expected_errors.is_empty() { + self.check_expected_errors(expected_errors, &proc_res); + } + let proc_res = self.exec_compiled_test(); if !proc_res.status.success() { @@ -992,7 +997,8 @@ actual:\n\ fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { - if proc_res.status.success() { + if proc_res.status.success() && + expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error)) { self.fatal_proc_rec("process did not return an error status", proc_res); } @@ -1320,6 +1326,7 @@ actual:\n\ match self.config.mode { CompileFail | ParseFail | + RunPass | Incremental => { // If we are extracting and matching errors in the new // fashion, then you want JSON mode. Old-skool error @@ -1350,7 +1357,6 @@ actual:\n\ args.push(dir_opt); } RunFail | - RunPass | RunPassValgrind | Pretty | DebugInfoGdb | From 144cc7285f44fca41fc5c336e0942acadac1019d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Aug 2016 19:32:54 +0000 Subject: [PATCH 214/768] Update cargo bootstrap rev and add fix for cargo#3005 --- src/bootstrap/Cargo.lock | 21 +++++++++++++++++++++ src/bootstrap/lib.rs | 4 ++++ src/rustc/Cargo.lock | 2 ++ src/rustc/std_shim/Cargo.lock | 2 ++ src/stage0.txt | 2 +- src/tools/compiletest/Cargo.lock | 10 ++++++++++ src/tools/linkchecker/Cargo.lock | 6 ++++++ 7 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index d52577eb228e2..36b94e4ebea32 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -157,3 +157,24 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[metadata] +"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" +"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978" +"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" +"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "" +"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07" +"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0" +"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09" +"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2" +"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199" +"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" +"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0af6082aee4f7..b40dbfde4a4a5 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -543,6 +543,10 @@ impl Build { .arg("-j").arg(self.jobs().to_string()) .arg("--target").arg(target); + // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005 + // Force cargo to output binaries with disambiguating hashes in the name + cargo.env("__CARGO_DEFAULT_LIB_METADATA", "1"); + let stage; if compiler.stage == 0 && self.local_rebuild { // Assume the local-rebuild rustc already has stage1 features. diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 4f78519e13aa8..c0db651d7d2b4 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -410,3 +410,5 @@ dependencies = [ "serialize 0.0.0", ] +[metadata] +"checksum gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3da3a2cbaeb01363c8e3704fd9fd0eb2ceb17c6f27abd4c1ef040fb57d20dc79" diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index 70aef55d799c1..d47b541b4c3bc 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -118,3 +118,5 @@ dependencies = [ "libc 0.0.0", ] +[metadata] +"checksum gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "806e63121fbf30760b060a5fc2d1e9f47e1bd356d183e8870367c6c12cc9d5ed" diff --git a/src/stage0.txt b/src/stage0.txt index 8c7961cc8497b..f9cf819dc9487 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -14,4 +14,4 @@ rustc: beta-2016-08-17 rustc_key: 195e6261 -cargo: nightly-2016-08-16 +cargo: nightly-2016-08-21 diff --git a/src/tools/compiletest/Cargo.lock b/src/tools/compiletest/Cargo.lock index 24c8b20fdf8d7..755697806a00e 100644 --- a/src/tools/compiletest/Cargo.lock +++ b/src/tools/compiletest/Cargo.lock @@ -80,3 +80,13 @@ name = "utf8-ranges" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[metadata] +"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03" +"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5" +"checksum libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca44454e7cfe7f8a2095a41a10c79d96a177c0b1672cbf1a30d901a9c16ee5" +"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum mempool 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f997e65fe3eb7a6f8557a7a477de9ed5c511850c85363d13f7b0145b526ed36a" +"checksum regex 0.1.62 (registry+https://github.com/rust-lang/crates.io-index)" = "22bdab319e36735729aa280752c9293b29ec0053a6810679d697515f80a986fe" +"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" diff --git a/src/tools/linkchecker/Cargo.lock b/src/tools/linkchecker/Cargo.lock index ed5fe081ffb2e..d71df6d3f83a8 100644 --- a/src/tools/linkchecker/Cargo.lock +++ b/src/tools/linkchecker/Cargo.lock @@ -42,3 +42,9 @@ dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[metadata] +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" +"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" +"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" +"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119" From 0f9cb1b97cbb10eb400768c8e6a3851c93515470 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 23 Aug 2016 02:05:53 +0200 Subject: [PATCH 215/768] Change a weird line break in `core::str` --- src/libcore/str/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index fdcadd43a0fb6..c085c8103fa27 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -388,8 +388,9 @@ pub fn next_code_point<'a, I: Iterator>(bytes: &mut I) -> Option< /// Reads the last code point out of a byte iterator (assuming a /// UTF-8-like encoding). #[inline] -fn next_code_point_reverse<'a, - I: DoubleEndedIterator>(bytes: &mut I) -> Option { +fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option + where I: DoubleEndedIterator, +{ // Decode UTF-8 let w = match bytes.next_back() { None => return None, From f39700514dfdc9ebe76e214967ed3fe9971578af Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 13 Aug 2016 16:52:41 -0700 Subject: [PATCH 216/768] Update E0389 to the new format. #35630 --- src/librustc_borrowck/borrowck/mod.rs | 6 ++++-- src/test/compile-fail/E0389.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index fd5db97b5d8bc..3ddb551603c27 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -919,9 +919,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { "{} in a static location", prefix) } mc::AliasableBorrowed => { - struct_span_err!( + let mut e = struct_span_err!( self.tcx.sess, span, E0389, - "{} in a `&` reference", prefix) + "{} in a `&` reference", prefix); + e.span_label(span, &"assignment into an immutable reference"); + e } }; diff --git a/src/test/compile-fail/E0389.rs b/src/test/compile-fail/E0389.rs index 445831bf8d7f7..584dfd5fa440c 100644 --- a/src/test/compile-fail/E0389.rs +++ b/src/test/compile-fail/E0389.rs @@ -16,5 +16,6 @@ fn main() { let mut fancy = FancyNum{ num: 5 }; let fancy_ref = &(&mut fancy); fancy_ref.num = 6; //~ ERROR E0389 + //~^ NOTE assignment into an immutable reference println!("{}", fancy_ref.num); } From 5e22e3025ce0079ff54f17ebe99e9d00a34a8cf6 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 23 Aug 2016 02:07:50 +0200 Subject: [PATCH 217/768] Implement more traits for `std::io::ErrorKind` This makes it possible to use it as key in various maps. --- src/libstd/io/error.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 5333b0a531eae..aa6ec75e3fc0c 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -83,7 +83,7 @@ struct Custom { /// It is used with the [`io::Error`] type. /// /// [`io::Error`]: struct.Error.html -#[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub enum ErrorKind { @@ -152,10 +152,6 @@ pub enum ErrorKind { /// Interrupted operations can typically be retried. #[stable(feature = "rust1", since = "1.0.0")] Interrupted, - /// Any I/O error not part of this list. - #[stable(feature = "rust1", since = "1.0.0")] - Other, - /// An error returned when an operation could not be completed because an /// "end of file" was reached prematurely. /// @@ -164,8 +160,12 @@ pub enum ErrorKind { /// read. #[stable(feature = "read_exact", since = "1.6.0")] UnexpectedEof, - /// Any I/O error not part of this list. + #[stable(feature = "rust1", since = "1.0.0")] + Other, + + /// A marker variant that tells the compiler that users of this enum cannot + /// match it exhaustively. #[unstable(feature = "io_error_internals", reason = "better expressed through extensible enums that this \ enum cannot be exhaustively matched against", From f863ea3d16fe0362249bd2f130a0b64022ca1b10 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 23 Aug 2016 00:38:26 +0000 Subject: [PATCH 218/768] Update rust-installer. Fixes #35840 --- src/rust-installer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust-installer b/src/rust-installer index c37d3747da75c..755bc3db4ff79 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit c37d3747da75c280237dc2d6b925078e69555499 +Subproject commit 755bc3db4ff795865ea31b5b4f38ac920d8acacb From 66a2578064c2572a355f87f2405859a1c347b590 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 22 Aug 2016 20:39:20 -0400 Subject: [PATCH 219/768] Mark panicking tests as `should_panic` instead of `no_run`. --- src/doc/book/macros.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/macros.md b/src/doc/book/macros.md index 9f40829f4233f..78fe07ec1be16 100644 --- a/src/doc/book/macros.md +++ b/src/doc/book/macros.md @@ -662,7 +662,7 @@ Here are some common macros you’ll see in Rust code. This macro causes the current thread to panic. You can give it a message to panic with: -```rust,no_run +```rust,should_panic panic!("oh no!"); ``` @@ -688,7 +688,7 @@ These two macros are used in tests. `assert!` takes a boolean. `assert_eq!` takes two values and checks them for equality. `true` passes, `false` `panic!`s. Like this: -```rust,no_run +```rust,should_panic // A-ok! assert!(true); From cfce351ad39ae0f5e35006ad11fabb4ec866d725 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 07:40:51 +0200 Subject: [PATCH 220/768] first attempt at implementing RFC 1623. This fixes #35897. This is a work in progress. In particular, I want to add more tests, especially the compile-fail test is very bare-bones. --- src/librustc_typeck/collect.rs | 2 +- src/test/compile-fail/rfc1623.rs | 21 +++++++++++++ src/test/run-pass/rfc1623.rs | 52 ++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/rfc1623.rs create mode 100644 src/test/run-pass/rfc1623.rs diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7e1fb32881d6f..0f48b7ca67e63 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1554,7 +1554,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, _, _) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&ExplicitRscope, &t) + ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs new file mode 100644 index 0000000000000..dfe58f0d94cc0 --- /dev/null +++ b/src/test/compile-fail/rfc1623.rs @@ -0,0 +1,21 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } + +// the boundaries of elision +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = non_elidable; +//~^ERROR: missing lifetime specifier + +fn main() { + // nothing to do here +} diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs new file mode 100644 index 0000000000000..b702a03b481f7 --- /dev/null +++ b/src/test/run-pass/rfc1623.rs @@ -0,0 +1,52 @@ +// 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. + +#![allow(dead_code)] + +// very simple test for a 'static static with default lifetime +static SOME_STATIC_STR : &str = "&'static str"; +const SOME_CONST_STR : &str = "&'static str"; + +// this should be the same as without default: +static SOME_EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const SOME_EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; +const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; + +// this should be the same as without elision +static SOME_STATIC_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; +const SOME_CONST_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; +const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; + + +fn main() { + // make sure that the lifetime is actually elided (and not defaulted) + let x = &[1u8, 2, 3]; + SOME_STATIC_SIMPLE_FN(x); + SOME_CONST_SIMPLE_FN(x); + + // make sure this works with different lifetimes + let a = &1; + { + let b = &2; + let c = &3; + SOME_CONST_MULTI_FN(a, b, c); + } +} From 6b95606a136bad2109253e5e32cc13b7ecbbc49e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 23 Aug 2016 09:07:23 +0300 Subject: [PATCH 221/768] rustc_trans: do not generate allocas for unused locals. --- src/librustc_trans/mir/analyze.rs | 6 ++++++ src/test/run-pass/mir_heavy_promoted.rs | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/run-pass/mir_heavy_promoted.rs diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index e0d959f4774a6..66eb78aef07b4 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -48,6 +48,12 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, common::type_is_fat_ptr(bcx.tcx(), ty)); } else if common::type_is_imm_pair(bcx.ccx(), ty) { // We allow pairs and uses of any of their 2 fields. + } else if !analyzer.seen_assigned.contains(index) { + // No assignment has been seen, which means that + // either the local has been marked as lvalue + // already, or there is no possible initialization + // for the local, making any reads invalid. + // This is useful in weeding out dead temps. } else { // These sorts of types require an alloca. Note that // type_is_immediate() may *still* be true, particularly diff --git a/src/test/run-pass/mir_heavy_promoted.rs b/src/test/run-pass/mir_heavy_promoted.rs new file mode 100644 index 0000000000000..9e033421574b9 --- /dev/null +++ b/src/test/run-pass/mir_heavy_promoted.rs @@ -0,0 +1,18 @@ +// 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. + +const TEST_DATA: [u8; 32 * 1024 * 1024] = [42; 32 * 1024 * 1024]; + +// Check that the promoted copy of TEST_DATA doesn't +// leave an alloca from an unused temp behind, which, +// without optimizations, can still blow the stack. +fn main() { + println!("{}", TEST_DATA.len()); +} From 72d629caa50fa482dd4165cb43b9fb02ac24c8d8 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 23 Aug 2016 18:23:31 +1200 Subject: [PATCH 222/768] Improve error message when failing to parse a block We want to catch this error: ``` if (foo) bar; ``` as it's valid syntax in other languages, and say how to fix it. Unfortunately it didn't care if the suggestion made sense and just highlighted the unexpected token. Now it attempts to parse a statement, and if it succeeds, it shows the help message. Fixes #35907 --- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++++--- src/test/compile-fail/missing-block-hint.rs | 20 +++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/missing-block-hint.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9443df6321bd0..1646246069ead 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4087,9 +4087,30 @@ impl<'a> Parser<'a> { if !self.eat(&token::OpenDelim(token::Brace)) { let sp = self.span; let tok = self.this_token_to_string(); - return Err(self.span_fatal_help(sp, - &format!("expected `{{`, found `{}`", tok), - "place this code inside a block")); + let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok)); + + // Check to see if the user has written something like + // + // if (cond) + // bar; + // + // Which is valid in other languages, but not Rust. + match self.parse_stmt_without_recovery(false) { + Ok(Some(stmt)) => { + let mut stmt_span = stmt.span; + // expand the span to include the semicolon, if it exists + if self.eat(&token::Semi) { + stmt_span.hi = self.last_span.hi; + } + e.span_help(stmt_span, "try placing this code inside a block"); + } + Err(mut e) => { + self.recover_stmt_(SemiColonMode::Break); + e.cancel(); + } + _ => () + } + return Err(e); } self.parse_block_tail(lo, BlockCheckMode::Default) diff --git a/src/test/compile-fail/missing-block-hint.rs b/src/test/compile-fail/missing-block-hint.rs new file mode 100644 index 0000000000000..1f29ff4e05c09 --- /dev/null +++ b/src/test/compile-fail/missing-block-hint.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + { + if (foo) => {} //~ ERROR expected `{`, found `=>` + } + { + if (foo) + bar; //~ ERROR expected `{`, found `bar` + //^ HELP try placing this code inside a block + } +} From 8bdb3e10ca637033667dec25ebfff64a069c46eb Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 12:34:28 +0200 Subject: [PATCH 223/768] fix run-pass test --- src/test/run-pass/rfc1623.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index b702a03b481f7..81e32efe6c775 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -22,18 +22,24 @@ const SOME_EXPLICIT_CONST_STR : &'static str = "&'static str"; fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } // one with a function, argument elided -static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; -const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; +static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static SOME_STATIC_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; -const SOME_CONST_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; +static SOME_STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const SOME_CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime fn multi_args(a: &u8, b: &u8, c: &u8) { } -static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; -const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; +static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); fn main() { @@ -41,7 +47,7 @@ fn main() { let x = &[1u8, 2, 3]; SOME_STATIC_SIMPLE_FN(x); SOME_CONST_SIMPLE_FN(x); - + // make sure this works with different lifetimes let a = &1; { From a6b9fea5cd10afe9d7b81d30b2b082f727aea255 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 12:38:09 +0200 Subject: [PATCH 224/768] fixed compile-fail test --- src/test/compile-fail/rfc1623.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index dfe58f0d94cc0..a52b9c596aa9a 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -13,8 +13,9 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } // the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = non_elidable; +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = //~^ERROR: missing lifetime specifier + &(non_elidable as fn(&u8, &u8) -> &u8); fn main() { // nothing to do here From 226e1e5ded651f18a9fef8e5865a6f4f0db0d051 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 07:40:53 -0400 Subject: [PATCH 225/768] add regression test for #35593 Fixes #35593 --- src/test/incremental/issue-35593.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/incremental/issue-35593.rs diff --git a/src/test/incremental/issue-35593.rs b/src/test/incremental/issue-35593.rs new file mode 100644 index 0000000000000..51e04dd7b2ce0 --- /dev/null +++ b/src/test/incremental/issue-35593.rs @@ -0,0 +1,21 @@ +// 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. + +// Regression test for #35593. Check that we can reuse this trivially +// equal example. + +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] +#![rustc_partition_reused(module="issue_35593", cfg="rpass2")] + +fn main() { + println!("hello world"); +} From 484da378452ed123919ee6d4d5a7e4e98c5d4060 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 07:47:14 -0400 Subject: [PATCH 226/768] rename HashesMap to IncrementalHashesMap --- src/librustc_driver/driver.rs | 30 +++++++++---------- src/librustc_incremental/calculate_svh/mod.rs | 7 +++-- src/librustc_incremental/lib.rs | 4 +-- src/librustc_incremental/persist/hash.rs | 12 ++++---- src/librustc_incremental/persist/load.rs | 21 +++++++------ src/librustc_incremental/persist/save.rs | 7 +++-- src/librustc_trans/back/link.rs | 6 ++-- src/librustc_trans/base.rs | 6 ++-- 8 files changed, 50 insertions(+), 43 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 825a84d075bb5..b99a3b4ba2eee 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -26,7 +26,7 @@ use rustc::util::common::time; use rustc::util::nodemap::NodeSet; use rustc_back::sha2::{Sha256, Digest}; use rustc_borrowck as borrowck; -use rustc_incremental::{self, HashesMap}; +use rustc_incremental::{self, IncrementalHashesMap}; use rustc_resolve::{MakeGlobMap, Resolver}; use rustc_metadata::macro_import; use rustc_metadata::creader::read_local_crates; @@ -172,7 +172,7 @@ pub fn compile_input(sess: &Session, resolutions, &arenas, &crate_name, - |tcx, mir_map, analysis, hashes_map, result| { + |tcx, mir_map, analysis, incremental_hashes_map, result| { { // Eventually, we will want to track plugins. let _ignore = tcx.dep_graph.in_ignore(); @@ -203,7 +203,7 @@ pub fn compile_input(sess: &Session, let trans = phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis, - &hashes_map); + &incremental_hashes_map); if log_enabled!(::log::INFO) { println!("Post-trans"); @@ -798,7 +798,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, Option>, ty::CrateAnalysis, - HashesMap, + IncrementalHashesMap, CompileResult) -> R { macro_rules! try_with_f { @@ -862,16 +862,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, index, name, |tcx| { - let hashes_map = + let incremental_hashes_map = time(time_passes, - "compute_hashes_map", - || rustc_incremental::compute_hashes_map(tcx)); + "compute_incremental_hashes_map", + || rustc_incremental::compute_incremental_hashes_map(tcx)); time(time_passes, "load_dep_graph", - || rustc_incremental::load_dep_graph(tcx, &hashes_map)); + || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map)); // passes are timed inside typeck - try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis, hashes_map)); + try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis, incremental_hashes_map)); time(time_passes, "const checking", @@ -941,7 +941,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis if sess.err_count() > 0 { - return Ok(f(tcx, Some(mir_map), analysis, hashes_map, Err(sess.err_count()))); + return Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Err(sess.err_count()))); } analysis.reachable = @@ -969,10 +969,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // The above three passes generate errors w/o aborting if sess.err_count() > 0 { - return Ok(f(tcx, Some(mir_map), analysis, hashes_map, Err(sess.err_count()))); + return Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Err(sess.err_count()))); } - Ok(f(tcx, Some(mir_map), analysis, hashes_map, Ok(()))) + Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Ok(()))) }) } @@ -980,7 +980,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mut mir_map: MirMap<'tcx>, analysis: ty::CrateAnalysis, - hashes_map: &HashesMap) + incremental_hashes_map: &IncrementalHashesMap) -> trans::CrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -1014,7 +1014,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let translation = time(time_passes, "translation", - move || trans::trans_crate(tcx, &mir_map, analysis, &hashes_map)); + move || trans::trans_crate(tcx, &mir_map, analysis, &incremental_hashes_map)); time(time_passes, "assert dep graph", @@ -1022,7 +1022,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(time_passes, "serialize dep graph", - move || rustc_incremental::save_dep_graph(tcx, &hashes_map)); + move || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map)); translation } diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 7b1b0ce4cf14d..d41d718be6314 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -41,9 +41,10 @@ use self::svh_visitor::StrictVersionHashVisitor; mod svh_visitor; -pub type HashesMap = FnvHashMap, u64>; +pub type IncrementalHashesMap = FnvHashMap, u64>; -pub fn compute_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> HashesMap { +pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> IncrementalHashesMap { let _ignore = tcx.dep_graph.in_ignore(); let krate = tcx.map.krate(); let mut visitor = HashItemsVisitor { tcx: tcx, hashes: FnvHashMap() }; @@ -55,7 +56,7 @@ pub fn compute_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> HashesMa struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: HashesMap, + hashes: IncrementalHashesMap, } impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index b9c56c45386c4..d31d97b22cf4f 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -38,8 +38,8 @@ mod calculate_svh; mod persist; pub use assert_dep_graph::assert_dep_graph; -pub use calculate_svh::compute_hashes_map; -pub use calculate_svh::HashesMap; +pub use calculate_svh::compute_incremental_hashes_map; +pub use calculate_svh::IncrementalHashesMap; pub use persist::load_dep_graph; pub use persist::save_dep_graph; pub use persist::save_trans_partition; diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 49ad6c36804e2..12dacf273b962 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -20,22 +20,24 @@ use std::io::{ErrorKind, Read}; use std::fs::File; use syntax::ast; -use HashesMap; +use IncrementalHashesMap; use super::data::*; use super::util::*; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes_map: &'a HashesMap, + incremental_hashes_map: &'a IncrementalHashesMap, item_metadata_hashes: FnvHashMap, crate_hashes: FnvHashMap, } impl<'a, 'tcx> HashContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, hashes_map: &'a HashesMap) -> Self { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + incremental_hashes_map: &'a IncrementalHashesMap) + -> Self { HashContext { tcx: tcx, - hashes_map: hashes_map, + incremental_hashes_map: incremental_hashes_map, item_metadata_hashes: FnvHashMap(), crate_hashes: FnvHashMap(), } @@ -63,7 +65,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { def_id, self.tcx.item_path_str(def_id)); - Some((def_id, self.hashes_map[dep_node])) + Some((def_id, self.incremental_hashes_map[dep_node])) } // MetaData from other crates is an *input* to us. diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index a2ba566f75e0e..7449205c536fa 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -22,7 +22,7 @@ use std::io::Read; use std::fs::{self, File}; use std::path::{Path}; -use HashesMap; +use IncrementalHashesMap; use super::data::*; use super::directory::*; use super::dirty_clean; @@ -40,17 +40,17 @@ type CleanEdges = Vec<(DepNode, DepNode)>; /// actually it doesn't matter all that much.) See `README.md` for /// more general overview. pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: &HashesMap) { + incremental_hashes_map: &IncrementalHashesMap) { if tcx.sess.opts.incremental.is_none() { return; } let _ignore = tcx.dep_graph.in_ignore(); - load_dep_graph_if_exists(tcx, hashes); + load_dep_graph_if_exists(tcx, incremental_hashes_map); } fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: &HashesMap) { + incremental_hashes_map: &IncrementalHashesMap) { let dep_graph_path = dep_graph_path(tcx).unwrap(); let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) { Some(p) => p, @@ -63,7 +63,7 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, None => return // no file }; - match decode_dep_graph(tcx, hashes, &dep_graph_data, &work_products_data) { + match decode_dep_graph(tcx, incremental_hashes_map, &dep_graph_data, &work_products_data) { Ok(dirty_nodes) => dirty_nodes, Err(err) => { tcx.sess.warn( @@ -100,7 +100,7 @@ fn load_data(sess: &Session, path: &Path) -> Option> { /// Decode the dep graph and load the edges/nodes that are still clean /// into `tcx.dep_graph`. pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: &HashesMap, + incremental_hashes_map: &IncrementalHashesMap, dep_graph_data: &[u8], work_products_data: &[u8]) -> Result<(), Error> @@ -137,7 +137,10 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // reason for this is that this way we can include nodes that have // been removed (which no longer have a `DefId` in the current // compilation). - let dirty_raw_source_nodes = dirty_nodes(tcx, hashes, &serialized_dep_graph.hashes, &retraced); + let dirty_raw_source_nodes = dirty_nodes(tcx, + incremental_hashes_map, + &serialized_dep_graph.hashes, + &retraced); // Create a list of (raw-source-node -> // retracted-target-node) edges. In the process of retracing the @@ -210,11 +213,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Computes which of the original set of def-ids are dirty. Stored in /// a bit vector where the index is the DefPathIndex. fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: &HashesMap, + incremental_hashes_map: &IncrementalHashesMap, serialized_hashes: &[SerializedHash], retraced: &RetracedDefIdDirectory) -> DirtyNodes { - let mut hcx = HashContext::new(tcx, hashes); + let mut hcx = HashContext::new(tcx, incremental_hashes_map); let mut dirty_nodes = FnvHashSet(); for hash in serialized_hashes { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index b81afe44f60e7..74ee876d0bbc5 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -21,21 +21,22 @@ use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; -use HashesMap; +use IncrementalHashesMap; use super::data::*; use super::directory::*; use super::hash::*; use super::preds::*; use super::util::*; -pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hashes_map: &HashesMap) { +pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + incremental_hashes_map: &IncrementalHashesMap) { debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); let sess = tcx.sess; if sess.opts.incremental.is_none() { return; } - let mut hcx = HashContext::new(tcx, hashes_map); + let mut hcx = HashContext::new(tcx, incremental_hashes_map); let mut builder = DefIdDirectoryBuilder::new(tcx); let query = tcx.dep_graph.query(); let preds = Predecessors::new(&query, &mut hcx); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index d47a5ddb22456..9f401b13d6f97 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -28,7 +28,7 @@ use util::fs::fix_windows_verbatim_for_gcc; use rustc::dep_graph::DepNode; use rustc::hir::svh::Svh; use rustc_back::tempdir::TempDir; -use rustc_incremental::HashesMap; +use rustc_incremental::IncrementalHashesMap; use std::ascii; use std::char; @@ -125,12 +125,12 @@ pub fn find_crate_name(sess: Option<&Session>, } -pub fn build_link_meta(hashes_map: &HashesMap, +pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap, name: &str) -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: Svh::new(hashes_map[&DepNode::Krate]), + crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate]), }; info!("{:?}", r); return r; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f2d0bbae942d2..cab353cd26209 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -48,7 +48,7 @@ use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::mir::mir_map::MirMap; use rustc_data_structures::graph::OUTGOING; -use rustc_incremental::HashesMap; +use rustc_incremental::IncrementalHashesMap; use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; use _match; @@ -2483,7 +2483,7 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &MirMap<'tcx>, analysis: ty::CrateAnalysis, - hashes_map: &HashesMap) + incremental_hashes_map: &IncrementalHashesMap) -> CrateTranslation { let _task = tcx.dep_graph.in_task(DepNode::TransCrate); @@ -2508,7 +2508,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.sess.opts.debug_assertions }; - let link_meta = link::build_link_meta(hashes_map, name); + let link_meta = link::build_link_meta(incremental_hashes_map, name); let shared_ccx = SharedCrateContext::new(tcx, &mir_map, From f9230833084118e31b6dd40cccdd7a8b42c8f236 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 07:56:34 -0400 Subject: [PATCH 227/768] cache def-path hashes across all items This seems like approx a 2x win on syntex_syntax. --- src/librustc_incremental/calculate_svh/mod.rs | 10 ++++++++-- .../calculate_svh/svh_visitor.rs | 17 +++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index d41d718be6314..066d6dd05a38e 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,6 +35,7 @@ use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; +use rustc::util::nodemap::DefIdMap; use rustc_data_structures::fnv::FnvHashMap; use self::svh_visitor::StrictVersionHashVisitor; @@ -47,7 +48,9 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IncrementalHashesMap { let _ignore = tcx.dep_graph.in_ignore(); let krate = tcx.map.krate(); - let mut visitor = HashItemsVisitor { tcx: tcx, hashes: FnvHashMap() }; + let mut visitor = HashItemsVisitor { tcx: tcx, + hashes: FnvHashMap(), + def_path_hashes: DefIdMap() }; visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); krate.visit_all_items(&mut visitor); visitor.compute_crate_hash(); @@ -56,6 +59,7 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_path_hashes: DefIdMap, hashes: IncrementalHashesMap, } @@ -75,7 +79,9 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // FIXME: this should use SHA1, not SipHash. SipHash is not // built to avoid collisions. let mut state = SipHasher::new(); - walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx)); + walk_op(&mut StrictVersionHashVisitor::new(&mut state, + self.tcx, + &mut self.def_path_hashes)); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 1e00e0fc56260..30c7a04fd7fb3 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -35,23 +35,24 @@ pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> { pub st: &'a mut SipHasher, // collect a deterministic hash of def-ids that we have seen - def_id_hashes: DefIdMap, + def_path_hashes: &'a mut DefIdMap, } impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { pub fn new(st: &'a mut SipHasher, - tcx: TyCtxt<'a, 'tcx, 'tcx>) + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_path_hashes: &'a mut DefIdMap) -> Self { - StrictVersionHashVisitor { st: st, tcx: tcx, def_id_hashes: DefIdMap() } + StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes } } fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { let tcx = self.tcx; - *self.def_id_hashes.entry(def_id) - .or_insert_with(|| { - let def_path = tcx.def_path(def_id); - def_path.deterministic_hash(tcx) - }) + *self.def_path_hashes.entry(def_id) + .or_insert_with(|| { + let def_path = tcx.def_path(def_id); + def_path.deterministic_hash(tcx) + }) } } From c42e0a34519d44ef0424574093999126fae1d13f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 10:42:46 -0400 Subject: [PATCH 228/768] make svh independent of item ordering --- .../calculate_svh/def_path_hash.rs | 36 +++++++++++++++++++ src/librustc_incremental/calculate_svh/mod.rs | 34 +++++++++++------- .../calculate_svh/svh_visitor.rs | 26 ++++++-------- 3 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 src/librustc_incremental/calculate_svh/def_path_hash.rs diff --git a/src/librustc_incremental/calculate_svh/def_path_hash.rs b/src/librustc_incremental/calculate_svh/def_path_hash.rs new file mode 100644 index 0000000000000..8aa134ba3bfd0 --- /dev/null +++ b/src/librustc_incremental/calculate_svh/def_path_hash.rs @@ -0,0 +1,36 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::def_id::DefId; +use rustc::ty::TyCtxt; +use rustc::util::nodemap::DefIdMap; + +pub struct DefPathHashes<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + data: DefIdMap, +} + +impl<'a, 'tcx> DefPathHashes<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + DefPathHashes { + tcx: tcx, + data: DefIdMap() + } + } + + pub fn hash(&mut self, def_id: DefId) -> u64 { + let tcx = self.tcx; + *self.data.entry(def_id) + .or_insert_with(|| { + let def_path = tcx.def_path(def_id); + def_path.deterministic_hash(tcx) + }) + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 066d6dd05a38e..42bb1a5246738 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,11 +35,12 @@ use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; -use rustc::util::nodemap::DefIdMap; use rustc_data_structures::fnv::FnvHashMap; +use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; +mod def_path_hash; mod svh_visitor; pub type IncrementalHashesMap = FnvHashMap, u64>; @@ -50,7 +51,7 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) let krate = tcx.map.krate(); let mut visitor = HashItemsVisitor { tcx: tcx, hashes: FnvHashMap(), - def_path_hashes: DefIdMap() }; + def_path_hashes: DefPathHashes::new(tcx) }; visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); krate.visit_all_items(&mut visitor); visitor.compute_crate_hash(); @@ -59,20 +60,20 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefIdMap, + def_path_hashes: DefPathHashes<'a, 'tcx>, hashes: IncrementalHashesMap, } impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { fn calculate_node_id(&mut self, id: ast::NodeId, walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'tcx>) + where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) { let def_id = self.tcx.map.local_def_id(id); self.calculate_def_id(def_id, walk_op) } fn calculate_def_id(&mut self, def_id: DefId, mut walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'tcx>) + where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) { assert!(def_id.is_local()); debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); @@ -99,15 +100,22 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // add each item (in some deterministic order) to the overall // crate hash. - // - // FIXME -- it'd be better to sort by the hash of the def-path, - // so that reordering items would not affect the crate hash. { - let mut keys: Vec<_> = self.hashes.keys().collect(); - keys.sort(); - for key in keys { - self.hashes[key].hash(&mut crate_state); - } + let def_path_hashes = &mut self.def_path_hashes; + let mut item_hashes: Vec<_> = + self.hashes.iter() + .map(|(item_dep_node, &item_hash)| { + // convert from a DepNode tp a + // DepNode where the u64 is the + // hash of the def-id's def-path: + let item_dep_node = + item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did))) + .unwrap(); + (item_dep_node, item_hash) + }) + .collect(); + item_hashes.sort(); // avoid artificial dependencies on item ordering + item_hashes.hash(&mut crate_state); } for attr in &krate.attrs { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 30c7a04fd7fb3..c1158dc2d5fe9 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -26,33 +26,29 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, FnKind}; use rustc::ty::TyCtxt; -use rustc::util::nodemap::DefIdMap; use std::hash::{Hash, SipHasher}; -pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, +use super::def_path_hash::DefPathHashes; + +pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { + pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, pub st: &'a mut SipHasher, // collect a deterministic hash of def-ids that we have seen - def_path_hashes: &'a mut DefIdMap, + def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, } -impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { +impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { pub fn new(st: &'a mut SipHasher, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefIdMap) + tcx: TyCtxt<'hash, 'tcx, 'tcx>, + def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>) -> Self { StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes } } fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { - let tcx = self.tcx; - *self.def_path_hashes.entry(def_id) - .or_insert_with(|| { - let def_path = tcx.def_path(def_id); - def_path.deterministic_hash(tcx) - }) + self.def_path_hashes.hash(def_id) } } @@ -196,7 +192,7 @@ pub enum SawStmtComponent { SawStmtSemi, } -impl<'a, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'tcx> { +impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn visit_nested_item(&mut self, _: ItemId) { // Each item is hashed independently; ignore nested items. } @@ -370,7 +366,7 @@ pub enum DefHash { SawErr, } -impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { +impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn hash_resolve(&mut self, id: ast::NodeId) { // Because whether or not a given id has an entry is dependent // solely on expr variant etc, we don't need to hash whether From c7d5f7e5e638775e45c4fdc64f3b91bdbfca9c28 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 23 Aug 2016 10:47:28 -0400 Subject: [PATCH 229/768] Rust has type aliases, not typedefs. They're the same thing but it's better to keep the terminology consistent. --- src/libcollections/fmt.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index a1b4461949c6e..beb3e6b3d4e31 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -165,15 +165,15 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is `fmt::Result` which is a -//! typedef to `Result<(), std::fmt::Error>`. Formatting implementations should -//! ensure that they propagate errors from the `Formatter` (e.g., when calling -//! `write!`) however, they should never return errors spuriously. That is, a -//! formatting implementation must and may only return an error if the passed-in -//! `Formatter` returns an error. This is because, contrary to what the function -//! signature might suggest, string formatting is an infallible operation. -//! This function only returns a result because writing to the underlying stream -//! might fail and it must provide a way to propagate the fact that an error has -//! occurred back up the stack. +//! type alias of `Result<(), std::fmt::Error>`. Formatting implementations +//! should ensure that they propagate errors from the `Formatter` (e.g., when +//! calling `write!`) however, they should never return errors spuriously. That +//! is, a formatting implementation must and may only return an error if the +//! passed-in `Formatter` returns an error. This is because, contrary to what +//! the function signature might suggest, string formatting is an infallible +//! operation. This function only returns a result because writing to the +//! underlying stream might fail and it must provide a way to propagate the fact +//! that an error has occurred back up the stack. //! //! An example of implementing the formatting traits would look //! like: From 67b9cd3fe136247e928d11daa12749d0488464c9 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 17:46:34 -0400 Subject: [PATCH 230/768] improve documentation for `Fn*` traits I can think of a few things we may want to accomplish with the documentation of the `Fn`, `FnMut`, and `FnOnce` traits: - the relationship between these traits and the closures that implement them - examples of non-closure implementations - the relationship between these traits and Rust's ownership semantics add module-level documentation for `Fn*` traits Describe how `Fn*` traits, closure types, and ownership semantics are linked, and provide examples of higher-level functions that take `Fn*`s. more examples for `Fn*` traits create correct (though not yet elegant) examples for `FnMut` and `FnOnce` add trait links to module-level documentation third time's a charm! argument -> capture for trait documentation This wording will need to be supported with better examples for capturing eventually. correct `FnOnce` example I also fixed some of the trait wording here to make the concept of capturing clearer; though that still needs more work. replace `x + x` with `x * 2` for `fn double` --- src/libcore/ops.rs | 165 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 5a1993e741c60..a8a557ce68111 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -68,6 +68,73 @@ //! ``` //! //! See the documentation for each trait for an example implementation. +//! +//! The [`Fn`], [`FnMut`], and [`FnOnce`] traits are implemented by types that can be +//! invoked like functions. Note that `Fn` takes `&self`, `FnMut` takes `&mut +//! self` and `FnOnce` takes `self`. These correspond to the three kinds of +//! methods that can be invoked on an instance: call-by-reference, +//! call-by-mutable-reference, and call-by-value. The most common use of these +//! traits is to act as bounds to higher-level functions that take functions or +//! closures as arguments. +//! +//! [`Fn`]: trait.Fn.html +//! [`FnMut`]: trait.FnMut.html +//! [`FnOnce`]: trait.FnOnce.html +//! +//! Taking a `Fn` as a parameter: +//! +//! ```rust +//! fn call_with_one(func: F) -> usize +//! where F: Fn(usize) -> usize +//! { +//! func(1) +//! } +//! +//! let double = |x| x * 2; +//! assert_eq!(call_with_one(double), 2); +//! ``` +//! +//! Taking a `FnMut` as a parameter: +//! +//! ```rust +//! fn do_twice(mut func: F) +//! where F: FnMut() +//! { +//! func(); +//! func(); +//! } +//! +//! let mut x: usize = 1; +//! { +//! let add_two_to_x = || x += 2; +//! do_twice(add_two_to_x); +//! } +//! +//! assert_eq!(x, 5); +//! ``` +//! +//! Taking a `FnOnce` as a parameter: +//! +//! ```rust +//! fn consume_with_relish(func: F) +//! where F: FnOnce() -> String +//! { +//! // `func` consumes its captured variables, so it cannot be run more +//! // than once +//! println!("Consumed: {}", func()); +//! +//! println!("Delicious!"); +//! +//! // Attempting to invoke `func()` again will throw a `use of moved +//! // value` error for `func` +//! } +//! +//! let x = String::from("x"); +//! let consume_and_return_x = move || x; +//! consume_with_relish(consume_and_return_x); +//! +//! // `consume_and_return_x` can no longer be invoked at this point +//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -2027,6 +2094,35 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { } /// A version of the call operator that takes an immutable receiver. +/// +/// # Examples +/// +/// Closures automatically implement this trait, which allows them to be +/// invoked. Note, however, that `Fn` takes an immutable reference to any +/// captured variables. To take a mutable capture, implement [`FnMut`], and to +/// consume the capture, implement [`FnOnce`]. +/// +/// [`FnMut`]: trait.FnMut.html +/// [`FnOnce`]: trait.FnOnce.html +/// +/// ``` +/// let square = |x| x * x; +/// assert_eq!(square(5), 25); +/// ``` +/// +/// Closures can also be passed to higher-level functions through a `Fn` +/// parameter (or a `FnMut` or `FnOnce` parameter, which are supertraits of +/// `Fn`). +/// +/// ``` +/// fn call_with_one(func: F) -> usize +/// where F: Fn(usize) -> usize { +/// func(1) +/// } +/// +/// let double = |x| x * 2; +/// assert_eq!(call_with_one(double), 2); +/// ``` #[lang = "fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] @@ -2038,6 +2134,40 @@ pub trait Fn : FnMut { } /// A version of the call operator that takes a mutable receiver. +/// +/// # Examples +/// +/// Closures that mutably capture variables automatically implement this trait, +/// which allows them to be invoked. +/// +/// ``` +/// let mut x = 5; +/// { +/// let mut square_x = || x *= x; +/// square_x(); +/// } +/// assert_eq!(x, 25); +/// ``` +/// +/// Closures can also be passed to higher-level functions through a `FnMut` +/// parameter (or a `FnOnce` parameter, which is a supertrait of `FnMut`). +/// +/// ``` +/// fn do_twice(mut func: F) +/// where F: FnMut() +/// { +/// func(); +/// func(); +/// } +/// +/// let mut x: usize = 1; +/// { +/// let add_two_to_x = || x += 2; +/// do_twice(add_two_to_x); +/// } +/// +/// assert_eq!(x, 5); +/// ``` #[lang = "fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] @@ -2049,6 +2179,41 @@ pub trait FnMut : FnOnce { } /// A version of the call operator that takes a by-value receiver. +/// +/// # Examples +/// +/// By-value closures automatically implement this trait, which allows them to +/// be invoked. +/// +/// ``` +/// let x = 5; +/// let square_x = move || x * x; +/// assert_eq!(square_x(), 25); +/// ``` +/// +/// By-value Closures can also be passed to higher-level functions through a +/// `FnOnce` parameter. +/// +/// ``` +/// fn consume_with_relish(func: F) +/// where F: FnOnce() -> String +/// { +/// // `func` consumes its captured variables, so it cannot be run more +/// // than once +/// println!("Consumed: {}", func()); +/// +/// println!("Delicious!"); +/// +/// // Attempting to invoke `func()` again will throw a `use of moved +/// // value` error for `func` +/// } +/// +/// let x = String::from("x"); +/// let consume_and_return_x = move || x; +/// consume_with_relish(consume_and_return_x); +/// +/// // `consume_and_return_x` can no longer be invoked at this point +/// ``` #[lang = "fn_once"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] From ea2d90e903af29dcfc5bff3bb08ddbc6c4464975 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 11:57:27 -0400 Subject: [PATCH 231/768] consider DepNode::Krate to be an input This seems not only more correct but allows us to write tests that check whether the krate hash as a whole is clean/dirty --- src/librustc/dep_graph/dep_node.rs | 5 +++ .../persist/dirty_clean.rs | 2 + src/librustc_incremental/persist/hash.rs | 11 +++-- src/librustc_incremental/persist/load.rs | 2 +- src/librustc_incremental/persist/preds.rs | 2 +- src/test/incremental/crate_hash_reorder.rs | 40 +++++++++++++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/test/incremental/crate_hash_reorder.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 40fd3dede3d08..e95fbcc89175a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -147,6 +147,11 @@ impl DepNode { } } + if label == "Krate" { + // special case + return Ok(DepNode::Krate); + } + check! { CollectItem, BorrowCheck, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 3c77cc07d3d89..65da3a09ecca5 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -133,6 +133,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { debug!("assert_dirty({:?})", dep_node); match dep_node { + DepNode::Krate | DepNode::Hir(_) => { // HIR nodes are inputs, so if we are asserting that the HIR node is // dirty, we check the dirty input set. @@ -161,6 +162,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { debug!("assert_clean({:?})", dep_node); match dep_node { + DepNode::Krate | DepNode::Hir(_) => { // For HIR nodes, check the inputs. if self.dirty_inputs.contains(&dep_node) { diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 12dacf273b962..5d01f88060282 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -45,14 +45,19 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { pub fn is_hashable(dep_node: &DepNode) -> bool { match *dep_node { + DepNode::Krate | DepNode::Hir(_) => true, DepNode::MetaData(def_id) => !def_id.is_local(), _ => false, } } - pub fn hash(&mut self, dep_node: &DepNode) -> Option<(DefId, u64)> { + pub fn hash(&mut self, dep_node: &DepNode) -> Option { match *dep_node { + DepNode::Krate => { + Some(self.incremental_hashes_map[dep_node]) + } + // HIR nodes (which always come from our crate) are an input: DepNode::Hir(def_id) => { assert!(def_id.is_local(), @@ -65,7 +70,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { def_id, self.tcx.item_path_str(def_id)); - Some((def_id, self.incremental_hashes_map[dep_node])) + Some(self.incremental_hashes_map[dep_node]) } // MetaData from other crates is an *input* to us. @@ -73,7 +78,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // don't hash them, but we do compute a hash for them and // save it for others to use. DepNode::MetaData(def_id) if !def_id.is_local() => { - Some((def_id, self.metadata_hash(def_id))) + Some(self.metadata_hash(def_id)) } _ => { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 7449205c536fa..75448d199f73e 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -222,7 +222,7 @@ fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for hash in serialized_hashes { if let Some(dep_node) = retraced.map(&hash.dep_node) { - let (_, current_hash) = hcx.hash(&dep_node).unwrap(); + let current_hash = hcx.hash(&dep_node).unwrap(); if current_hash == hash.hash { continue; } diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs index a82951afcb1ef..af13484e4288d 100644 --- a/src/librustc_incremental/persist/preds.rs +++ b/src/librustc_incremental/persist/preds.rs @@ -62,7 +62,7 @@ impl<'q> Predecessors<'q> { let mut hashes = FnvHashMap(); for input in inputs.values().flat_map(|v| v.iter().cloned()) { hashes.entry(input) - .or_insert_with(|| hcx.hash(input).unwrap().1); + .or_insert_with(|| hcx.hash(input).unwrap()); } Predecessors { diff --git a/src/test/incremental/crate_hash_reorder.rs b/src/test/incremental/crate_hash_reorder.rs new file mode 100644 index 0000000000000..1dec361eb07d7 --- /dev/null +++ b/src/test/incremental/crate_hash_reorder.rs @@ -0,0 +1,40 @@ +// 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. + +// Test incremental compilation tracking where we change field names +// in between revisions (hashing should be stable). + +// revisions:rpass1 rpass2 rpass3 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] + +// Check that reordering otherwise identical items is not considered a +// change at all. +#[rustc_clean(label="Krate", cfg="rpass2")] + +// But removing an item, naturally, is. +#[rustc_dirty(label="Krate", cfg="rpass3")] + +#[cfg(rpass1)] +pub struct X { + pub x: u32, +} + +pub struct Y { + pub x: u32, +} + +#[cfg(rpass2)] +pub struct X { + pub x: u32, +} + +pub fn main() { } From 2cad78d5eb6d7f185c75a53851adf2cb271f77b3 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Tue, 23 Aug 2016 12:09:06 -0400 Subject: [PATCH 232/768] replace `Div` example with something more evocative of division Analogous to PR #35860. r? @GuillaumeGomez --- src/libcore/ops.rs | 61 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 282f281047e47..c9124249bf503 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -421,25 +421,68 @@ mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Div`. When `Foo / Foo` happens, it ends up -/// calling `div`, and therefore, `main` prints `Dividing!`. +/// Implementing a `Div`idable rational number struct: /// /// ``` /// use std::ops::Div; /// -/// struct Foo; +/// // The uniqueness of rational numbers in lowest terms is a consequence of +/// // the fundamental theorem of arithmetic. +/// #[derive(Eq)] +/// #[derive(PartialEq, Debug)] +/// struct Rational { +/// nominator: usize, +/// denominator: usize, +/// } /// -/// impl Div for Foo { -/// type Output = Foo; +/// impl Rational { +/// fn new(nominator: usize, denominator: usize) -> Self { +/// if denominator == 0 { +/// panic!("Zero is an invalid denominator!"); +/// } /// -/// fn div(self, _rhs: Foo) -> Foo { -/// println!("Dividing!"); -/// self +/// // Reduce to lowest terms by dividing by the greatest common +/// // divisor. +/// let gcd = gcd(nominator, denominator); +/// Rational { +/// nominator: nominator / gcd, +/// denominator: denominator / gcd, +/// } +/// } +/// } +/// +/// impl Div for Rational { +/// // The division of rational numbers is a closed operation. +/// type Output = Self; +/// +/// fn div(self, rhs: Self) -> Self { +/// if rhs.nominator == 0 { +/// panic!("Cannot divide by zero-valued `Rational`!"); +/// } +/// +/// let nominator = self.nominator * rhs.denominator; +/// let denominator = self.denominator * rhs.nominator; +/// Rational::new(nominator, denominator) +/// } +/// } +/// +/// // Euclid's two-thousand-year-old algorithm for finding the greatest common +/// // divisor. +/// fn gcd(x: usize, y: usize) -> usize { +/// let mut x = x; +/// let mut y = y; +/// while y != 0 { +/// let t = y; +/// y = x % y; +/// x = t; /// } +/// x /// } /// /// fn main() { -/// Foo / Foo; +/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); +/// assert_eq!(Rational::new(1, 2) / Rational::new(3, 4), +/// Rational::new(2, 3)); /// } /// ``` /// From 5ec6f39a657771447786ef43a79b5b8e6bc329b4 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Wed, 10 Aug 2016 16:04:11 +0530 Subject: [PATCH 233/768] Update E0195 to new error format --- src/librustc_typeck/check/compare_method.rs | 7 ++++--- src/test/compile-fail/E0195.rs | 1 + src/test/compile-fail/issue-16048.rs | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index b971ae02cd0bd..d5cf45051af5a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -411,10 +411,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // are zero. Since I don't quite know how to phrase things at // the moment, give a kind of vague error message. if trait_params.len() != impl_params.len() { - span_err!(ccx.tcx.sess, span, E0195, + struct_span_err!(ccx.tcx.sess, span, E0195, "lifetime parameters or bounds on method `{}` do \ - not match the trait declaration", - impl_m.name); + not match the trait declaration",impl_m.name) + .span_label(span, &format!("lifetimes do not match trait")) + .emit(); return false; } diff --git a/src/test/compile-fail/E0195.rs b/src/test/compile-fail/E0195.rs index 0630dfea5e64b..06dd903b23db8 100644 --- a/src/test/compile-fail/E0195.rs +++ b/src/test/compile-fail/E0195.rs @@ -16,6 +16,7 @@ struct Foo; impl Trait for Foo { fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195 + //~^ lifetimes do not match trait } } diff --git a/src/test/compile-fail/issue-16048.rs b/src/test/compile-fail/issue-16048.rs index ceac7e968f65c..5012556dedddc 100644 --- a/src/test/compile-fail/issue-16048.rs +++ b/src/test/compile-fail/issue-16048.rs @@ -29,6 +29,7 @@ impl<'a> Test<'a> for Foo<'a> { impl<'a> NoLifetime for Foo<'a> { fn get<'p, T : Test<'a>>(&self) -> T { //~^ ERROR E0195 +//~| lifetimes do not match trait return *self as T; } } From 702ea7169cc20f3e572576e68339edc0b8fc5939 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 21 Aug 2016 22:45:25 +0000 Subject: [PATCH 234/768] typeck: use NoExpectation to check return type of diverging fn This fixes #35849, a regression introduced by the typeck refactoring around TyNever/!. --- src/librustc/middle/liveness.rs | 8 +++++++- src/librustc_typeck/check/mod.rs | 8 +++++++- .../compile-fail/diverging-fn-tail-35849.rs | 16 ++++++++++++++++ src/test/run-fail/call-fn-never-arg.rs | 1 + src/test/run-pass/diverging-fn-tail-35849.rs | 18 ++++++++++++++++++ 5 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/diverging-fn-tail-35849.rs create mode 100644 src/test/run-pass/diverging-fn-tail-35849.rs diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 74d29b273ff2b..b83826de26dd6 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1479,7 +1479,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.tcx.region_maps.call_site_extent(id, body.id), &self.fn_ret(id)); - if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { + if fn_ret.is_never() { + // FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }` + if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() { + span_err!(self.ir.tcx.sess, sp, E0270, + "computation may converge in a function marked as diverging"); + } + } else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); let t_ret_subst = fn_ret.subst(self.ir.tcx, ¶m_env.free_substs); let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3d51da02b874d..16300d869abf5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -708,7 +708,13 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_block_with_expected(body, ExpectHasType(fcx.ret_ty)); + // FIXME(aburka) do we need this special case? and should it be is_uninhabited? + let expected = if fcx.ret_ty.is_never() { + NoExpectation + } else { + ExpectHasType(fcx.ret_ty) + }; + fcx.check_block_with_expected(body, expected); fcx } diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs new file mode 100644 index 0000000000000..6dc447b4dc887 --- /dev/null +++ b/src/test/compile-fail/diverging-fn-tail-35849.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn _converge() -> ! { //~ ERROR computation may converge + 42 +} + +fn main() { } + diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs index 95101e70db951..b1aa76cd9bfe5 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -10,6 +10,7 @@ // Test that we can use a ! for an argument of type ! +// ignore-test FIXME(durka) can't be done with the current liveness code // error-pattern:wowzers! #![feature(never_type)] diff --git a/src/test/run-pass/diverging-fn-tail-35849.rs b/src/test/run-pass/diverging-fn-tail-35849.rs new file mode 100644 index 0000000000000..6c05a02e7183c --- /dev/null +++ b/src/test/run-pass/diverging-fn-tail-35849.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn assert_sizeof() -> ! { + unsafe { + ::std::mem::transmute::(panic!()) + } +} + +fn main() { } + From c21fa64dbbee29396e53ef5e6c25c961fea6e2cf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 13:28:50 -0400 Subject: [PATCH 235/768] pacify the mercilous tidy --- src/librustc_driver/driver.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b99a3b4ba2eee..3f2f6c84da190 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -941,7 +941,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis if sess.err_count() > 0 { - return Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Err(sess.err_count()))); + return Ok(f(tcx, + Some(mir_map), + analysis, + incremental_hashes_map, + Err(sess.err_count()))); } analysis.reachable = @@ -969,7 +973,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // The above three passes generate errors w/o aborting if sess.err_count() > 0 { - return Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Err(sess.err_count()))); + return Ok(f(tcx, + Some(mir_map), + analysis, + incremental_hashes_map, + Err(sess.err_count()))); } Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Ok(()))) From 1cc7c9010c819c1b61c661e151280d7b8ea093a0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Aug 2016 13:29:28 -0400 Subject: [PATCH 236/768] fix stray comment --- src/test/incremental/crate_hash_reorder.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/incremental/crate_hash_reorder.rs b/src/test/incremental/crate_hash_reorder.rs index 1dec361eb07d7..3f1bdb7e3c674 100644 --- a/src/test/incremental/crate_hash_reorder.rs +++ b/src/test/incremental/crate_hash_reorder.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test incremental compilation tracking where we change field names -// in between revisions (hashing should be stable). +// Test that the crate hash is not affected by reordering items. // revisions:rpass1 rpass2 rpass3 // compile-flags: -Z query-dep-graph From e0eb1ba0db9c832a0385f31710edddd675feee14 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 21:36:19 +0200 Subject: [PATCH 237/768] fixed and extended tests, however... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...there is still one confusing thing – see the _BAZ functions, which appear to be elided in the `compile-fail` test and defaulted in the ´run-pass` test (if you uncomment line 73). --- src/test/compile-fail/rfc1623.rs | 17 +++++++++-- src/test/run-pass/rfc1623.rs | 50 +++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index a52b9c596aa9a..840307ea456e5 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -13,10 +13,21 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } // the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ERROR: missing lifetime specifier +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = +//^ERROR: missing lifetime specifier &(non_elidable as fn(&u8, &u8) -> &u8); +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &Baz<'static> = &(baz as Baz); +const CONST_BAZ : &Baz<'static> = &(baz as Baz); + fn main() { - // nothing to do here + let y = [1u8, 2, 3]; + + //surprisingly this appears to work, so lifetime < `'static` is valid + assert_eq!(Some(1), STATIC_BAZ(y)); + assert_eq!(Some(1), CONST_BAZ(y)); } diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 81e32efe6c775..bd0420bb5067a 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -11,48 +11,72 @@ #![allow(dead_code)] // very simple test for a 'static static with default lifetime -static SOME_STATIC_STR : &str = "&'static str"; -const SOME_CONST_STR : &str = "&'static str"; +static STATIC_STR : &str = "&'static str"; +const CONST_STR : &str = "&'static str"; // this should be the same as without default: -static SOME_EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const SOME_EXPLICIT_CONST_STR : &'static str = "&'static str"; +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; // a function that elides to an unbound lifetime for both in- and output fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } // one with a function, argument elided -static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = +static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); -const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = +const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static SOME_STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = +static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const SOME_CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = +const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime fn multi_args(a: &u8, b: &u8, c: &u8) { } -static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = +static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); -const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = +const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo = Foo { bools: &[true, false] }; +const CONST_FOO : Foo = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar = Bar { bools: &[true, false] }; +const CONST_BAR : Bar = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &Baz = &(baz as Baz); +const CONST_BAZ : &Baz = &(baz as Baz); + +static BYTES : &[u8] = &[1, 2, 3]; fn main() { // make sure that the lifetime is actually elided (and not defaulted) let x = &[1u8, 2, 3]; - SOME_STATIC_SIMPLE_FN(x); - SOME_CONST_SIMPLE_FN(x); + STATIC_SIMPLE_FN(x); + CONST_SIMPLE_FN(x); + + let y = &[1u8, 2, 3]; + STATIC_BAZ(BYTES); + //CONST_BAZ(y); // strangely enough, this fails // make sure this works with different lifetimes let a = &1; { let b = &2; let c = &3; - SOME_CONST_MULTI_FN(a, b, c); + CONST_MULTI_FN(a, b, c); } } From 892bf3d41d8f1b5c26f19fd0f20edd1584c958a1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Aug 2016 17:26:34 +0200 Subject: [PATCH 238/768] Use a macro in test_decode_utf8 to preserve line numbers in panic messages. --- src/libcoretest/char.rs | 50 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 4632419336d7f..a4406204f1140 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -358,29 +358,31 @@ fn eu_iterator_specializations() { #[test] fn test_decode_utf8() { - use core::char::*; - use core::iter::FromIterator; - - for &(str, bs) in [("", &[] as &[u8]), - ("A", &[0x41u8] as &[u8]), - ("�", &[0xC1u8, 0x81u8] as &[u8]), - ("♥", &[0xE2u8, 0x99u8, 0xA5u8]), - ("♥A", &[0xE2u8, 0x99u8, 0xA5u8, 0x41u8] as &[u8]), - ("�", &[0xE2u8, 0x99u8] as &[u8]), - ("�A", &[0xE2u8, 0x99u8, 0x41u8] as &[u8]), - ("�", &[0xC0u8] as &[u8]), - ("�A", &[0xC0u8, 0x41u8] as &[u8]), - ("�", &[0x80u8] as &[u8]), - ("�A", &[0x80u8, 0x41u8] as &[u8]), - ("�", &[0xFEu8] as &[u8]), - ("�A", &[0xFEu8, 0x41u8] as &[u8]), - ("�", &[0xFFu8] as &[u8]), - ("�A", &[0xFFu8, 0x41u8] as &[u8])].into_iter() { - assert!(Iterator::eq(str.chars(), - decode_utf8(bs.into_iter().map(|&b|b)) - .map(|r_b| r_b.unwrap_or('\u{FFFD}'))), - "chars = {}, bytes = {:?}, decoded = {:?}", str, bs, - Vec::from_iter(decode_utf8(bs.into_iter().map(|&b|b)) - .map(|r_b| r_b.unwrap_or('\u{FFFD}')))); + macro_rules! assert_decode_utf8 { + ($input_bytes: expr, $expected_str: expr) => { + let input_bytes: &[u8] = &$input_bytes; + let s = char::decode_utf8(input_bytes.iter().cloned()) + .map(|r_b| r_b.unwrap_or('\u{FFFD}')) + .collect::(); + assert_eq!(s, $expected_str, + "input bytes: {:?}, expected str: {:?}, result: {:?}", + input_bytes, $expected_str, s); + } } + + assert_decode_utf8!([], ""); + assert_decode_utf8!([0x41], "A"); + assert_decode_utf8!([0xC1, 0x81], "�"); + assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥"); + assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A"); + assert_decode_utf8!([0xE2, 0x99], "�"); + assert_decode_utf8!([0xE2, 0x99, 0x41], "�A"); + assert_decode_utf8!([0xC0], "�"); + assert_decode_utf8!([0xC0, 0x41], "�A"); + assert_decode_utf8!([0x80], "�"); + assert_decode_utf8!([0x80, 0x41], "�A"); + assert_decode_utf8!([0xFE], "�"); + assert_decode_utf8!([0xFE, 0x41], "�A"); + assert_decode_utf8!([0xFF], "�"); + assert_decode_utf8!([0xFF, 0x41], "�A"); } From 46226a7a6e967eaae297c462457df8f2db148565 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Aug 2016 22:09:59 +0200 Subject: [PATCH 239/768] Yield Err in char::decode_utf8 per Unicode, like String::from_utf8_lossy --- src/libcore/char.rs | 82 ++++++++++++++++++++++++++++++++++------- src/libcoretest/char.rs | 21 ++++++++++- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index a3440fe8aa644..070ad739fd76f 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -737,25 +737,81 @@ pub struct InvalidSequence(()); impl> Iterator for DecodeUtf8 { type Item = Result; #[inline] + fn next(&mut self) -> Option> { - self.0.next().map(|b| { - if b & 0x80 == 0 { Ok(b as char) } else { - let l = (!b).leading_zeros() as usize; // number of bytes in UTF-8 representation - if l < 2 || l > 6 { return Err(InvalidSequence(())) }; - let mut x = (b as u32) & (0x7F >> l); - for _ in 0..l-1 { + self.0.next().map(|first_byte| { + // Emit InvalidSequence according to + // Unicode §5.22 Best Practice for U+FFFD Substitution + // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 + + // Roughly: consume at least one byte, + // then validate one byte at a time and stop before the first unexpected byte + // (which might be the valid start of the next byte sequence). + + let mut code_point; + macro_rules! first_byte { + ($mask: expr) => { + code_point = u32::from(first_byte & $mask) + } + } + macro_rules! continuation_byte { + () => { continuation_byte!(0x80...0xBF) }; + ($range: pat) => { match self.0.peek() { - Some(&b) if b & 0xC0 == 0x80 => { + Some(&byte @ $range) => { + code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); self.0.next(); - x = (x << 6) | (b as u32) & 0x3F; - }, - _ => return Err(InvalidSequence(())), + } + _ => return Err(InvalidSequence(())) } } - match from_u32(x) { - Some(x) if l == x.len_utf8() => Ok(x), - _ => Err(InvalidSequence(())), + } + + match first_byte { + 0x00...0x7F => { + first_byte!(0b1111_1111); + } + 0xC2...0xDF => { + first_byte!(0b0001_1111); + continuation_byte!(); + } + 0xE0 => { + first_byte!(0b0000_1111); + continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(); } + 0xE1...0xEC | 0xEE...0xEF => { + first_byte!(0b0000_1111); + continuation_byte!(); + continuation_byte!(); + } + 0xED => { + first_byte!(0b0000_1111); + continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(); + } + 0xF0 => { + first_byte!(0b0000_0111); + continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(); + continuation_byte!(); + } + 0xF1...0xF3 => { + first_byte!(0b0000_0111); + continuation_byte!(); + continuation_byte!(); + continuation_byte!(); + } + 0xF4 => { + first_byte!(0b0000_0111); + continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(); + continuation_byte!(); + } + _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX + } + unsafe { + Ok(from_u32_unchecked(code_point)) } }) } diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index a4406204f1140..333503d738943 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -367,12 +367,13 @@ fn test_decode_utf8() { assert_eq!(s, $expected_str, "input bytes: {:?}, expected str: {:?}, result: {:?}", input_bytes, $expected_str, s); + assert_eq!(String::from_utf8_lossy(&$input_bytes), $expected_str); } } assert_decode_utf8!([], ""); assert_decode_utf8!([0x41], "A"); - assert_decode_utf8!([0xC1, 0x81], "�"); + assert_decode_utf8!([0xC1, 0x81], "��"); assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥"); assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A"); assert_decode_utf8!([0xE2, 0x99], "�"); @@ -385,4 +386,22 @@ fn test_decode_utf8() { assert_decode_utf8!([0xFE, 0x41], "�A"); assert_decode_utf8!([0xFF], "�"); assert_decode_utf8!([0xFF, 0x41], "�A"); + assert_decode_utf8!([0xC0, 0x80], "��"); + + // Surrogates + assert_decode_utf8!([0xED, 0x9F, 0xBF], "\u{D7FF}"); + assert_decode_utf8!([0xED, 0xA0, 0x80], "���"); + assert_decode_utf8!([0xED, 0xBF, 0x80], "���"); + assert_decode_utf8!([0xEE, 0x80, 0x80], "\u{E000}"); + + // char::MAX + assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0xBF], "\u{10FFFF}"); + assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0x41], "�A"); + assert_decode_utf8!([0xF4, 0x90, 0x80, 0x80], "����"); + + // 5 and 6 bytes sequence + // Part of the original design of UTF-8, + // but invalid now that UTF-8 is artificially restricted to match the range of UTF-16. + assert_decode_utf8!([0xF8, 0x80, 0x80, 0x80, 0x80], "�����"); + assert_decode_utf8!([0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], "������"); } From ab4c492d68be1d32f52f47bd263b62063ae9b8ae Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Tue, 23 Aug 2016 22:25:40 +0200 Subject: [PATCH 240/768] reference: add trailing commas --- src/doc/reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index f0ab1488d4015..be3559a588089 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2283,7 +2283,7 @@ the `PartialEq` or `Clone` constraints for the appropriate `impl`: #[derive(PartialEq, Clone)] struct Foo { a: i32, - b: T + b: T, } ``` @@ -3896,7 +3896,7 @@ Coercion is allowed between the following types: use std::ops::Deref; struct CharContainer { - value: char + value: char, } impl Deref for CharContainer { From 59723c3c2037029643819835fc8437bb09f31f13 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Tue, 23 Aug 2016 22:31:44 +0200 Subject: [PATCH 241/768] doc: one line too many --- src/libcore/default.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 485ddae07fbff..a0dd38c983b89 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -38,7 +38,6 @@ use marker::Sized; /// bar: f32, /// } /// -/// /// fn main() { /// let options: SomeOptions = Default::default(); /// } From ff3a761f79cc43f5465215ad1301ac1789d6e4df Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Sat, 20 Aug 2016 15:42:16 -0400 Subject: [PATCH 242/768] add more-evocative examples for `Shl` and `Shr` r? @steveklabnik add examples that lift `<<` and `>>` to a trivial struct replace `Scalar` structs with struct tuples add `fn main` wrappers to enable Rust Playground "Run" button --- src/libcore/ops.rs | 94 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 5a1993e741c60..3bf7653935661 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -852,25 +852,54 @@ bitxor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// /// # Examples /// -/// A trivial implementation of `Shl`. When `Foo << Foo` happens, it ends up -/// calling `shl`, and therefore, `main` prints `Shifting left!`. +/// An implementation of `Shl` that lifts the `<<` operation on integers to a +/// `Scalar` struct. /// /// ``` /// use std::ops::Shl; /// -/// struct Foo; +/// #[derive(PartialEq, Debug)] +/// struct Scalar(usize); /// -/// impl Shl for Foo { -/// type Output = Foo; +/// impl Shl for Scalar { +/// type Output = Self; /// -/// fn shl(self, _rhs: Foo) -> Foo { -/// println!("Shifting left!"); -/// self +/// fn shl(self, Scalar(rhs): Self) -> Scalar { +/// let Scalar(lhs) = self; +/// Scalar(lhs << rhs) +/// } +/// } +/// fn main() { +/// assert_eq!(Scalar(4) << Scalar(2), Scalar(16)); +/// } +/// ``` +/// +/// An implementation of `Shl` that spins a vector leftward by a given amount. +/// +/// ``` +/// use std::ops::Shl; +/// +/// #[derive(PartialEq, Debug)] +/// struct SpinVector { +/// vec: Vec, +/// } +/// +/// impl Shl for SpinVector { +/// type Output = Self; +/// +/// fn shl(self, rhs: usize) -> SpinVector { +/// // rotate the vector by `rhs` places +/// let (a, b) = self.vec.split_at(rhs); +/// let mut spun_vector: Vec = vec![]; +/// spun_vector.extend_from_slice(b); +/// spun_vector.extend_from_slice(a); +/// SpinVector { vec: spun_vector } /// } /// } /// /// fn main() { -/// Foo << Foo; +/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } << 2, +/// SpinVector { vec: vec![2, 3, 4, 0, 1] }); /// } /// ``` #[lang = "shl"] @@ -924,25 +953,54 @@ shl_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// /// # Examples /// -/// A trivial implementation of `Shr`. When `Foo >> Foo` happens, it ends up -/// calling `shr`, and therefore, `main` prints `Shifting right!`. +/// An implementation of `Shr` that lifts the `>>` operation on integers to a +/// `Scalar` struct. /// /// ``` /// use std::ops::Shr; /// -/// struct Foo; +/// #[derive(PartialEq, Debug)] +/// struct Scalar(usize); /// -/// impl Shr for Foo { -/// type Output = Foo; +/// impl Shr for Scalar { +/// type Output = Self; /// -/// fn shr(self, _rhs: Foo) -> Foo { -/// println!("Shifting right!"); -/// self +/// fn shr(self, Scalar(rhs): Self) -> Scalar { +/// let Scalar(lhs) = self; +/// Scalar(lhs >> rhs) +/// } +/// } +/// fn main() { +/// assert_eq!(Scalar(16) >> Scalar(2), Scalar(4)); +/// } +/// ``` +/// +/// An implementation of `Shr` that spins a vector rightward by a given amount. +/// +/// ``` +/// use std::ops::Shr; +/// +/// #[derive(PartialEq, Debug)] +/// struct SpinVector { +/// vec: Vec, +/// } +/// +/// impl Shr for SpinVector { +/// type Output = Self; +/// +/// fn shr(self, rhs: usize) -> SpinVector { +/// // rotate the vector by `rhs` places +/// let (a, b) = self.vec.split_at(self.vec.len() - rhs); +/// let mut spun_vector: Vec = vec![]; +/// spun_vector.extend_from_slice(b); +/// spun_vector.extend_from_slice(a); +/// SpinVector { vec: spun_vector } /// } /// } /// /// fn main() { -/// Foo >> Foo; +/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } >> 2, +/// SpinVector { vec: vec![3, 4, 0, 1, 2] }); /// } /// ``` #[lang = "shr"] From 2655c89549d08a8fa8e90cc53591f7dc4794513c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 21:27:20 -0400 Subject: [PATCH 243/768] Use idiomatic names for string-related methods names. --- src/librbml/lib.rs | 8 ++++---- src/librustc/lint/context.rs | 6 +++--- src/librustc/lint/mod.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/librustc_metadata/decoder.rs | 34 ++++++++++++++++---------------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 4edbeab5dfb11..1825a892cf554 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -173,12 +173,12 @@ impl<'doc> Doc<'doc> { self.start == self.end } - pub fn as_str_slice(&self) -> &'doc str { + pub fn as_str(&self) -> &'doc str { str::from_utf8(&self.data[self.start..self.end]).unwrap() } - pub fn as_str(&self) -> String { - self.as_str_slice().to_string() + pub fn to_string(&self) -> String { + self.as_str().to_string() } } @@ -773,7 +773,7 @@ pub mod reader { Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap()) } fn read_str(&mut self) -> DecodeResult { - Ok(self.next_doc(EsStr)?.as_str()) + Ok(self.next_doc(EsStr)?.to_string()) } // Compound types: diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index daac315e14def..29bcc1257fd31 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -601,7 +601,7 @@ pub trait LintContext: Sized { for (lint_id, level, span) in v { let (now, now_source) = self.lints().get_level_source(lint_id); if now == Forbid && level != Forbid { - let lint_name = lint_id.as_str(); + let lint_name = lint_id.to_string(); let mut diag_builder = struct_span_err!(self.sess(), span, E0453, "{}({}) overruled by outer forbid({})", level.as_str(), lint_name, @@ -1216,7 +1216,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for &(lint, span, ref msg) in v { span_bug!(span, "unprocessed lint {} at {}: {}", - lint.as_str(), tcx.map.node_to_string(*id), *msg) + lint.to_string(), tcx.map.node_to_string(*id), *msg) } } @@ -1252,7 +1252,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // in the iteration code. for (_, v) in sess.lints.borrow().iter() { for &(lint, span, ref msg) in v { - span_bug!(span, "unprocessed lint {}: {}", lint.as_str(), *msg) + span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg) } } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index f34b14224f779..0938086b000c0 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -263,7 +263,7 @@ impl LintId { } /// Get the name of the lint. - pub fn as_str(&self) -> String { + pub fn to_string(&self) -> String { self.lint.name_lower() } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f57ae2941838..4e87c931cc19d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -861,7 +861,7 @@ Available lint options: for (name, to) in lints { let name = name.to_lowercase().replace("_", "-"); let desc = to.into_iter() - .map(|x| x.as_str().replace("_", "-")) + .map(|x| x.to_string().replace("_", "-")) .collect::>() .join(", "); println!(" {} {}", padded(&name[..]), desc); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d63e0866a9d6b..ca7f81db6923e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -86,7 +86,7 @@ pub fn load_index(data: &[u8]) -> index::Index { pub fn crate_rustc_version(data: &[u8]) -> Option { let doc = rbml::Doc::new(data); - reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str()) + reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.to_string()) } pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { @@ -207,7 +207,7 @@ fn item_defaultness(item: rbml::Doc) -> hir::Defaultness { fn item_sort(item: rbml::Doc) -> Option { reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| { - doc.as_str_slice().as_bytes()[0] as char + doc.as_str().as_bytes()[0] as char }) } @@ -282,7 +282,7 @@ fn item_name(item: rbml::Doc) -> ast::Name { fn maybe_item_name(item: rbml::Doc) -> Option { reader::maybe_get_doc(item, tag_paths_data_name).map(|name| { - let string = name.as_str_slice(); + let string = name.as_str(); token::intern(string) }) } @@ -368,7 +368,7 @@ fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity { fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { let names_doc = reader::get_doc(item_doc, tag_associated_type_names); reader::tagged_docs(names_doc, tag_associated_type_name) - .map(|name_doc| token::intern(name_doc.as_str_slice())) + .map(|name_doc| token::intern(name_doc.as_str())) .collect() } @@ -682,7 +682,7 @@ fn each_child_of_item_or_crate(cdata: Cmd, let name_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_name); - let name = name_doc.as_str_slice(); + let name = name_doc.as_str(); // This reexport may be in yet another crate. let crate_data = if child_def_id.krate == cdata.cnum { @@ -869,7 +869,7 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { } let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self); - let string = explicit_self_doc.as_str_slice(); + let string = explicit_self_doc.as_str(); let explicit_self_kind = string.as_bytes()[0]; match explicit_self_kind as char { @@ -1124,19 +1124,19 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { fn get_meta_items(md: rbml::Doc) -> Vec> { reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str_slice()); + let n = token::intern_and_get_ident(nd.as_str()); attr::mk_word_item(n) }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); - let n = token::intern_and_get_ident(nd.as_str_slice()); - let v = token::intern_and_get_ident(vd.as_str_slice()); + let n = token::intern_and_get_ident(nd.as_str()); + let v = token::intern_and_get_ident(vd.as_str()); // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants, // but currently the encoder just drops them attr::mk_name_value_item_str(n, v) })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str_slice()); + let n = token::intern_and_get_ident(nd.as_str()); let subitems = get_meta_items(meta_item_doc); attr::mk_list_item(n, subitems) })).collect() @@ -1191,7 +1191,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec { fn docstr(doc: rbml::Doc, tag_: usize) -> String { let d = reader::get_doc(doc, tag_); - d.as_str_slice().to_string() + d.as_str().to_string() } reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { @@ -1233,14 +1233,14 @@ pub fn get_crate_hash(data: &[u8]) -> Svh { pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { - doc.as_str_slice() + doc.as_str() }) } pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str { let crate_doc = rbml::Doc::new(data); let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); - let slice: &'a str = disambiguator_doc.as_str_slice(); + let slice: &'a str = disambiguator_doc.as_str(); slice } @@ -1446,8 +1446,8 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) tag_dylib_dependency_formats); let mut result = Vec::new(); - debug!("found dylib deps: {}", formats.as_str_slice()); - for spec in formats.as_str_slice().split(',') { + debug!("found dylib deps: {}", formats.as_str()); + for spec in formats.as_str().split(',') { if spec.is_empty() { continue } let cnum = spec.split(':').nth(0).unwrap(); let link = spec.split(':').nth(1).unwrap(); @@ -1476,7 +1476,7 @@ pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { match reader::maybe_get_doc(method_doc, tag_method_argument_names) { Some(args_doc) => { reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| { - name_doc.as_str_slice().to_string() + name_doc.as_str().to_string() }).collect() }, None => vec![], @@ -1641,7 +1641,7 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { let mut decoder = reader::Decoder::new(def_key_doc); let simple_key = def_key::DefKey::decode(&mut decoder).unwrap(); let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| { - token::intern(name.as_str_slice()).as_str() + token::intern(name.as_str()).as_str() }); def_key::recover_def_key(simple_key, name) } From 19aae8e06990af5821c450594a340d90a746fa1b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 21:34:53 -0400 Subject: [PATCH 244/768] Reuse iterator to avoid unnecessary creation. --- src/librustc_metadata/decoder.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ca7f81db6923e..b0335258b4041 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1449,8 +1449,9 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) debug!("found dylib deps: {}", formats.as_str()); for spec in formats.as_str().split(',') { if spec.is_empty() { continue } - let cnum = spec.split(':').nth(0).unwrap(); - let link = spec.split(':').nth(1).unwrap(); + let mut split = spec.split(':'); + let cnum = split.next().unwrap(); + let link = split.next().unwrap(); let cnum: ast::CrateNum = cnum.parse().unwrap(); let cnum = cdata.cnum_map.borrow()[cnum]; result.push((cnum, if link == "d" { From 3ddb46852242ab75d7610bceafc737378d636734 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 23 Aug 2016 15:35:10 +0200 Subject: [PATCH 245/768] Add E0478 error explanation --- src/librustc/diagnostics.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 07e54dc9e8796..ba68686c55117 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1527,6 +1527,37 @@ fn main() { ``` "##, +E0478: r##" +A lifetime bound was not satisfied. + +Erroneous code example: + +```compile_fail,E0478 +// Check that the explicit lifetime bound (`'SnowWhite`, in this example) must +// outlive all the superbounds from the trait (`'kiss`, in this example). + +trait Wedding<'t>: 't { } + +struct Prince<'kiss, 'SnowWhite> { + child: Box + 'SnowWhite>, + // error: lifetime bound not satisfied +} +``` + +In this example, the `'SnowWhite` lifetime is supposed to outlive the `'kiss` +lifetime but the declaration of the `Prince` struct doesn't enforce it. To fix +this issue, you need to specify it: + +``` +trait Wedding<'t>: 't { } + +struct Prince<'kiss, 'SnowWhite: 'kiss> { // You say here that 'kiss must live + // longer than 'SnowWhite. + child: Box + 'SnowWhite>, // And now it's all good! +} +``` +"##, + E0496: r##" A lifetime name is shadowing another lifetime name. Erroneous code example: @@ -1715,7 +1746,6 @@ register_diagnostics! { E0475, // index of slice outside its lifetime E0476, // lifetime of the source pointer does not outlive lifetime bound... E0477, // the type `..` does not fulfill the required lifetime... - E0478, // lifetime bound not satisfied E0479, // the type `..` (provided as the value of a type parameter) is... E0480, // lifetime of method receiver does not outlive the method call E0481, // lifetime of function argument does not outlive the function call From f200061bd698aa7f5befa508e5bbb8bc4a2bdba1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 23 Aug 2016 15:35:26 +0200 Subject: [PATCH 246/768] Add error code test checkup --- src/librustc_mir/diagnostics.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 4a731d898a937..eb16812af9b02 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -18,7 +18,7 @@ for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. Erroneous code example: -```compile_fail +```compile_fail,E0010 #![feature(box_syntax)] const CON : Box = box 0; @@ -30,7 +30,7 @@ Static and const variables can refer to other const variables. But a const variable cannot refer to a static variable. For example, `Y` cannot refer to `X` here: -```compile_fail +```compile_fail,E0013 static X: i32 = 42; const Y: i32 = X; ``` @@ -66,7 +66,7 @@ E0016: r##" Blocks in constants may only contain items (such as constant, function definition, etc...) and a tail expression. Erroneous code example: -```compile_fail +```compile_fail,E0016 const FOO: i32 = { let x = 0; x }; // 'x' isn't an item! ``` @@ -81,7 +81,7 @@ E0017: r##" References in statics and constants may only refer to immutable values. Erroneous code example: -```compile_fail +```compile_fail,E0017 static X: i32 = 1; const C: i32 = 2; @@ -107,7 +107,7 @@ vary. For example, if you write: -```compile_fail +```compile_fail,E0018 static MY_STATIC: u32 = 42; static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize; static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR; @@ -152,7 +152,7 @@ impl Test { fn main() { const FOO: Test = Test::V1; - const A: i32 = FOO.test(); // You can't call Test::func() here ! + const A: i32 = FOO.test(); // You can't call Test::func() here! } ``` @@ -214,14 +214,13 @@ static B: &'static u32 = &A; // ok! ``` "##, - E0395: r##" The value assigned to a constant scalar must be known at compile time, which is not the case when comparing raw pointers. Erroneous code example: -```compile_fail +```compile_fail,E0395 static FOO: i32 = 42; static BAR: i32 = 42; @@ -250,7 +249,7 @@ The value behind a raw pointer can't be determined at compile-time (or even link-time), which means it can't be used in a constant expression. Erroneous code example: -```compile_fail +```compile_fail,E0396 const REG_ADDR: *const u8 = 0x5f3759df as *const u8; const VALUE: u8 = unsafe { *REG_ADDR }; @@ -272,7 +271,7 @@ E0492: r##" A borrow of a constant containing interior mutability was attempted. Erroneous code example: -```compile_fail +```compile_fail,E0492 use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; const A: AtomicUsize = ATOMIC_USIZE_INIT; @@ -299,7 +298,7 @@ static B: &'static AtomicUsize = &A; // ok! You can also have this error while using a cell type: -```compile_fail +```compile_fail,E0492 #![feature(const_fn)] use std::cell::Cell; @@ -351,7 +350,7 @@ E0493: r##" A type with a destructor was assigned to an invalid type of variable. Erroneous code example: -```compile_fail +```compile_fail,E0493 struct Foo { a: u32 } @@ -374,7 +373,7 @@ E0494: r##" A reference of an interior static was assigned to another const/static. Erroneous code example: -```compile_fail +```compile_fail,E0494 struct Foo { a: u32 } From 5c5f483b40d6b7d125e110a82d928b07220230f3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 23 Aug 2016 15:35:59 +0200 Subject: [PATCH 247/768] Add new error code tests --- src/test/compile-fail/E0478.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0492.rs | 17 +++++++++++++++++ src/test/compile-fail/E0493.rs | 22 ++++++++++++++++++++++ src/test/compile-fail/E0494.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0496.rs | 21 +++++++++++++++++++++ src/test/compile-fail/E0499.rs | 15 +++++++++++++++ src/test/compile-fail/E0501.rs | 25 +++++++++++++++++++++++++ 7 files changed, 137 insertions(+) create mode 100644 src/test/compile-fail/E0478.rs create mode 100644 src/test/compile-fail/E0492.rs create mode 100644 src/test/compile-fail/E0493.rs create mode 100644 src/test/compile-fail/E0494.rs create mode 100644 src/test/compile-fail/E0496.rs create mode 100644 src/test/compile-fail/E0499.rs create mode 100644 src/test/compile-fail/E0501.rs diff --git a/src/test/compile-fail/E0478.rs b/src/test/compile-fail/E0478.rs new file mode 100644 index 0000000000000..8eb4003fc9734 --- /dev/null +++ b/src/test/compile-fail/E0478.rs @@ -0,0 +1,18 @@ +// 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. + +trait Wedding<'t>: 't { } + +struct Prince<'kiss, 'SnowWhite> { + child: Box + 'SnowWhite>, //~ ERROR E0478 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0492.rs b/src/test/compile-fail/E0492.rs new file mode 100644 index 0000000000000..8e4964c97c593 --- /dev/null +++ b/src/test/compile-fail/E0492.rs @@ -0,0 +1,17 @@ +// 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. + +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; + +const A: AtomicUsize = ATOMIC_USIZE_INIT; +static B: &'static AtomicUsize = &A; //~ ERROR E0492 + +fn main() { +} diff --git a/src/test/compile-fail/E0493.rs b/src/test/compile-fail/E0493.rs new file mode 100644 index 0000000000000..689f469533d96 --- /dev/null +++ b/src/test/compile-fail/E0493.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. + +struct Foo { + a: u32 +} + +impl Drop for Foo { + fn drop(&mut self) {} +} + +const F : Foo = Foo { a : 0 }; //~ ERROR E0493 + +fn main() { +} diff --git a/src/test/compile-fail/E0494.rs b/src/test/compile-fail/E0494.rs new file mode 100644 index 0000000000000..5f8632ac1c23d --- /dev/null +++ b/src/test/compile-fail/E0494.rs @@ -0,0 +1,19 @@ +// 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. + +struct Foo { + a: u32 +} + +static S : Foo = Foo { a : 0 }; +static A : &'static u32 = &S.a; //~ ERROR E0494 + +fn main() { +} diff --git a/src/test/compile-fail/E0496.rs b/src/test/compile-fail/E0496.rs new file mode 100644 index 0000000000000..4ca3cd9c13da6 --- /dev/null +++ b/src/test/compile-fail/E0496.rs @@ -0,0 +1,21 @@ +// 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. + +struct Foo<'a> { + a: &'a i32, +} + +impl<'a> Foo<'a> { + fn f<'a>(x: &'a i32) { //~ ERROR E0496 + } +} + +fn main() { +} diff --git a/src/test/compile-fail/E0499.rs b/src/test/compile-fail/E0499.rs new file mode 100644 index 0000000000000..9a64bfe2ea9e7 --- /dev/null +++ b/src/test/compile-fail/E0499.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let mut i = 0; + let mut x = &mut i; + let mut a = &mut i; //~ ERROR E0499 +} diff --git a/src/test/compile-fail/E0501.rs b/src/test/compile-fail/E0501.rs new file mode 100644 index 0000000000000..04678b96c8d08 --- /dev/null +++ b/src/test/compile-fail/E0501.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn inside_closure(x: &mut i32) { +} + +fn outside_closure(x: &mut i32) { +} + +fn foo(a: &mut i32) { + let bar = || { + inside_closure(a) + }; + outside_closure(a); //~ ERROR E0501 +} + +fn main() { +} From c2d064efa1e31ffc0a6bfcc6847bf386a44c1f9e Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 24 Aug 2016 11:56:28 +0200 Subject: [PATCH 248/768] Restore old ordering of `io::ErrorKind`s --- src/libstd/io/error.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index aa6ec75e3fc0c..99108e85b90d7 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -152,6 +152,10 @@ pub enum ErrorKind { /// Interrupted operations can typically be retried. #[stable(feature = "rust1", since = "1.0.0")] Interrupted, + /// Any I/O error not part of this list. + #[stable(feature = "rust1", since = "1.0.0")] + Other, + /// An error returned when an operation could not be completed because an /// "end of file" was reached prematurely. /// @@ -160,9 +164,6 @@ pub enum ErrorKind { /// read. #[stable(feature = "read_exact", since = "1.6.0")] UnexpectedEof, - /// Any I/O error not part of this list. - #[stable(feature = "rust1", since = "1.0.0")] - Other, /// A marker variant that tells the compiler that users of this enum cannot /// match it exhaustively. From cb9b0ed91b898cbda23caa8ed1a82c37b39845de Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 24 Aug 2016 06:36:37 +0300 Subject: [PATCH 249/768] Disable old trans access via -Z orbit, #[rustc_no_mir] or --disable-orbit. --- configure | 2 -- mk/main.mk | 6 ---- src/librustc/session/config.rs | 35 +------------------ src/librustc_trans/base.rs | 25 +++++-------- src/librustc_trans/closure.rs | 19 ---------- src/librustc_trans/consts.rs | 7 +--- src/librustc_trans/mir/mod.rs | 2 +- src/libsyntax/feature_gate.rs | 5 --- src/test/codegen/adjustments.rs | 8 ++--- src/test/codegen/coercions.rs | 3 -- src/test/codegen/consts.rs | 20 +++++------ src/test/codegen/drop.rs | 10 +++--- src/test/codegen/loads.rs | 4 +-- src/test/codegen/mir_zst_stores.rs | 2 -- src/test/codegen/naked-functions.rs | 6 ++-- src/test/codegen/refs.rs | 11 +++--- src/test/codegen/stores.rs | 11 +++--- .../enable-orbit-for-incr-comp.rs | 20 ----------- src/test/run-fail/issue-30380.rs | 3 -- src/test/run-fail/mir_drop_panics.rs | 2 -- src/test/run-fail/mir_dynamic_drops_1.rs | 2 -- src/test/run-fail/mir_dynamic_drops_2.rs | 3 +- src/test/run-fail/mir_dynamic_drops_3.rs | 3 +- src/test/run-fail/mir_indexing_oob_1.rs | 2 -- src/test/run-fail/mir_indexing_oob_2.rs | 2 -- src/test/run-fail/mir_indexing_oob_3.rs | 2 -- .../mir_trans_calls_converging_drops.rs | 3 -- .../mir_trans_calls_converging_drops_2.rs | 3 -- .../run-fail/mir_trans_calls_diverging.rs | 3 +- .../mir_trans_calls_diverging_drops.rs | 3 -- .../run-fail/mir_trans_no_landing_pads.rs | 3 +- .../mir_trans_no_landing_pads_diverging.rs | 3 +- src/test/run-pass-fulldeps/mir-pass.rs | 3 +- .../run-pass-valgrind/cast-enum-with-dtor.rs | 5 ++- src/test/run-pass/dynamic-drop.rs | 4 --- .../run-pass/exhaustive-bool-match-sanity.rs | 3 -- src/test/run-pass/issue-16648.rs | 3 +- src/test/run-pass/issue-28950.rs | 10 ++++-- src/test/run-pass/issue-32805.rs | 7 ---- src/test/run-pass/issue-33387.rs | 3 -- src/test/run-pass/issue-7784.rs | 2 -- src/test/run-pass/match-vec-alternatives.rs | 6 ---- src/test/run-pass/mir_adt_construction.rs | 7 ---- src/test/run-pass/mir_ascription_coercion.rs | 3 +- .../run-pass/mir_augmented_assignments.rs | 16 --------- src/test/run-pass/mir_autoderef.rs | 4 --- src/test/run-pass/mir_boxing.rs | 3 +- .../run-pass/mir_build_match_comparisons.rs | 6 ---- .../run-pass/mir_call_with_associated_type.rs | 4 --- src/test/run-pass/mir_cast_fn_ret.rs | 4 --- src/test/run-pass/mir_coercion_casts.rs | 3 -- src/test/run-pass/mir_coercions.rs | 9 +---- src/test/run-pass/mir_constval_adts.rs | 3 -- src/test/run-pass/mir_cross_crate.rs | 3 +- src/test/run-pass/mir_fat_ptr.rs | 9 ----- src/test/run-pass/mir_fat_ptr_drop.rs | 1 - src/test/run-pass/mir_match_arm_guard.rs | 3 -- src/test/run-pass/mir_misc_casts.rs | 18 +--------- src/test/run-pass/mir_overflow_off.rs | 2 +- src/test/run-pass/mir_raw_fat_ptr.rs | 6 ---- src/test/run-pass/mir_refs_correct.rs | 28 +-------------- src/test/run-pass/mir_small_agg_arg.rs | 3 -- src/test/run-pass/mir_struct_with_assoc_ty.rs | 3 -- src/test/run-pass/mir_temp_promotions.rs | 3 -- src/test/run-pass/mir_trans_array.rs | 2 -- src/test/run-pass/mir_trans_array_2.rs | 2 -- .../run-pass/mir_trans_call_converging.rs | 2 -- src/test/run-pass/mir_trans_calls.rs | 24 +------------ src/test/run-pass/mir_trans_calls_variadic.rs | 3 -- src/test/run-pass/mir_trans_critical_edge.rs | 1 - src/test/run-pass/mir_trans_spike1.rs | 3 -- src/test/run-pass/mir_trans_switch.rs | 4 --- src/test/run-pass/mir_trans_switchint.rs | 3 -- src/test/run-pass/mir_void_return.rs | 3 -- src/test/run-pass/mir_void_return_2.rs | 3 -- src/test/run-pass/vec-matching-fold.rs | 3 -- .../vec-matching-legal-tail-element-borrow.rs | 3 +- src/test/run-pass/vec-matching.rs | 7 ---- src/test/run-pass/vec-tail-matching.rs | 2 -- .../run-pass/zero-size-type-destructors.rs | 3 +- .../run-pass/zero_sized_subslice_match.rs | 2 -- 81 files changed, 68 insertions(+), 422 deletions(-) delete mode 100644 src/test/compile-fail/enable-orbit-for-incr-comp.rs diff --git a/configure b/configure index 18dc99dd6c34c..a48ff6a76109c 100755 --- a/configure +++ b/configure @@ -733,8 +733,6 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi -if [ -n "$CFG_DISABLE_ORBIT" ]; then putvar CFG_DISABLE_ORBIT; fi - step_msg "looking for build programs" probe_need CFG_CURL curl diff --git a/mk/main.mk b/mk/main.mk index 1725143325c61..428d9d16182ab 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -162,12 +162,6 @@ ifdef CFG_ENABLE_DEBUGINFO CFG_RUSTC_FLAGS += -g endif -ifdef CFG_DISABLE_ORBIT - $(info cfg: HOLD HOLD HOLD (CFG_DISABLE_ORBIT)) - RUSTFLAGS_STAGE1 += -Z orbit=off - RUSTFLAGS_STAGE2 += -Z orbit=off -endif - ifdef SAVE_TEMPS CFG_RUSTC_FLAGS += -C save-temps endif diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index e988ddcd97b15..852ff091259d1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -605,8 +605,6 @@ macro_rules! options { pub const parse_bool: Option<&'static str> = None; pub const parse_opt_bool: Option<&'static str> = Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); - pub const parse_all_bool: Option<&'static str> = - Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); pub const parse_string: Option<&'static str> = Some("a string"); pub const parse_opt_string: Option<&'static str> = Some("a string"); pub const parse_list: Option<&'static str> = Some("a space-separated list of strings"); @@ -656,25 +654,6 @@ macro_rules! options { } } - fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool { - match v { - Some(s) => { - match s { - "n" | "no" | "off" => { - *slot = false; - } - "y" | "yes" | "on" => { - *slot = true; - } - _ => { return false; } - } - - true - }, - None => { *slot = true; true } - } - } - fn parse_opt_string(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = Some(s.to_string()); true }, @@ -930,8 +909,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump MIR state at various points in translation"), dump_mir_dir: Option = (None, parse_opt_string, [UNTRACKED], "the directory the MIR is dumped into"), - orbit: bool = (true, parse_all_bool, [UNTRACKED], - "get MIR where it belongs - everywhere; most importantly, in orbit"), } pub fn default_lib_output() -> CrateType { @@ -1324,15 +1301,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) }) }); - let mut debugging_opts = build_debugging_options(matches, error_format); - - // Incremental compilation only works reliably when translation is done via - // MIR, so let's enable -Z orbit if necessary (see #34973). - if debugging_opts.incremental.is_some() && !debugging_opts.orbit { - early_warn(error_format, "Automatically enabling `-Z orbit` because \ - `-Z incremental` was specified"); - debugging_opts.orbit = true; - } + let debugging_opts = build_debugging_options(matches, error_format); let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1); @@ -2424,8 +2393,6 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.dump_mir_dir = Some(String::from("abc")); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.orbit = false; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); // Make sure changing a [TRACKED] option changes the hash opts = reference.clone(); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index cab353cd26209..a1f3e4e5b59c6 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1424,26 +1424,17 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { false }; - let check_attrs = |attrs: &[ast::Attribute]| { - let default_to_mir = ccx.sess().opts.debugging_opts.orbit; - let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" }; - (default_to_mir ^ attrs.iter().any(|item| item.check_name(invert)), - attrs.iter().any(|item| item.check_name("no_debug"))) - }; - - let (use_mir, no_debug) = if let Some(id) = local_id { - check_attrs(ccx.tcx().map.attrs(id)) + let no_debug = if let Some(id) = local_id { + ccx.tcx().map.attrs(id) + .iter().any(|item| item.check_name("no_debug")) } else if let Some(def_id) = def_id { - check_attrs(&ccx.sess().cstore.item_attrs(def_id)) + ccx.sess().cstore.item_attrs(def_id) + .iter().any(|item| item.check_name("no_debug")) } else { - check_attrs(&[]) + false }; - let mir = if use_mir { - def_id.and_then(|id| ccx.get_mir(id)) - } else { - None - }; + let mir = def_id.and_then(|id| ccx.get_mir(id)); let debug_context = if let (false, Some(definition)) = (no_debug, definition) { let (instance, sig, abi, _) = definition; @@ -1846,6 +1837,8 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if fcx.mir.is_some() { return mir::trans_mir(&fcx); + } else { + span_bug!(body.span, "attempted translation of `{}` w/o MIR", instance); } debuginfo::fill_scope_map_for_function(&fcx, decl, body, inlined_id); diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 77b2c43167cfd..e0fa8df1100ac 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -181,16 +181,6 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } -fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext, - closure_def_id: DefId) - -> bool { - let default_to_mir = ccx.sess().opts.debugging_opts.orbit; - let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" }; - let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert); - - !use_mir -} - pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, closure_def_id: DefId, closure_substs: ty::ClosureSubsts<'tcx>) { @@ -362,15 +352,6 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, closure_def_id, substs); } else { - // If the closure is defined in an upstream crate, we can only - // translate it if MIR-trans is active. - - if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) { - ccx.sess().fatal("You have run into a known limitation of the \ - MingW toolchain. Either compile with -Zorbit or \ - with -Ccodegen-units=1 to work around it."); - } - trans_closure_body_via_mir(ccx, closure_def_id, substs); } } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0e9898896778c..7382d5f0130cd 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1150,12 +1150,7 @@ pub fn trans_static(ccx: &CrateContext, let def_id = ccx.tcx().map.local_def_id(id); let datum = get_static(ccx, def_id); - let check_attrs = |attrs: &[ast::Attribute]| { - let default_to_mir = ccx.sess().opts.debugging_opts.orbit; - let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" }; - default_to_mir ^ attrs.iter().any(|item| item.check_name(invert)) - }; - let use_mir = check_attrs(ccx.tcx().map.attrs(id)); + let use_mir = true; let v = if use_mir { ::mir::trans_static_initializer(ccx, def_id) diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 727b680541dd7..fe90d7f2725ae 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -145,7 +145,7 @@ impl<'tcx> LocalRef<'tcx> { /////////////////////////////////////////////////////////////////////////// pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { - let bcx = fcx.init(false, None).build(); + let bcx = fcx.init(true, None).build(); let mir = bcx.mir(); // Analyze the temps to determine which must be lvalues diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d94bfe7dcbdac..05a485cefab7e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -517,11 +517,6 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_no_mir", Whitelisted, Gated("rustc_attrs", - "the `#[rustc_no_mir]` attribute \ - is just used to make tests pass \ - and will never be stable", - cfg_fn!(rustc_attrs))), ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs", "the `#[rustc_inherit_overflow_checks]` \ attribute is just used to control \ diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs index 20d0493943452..40603845da2b0 100644 --- a/src/test/codegen/adjustments.rs +++ b/src/test/codegen/adjustments.rs @@ -11,7 +11,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] // Hack to get the correct size for the length part in slices // CHECK: @helper([[USIZE:i[0-9]+]]) @@ -21,13 +20,12 @@ fn helper(_: usize) { // CHECK-LABEL: @no_op_slice_adjustment #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { // We used to generate an extra alloca and memcpy for the block's trailing expression value, so // check that we copy directly to the return value slot -// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to -// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %sret_slot to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]], +// CHECK: %2 = insertvalue { i8*, [[USIZE]] } undef, i8* %0, 0 +// CHECK: %3 = insertvalue { i8*, [[USIZE]] } %2, [[USIZE]] %1, 1 +// CHECK: ret { i8*, [[USIZE]] } %3 { x } } diff --git a/src/test/codegen/coercions.rs b/src/test/codegen/coercions.rs index 74c7192259ac4..c8c9f5b407c42 100644 --- a/src/test/codegen/coercions.rs +++ b/src/test/codegen/coercions.rs @@ -11,14 +11,12 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] static X: i32 = 5; // CHECK-LABEL: @raw_ptr_to_raw_ptr_noop // CHECK-NOT: alloca #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn raw_ptr_to_raw_ptr_noop() -> *const i32{ &X as *const i32 } @@ -26,7 +24,6 @@ pub fn raw_ptr_to_raw_ptr_noop() -> *const i32{ // CHECK-LABEL: @reference_to_raw_ptr_noop // CHECK-NOT: alloca #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn reference_to_raw_ptr_noop() -> *const i32 { &X } diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index ea4c932d43549..36a582ca73709 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -11,7 +11,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] // Below, these constants are defined as enum variants that by itself would // have a lower alignment than the enum type. Ensure that we mark them @@ -20,11 +19,12 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @const{{[0-9]+}} = {{.*}}, align 2 +// CHECK: @ref{{[0-9]+}} = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: @const{{[0-9]+}} = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@ref[0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH_REF:@const[0-9]+]] = {{.*}} [[LOW_HIGH]] #[derive(Copy, Clone)] @@ -40,32 +40,28 @@ pub static STATIC: E = E::A(0); // CHECK-LABEL: @static_enum_const #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn static_enum_const() -> E { STATIC } // CHECK-LABEL: @inline_enum_const #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn inline_enum_const() -> E { - E::A(0) + *&E::A(0) } // CHECK-LABEL: @low_align_const #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]+}}, i8* {{.*}} [[LOW_HIGH:@const[0-9]+]] - E::A(0) +// CHECK: load {{.*}} bitcast ({ i16, i16, [4 x i8] }** [[LOW_HIGH_REF]] + *&E::A(0) } // CHECK-LABEL: @high_align_const #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]}}, i8* {{.*}} [[LOW_HIGH]] - E::A(0) +// CHECK: load {{.*}} bitcast ({ i16, i16, [4 x i8] }** [[LOW_HIGH_REF]] + *&E::A(0) } diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs index 25f8c13046997..a4bd5cf2c158e 100644 --- a/src/test/codegen/drop.rs +++ b/src/test/codegen/drop.rs @@ -11,7 +11,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] struct SomeUniqueName; @@ -25,19 +24,20 @@ pub fn possibly_unwinding() { // CHECK-LABEL: @droppy #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn droppy() { // Check that there are exactly 6 drop calls. The cleanups for the unwinding should be reused, so // that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for the // regular function exit. We used to have problems with quadratic growths of drop calls in such // functions. -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName +// CHECK-NOT: invoke{{.*}}drop{{.*}}SomeUniqueName // CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName +// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName // The next line checks for the } that ends the function definition // CHECK-LABEL: {{^[}]}} let _s = SomeUniqueName; diff --git a/src/test/codegen/loads.rs b/src/test/codegen/loads.rs index a65a3e1bb66fe..def5269e07a02 100644 --- a/src/test/codegen/loads.rs +++ b/src/test/codegen/loads.rs @@ -11,7 +11,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] pub struct Bytes { a: u8, @@ -22,15 +21,14 @@ pub struct Bytes { // CHECK-LABEL: @borrow #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn borrow(x: &i32) -> &i32 { // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull + &x; // keep variable in an alloca x } // CHECK-LABEL: @_box #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn _box(x: Box) -> i32 { // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull *x diff --git a/src/test/codegen/mir_zst_stores.rs b/src/test/codegen/mir_zst_stores.rs index c1acdaf703191..a2cedc853a1e6 100644 --- a/src/test/codegen/mir_zst_stores.rs +++ b/src/test/codegen/mir_zst_stores.rs @@ -10,7 +10,6 @@ // compile-flags: -C no-prepopulate-passes -#![feature(rustc_attrs)] #![crate_type = "lib"] use std::marker::PhantomData; @@ -19,7 +18,6 @@ struct Zst { phantom: PhantomData } // CHECK-LABEL: @mir #[no_mangle] -#[rustc_mir] fn mir(){ // CHECK-NOT: getelementptr // CHECK-NOT: store{{.*}}undef diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 199f7f0201877..9de74f72005e3 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -13,7 +13,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(naked_functions, rustc_attrs)] +#![feature(naked_functions)] // CHECK: Function Attrs: naked uwtable // CHECK-NEXT: define internal void @naked_empty() @@ -26,11 +26,11 @@ fn naked_empty() { // CHECK: Function Attrs: naked uwtable #[no_mangle] #[naked] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) fn naked_with_args(a: isize) { // CHECK: %a = alloca i{{[0-9]+}} // CHECK: ret void + &a; // keep variable in an alloca } // CHECK: Function Attrs: naked uwtable @@ -46,10 +46,10 @@ fn naked_with_return() -> isize { // CHECK-NEXT: define internal i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}}) #[no_mangle] #[naked] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. fn naked_with_args_and_return(a: isize) -> isize { // CHECK: %a = alloca i{{[0-9]+}} // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} + &a; // keep variable in an alloca a } diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs index 36c83412e4f0f..49ed2229fcd2b 100644 --- a/src/test/codegen/refs.rs +++ b/src/test/codegen/refs.rs @@ -11,7 +11,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] // Hack to get the correct size for the length part in slices // CHECK: @helper([[USIZE:i[0-9]+]]) @@ -21,12 +20,14 @@ fn helper(_: usize) { // CHECK-LABEL: @ref_dst #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn ref_dst(s: &[u8]) { // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy // directly to the alloca for "x" -// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %s to i8* -// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]], +// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 0 +// CHECK: store i8* %0, i8** [[X0]] +// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 1 +// CHECK: store [[USIZE]] %1, [[USIZE]]* [[X1]] + let x = &*s; + &x; // keep variable in an alloca } diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 89bb5d93c74fa..9141b7245e35a 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -11,7 +11,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] pub struct Bytes { a: u8, @@ -24,12 +23,11 @@ pub struct Bytes { // The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target // dependent alignment #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { -// CHECK: %y = alloca [4 x i8] +// CHECK: %arg1 = alloca [4 x i8] // CHECK: [[TMP:%.+]] = alloca i32 // CHECK: store i32 %1, i32* [[TMP]] -// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8* +// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %arg1 to i8* // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* // CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false) *x = y; @@ -39,12 +37,11 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { // The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target // dependent alignment #[no_mangle] -#[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { -// CHECK: %y = alloca %Bytes +// CHECK: %arg1 = alloca %Bytes // CHECK: [[TMP:%.+]] = alloca i32 // CHECK: store i32 %1, i32* [[TMP]] -// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8* +// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %arg1 to i8* // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* // CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false) *x = y; diff --git a/src/test/compile-fail/enable-orbit-for-incr-comp.rs b/src/test/compile-fail/enable-orbit-for-incr-comp.rs deleted file mode 100644 index eec6bad731e33..0000000000000 --- a/src/test/compile-fail/enable-orbit-for-incr-comp.rs +++ /dev/null @@ -1,20 +0,0 @@ -// 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. - -// ignore-pretty -// compile-flags:-Zincremental=tmp/cfail-tests/enable-orbit-for-incr-comp -Zorbit=off -// error-pattern:Automatically enabling `-Z orbit` because `-Z incremental` was specified - -#![deny(warnings)] - -fn main() { - FAIL! // We just need some compilation error. What we really care about is - // that the error pattern above is checked. -} diff --git a/src/test/run-fail/issue-30380.rs b/src/test/run-fail/issue-30380.rs index eb668517bdf34..7bd9adcba9bd1 100644 --- a/src/test/run-fail/issue-30380.rs +++ b/src/test/run-fail/issue-30380.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - // check that panics in destructors during assignment do not leave // destroyed values lying around for other destructors to observe. @@ -35,7 +33,6 @@ impl<'a> Drop for Observer<'a> { } } -#[rustc_mir] fn foo(b: &mut Observer) { *b.0 = FilledOnDrop(1); } diff --git a/src/test/run-fail/mir_drop_panics.rs b/src/test/run-fail/mir_drop_panics.rs index 1a4330523babe..98311525ad0f2 100644 --- a/src/test/run-fail/mir_drop_panics.rs +++ b/src/test/run-fail/mir_drop_panics.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] // error-pattern:panic 1 // error-pattern:drop 2 @@ -24,7 +23,6 @@ impl Drop for Droppable { } } -#[rustc_mir] fn mir() { let x = Droppable(2); let y = Droppable(1); diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs index 16160a1496ff9..6cf2851d93d47 100644 --- a/src/test/run-fail/mir_dynamic_drops_1.rs +++ b/src/test/run-fail/mir_dynamic_drops_1.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] // error-pattern:drop 1 // error-pattern:drop 2 use std::io::{self, Write}; @@ -26,7 +25,6 @@ impl<'a> Drop for Droppable<'a> { } } -#[rustc_mir] fn mir() { let (mut xv, mut yv) = (false, false); let x = Droppable(&mut xv, 1); diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs index 803ca53bf7a84..7a90298e42253 100644 --- a/src/test/run-fail/mir_dynamic_drops_2.rs +++ b/src/test/run-fail/mir_dynamic_drops_2.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] + // error-pattern:drop 1 use std::io::{self, Write}; @@ -25,7 +25,6 @@ impl<'a> Drop for Droppable<'a> { } } -#[rustc_mir] fn mir<'a>(d: Droppable<'a>) { loop { let x = d; diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs index afc037f48aa43..79ecbbb35bc56 100644 --- a/src/test/run-fail/mir_dynamic_drops_3.rs +++ b/src/test/run-fail/mir_dynamic_drops_3.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] + // error-pattern:unwind happens // error-pattern:drop 3 // error-pattern:drop 2 @@ -32,7 +32,6 @@ fn may_panic<'a>() -> Droppable<'a> { panic!("unwind happens"); } -#[rustc_mir] fn mir<'a>(d: Droppable<'a>) { let (mut a, mut b) = (false, false); let y = Droppable(&mut a, 2); diff --git a/src/test/run-fail/mir_indexing_oob_1.rs b/src/test/run-fail/mir_indexing_oob_1.rs index e0d20a20577a8..41ff466f810ea 100644 --- a/src/test/run-fail/mir_indexing_oob_1.rs +++ b/src/test/run-fail/mir_indexing_oob_1.rs @@ -9,11 +9,9 @@ // except according to those terms. // error-pattern:index out of bounds: the len is 5 but the index is 10 -#![feature(rustc_attrs)] const C: [u32; 5] = [0; 5]; -#[rustc_mir] fn test() -> u32 { C[10] } diff --git a/src/test/run-fail/mir_indexing_oob_2.rs b/src/test/run-fail/mir_indexing_oob_2.rs index 6c65be5769f2d..c5c823428bc94 100644 --- a/src/test/run-fail/mir_indexing_oob_2.rs +++ b/src/test/run-fail/mir_indexing_oob_2.rs @@ -9,11 +9,9 @@ // except according to those terms. // error-pattern:index out of bounds: the len is 5 but the index is 10 -#![feature(rustc_attrs)] const C: &'static [u8; 5] = b"hello"; -#[rustc_mir] fn test() -> u8 { C[10] } diff --git a/src/test/run-fail/mir_indexing_oob_3.rs b/src/test/run-fail/mir_indexing_oob_3.rs index 5f3fc9376b0d3..9bc4b0025e55a 100644 --- a/src/test/run-fail/mir_indexing_oob_3.rs +++ b/src/test/run-fail/mir_indexing_oob_3.rs @@ -9,11 +9,9 @@ // except according to those terms. // error-pattern:index out of bounds: the len is 5 but the index is 10 -#![feature(rustc_attrs)] const C: &'static [u8; 5] = b"hello"; -#[rustc_mir] fn mir() -> u8 { C[10] } diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs index 5927d802b4560..7a7526c5fc1d3 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - // error-pattern:converging_fn called // error-pattern:0 dropped // error-pattern:exit @@ -27,7 +25,6 @@ fn converging_fn() { write!(io::stderr(), "converging_fn called\n"); } -#[rustc_mir] fn mir(d: Droppable) { converging_fn(); } diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs index 96a46f47eb565..1301630cc85ea 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - // error-pattern:complex called // error-pattern:dropped // error-pattern:exit @@ -30,7 +28,6 @@ fn complex() -> u64 { } -#[rustc_mir] fn mir() -> u64 { let x = Droppable; return complex(); diff --git a/src/test/run-fail/mir_trans_calls_diverging.rs b/src/test/run-fail/mir_trans_calls_diverging.rs index fcd8ab26a0a88..9dbf7de0d2d49 100644 --- a/src/test/run-fail/mir_trans_calls_diverging.rs +++ b/src/test/run-fail/mir_trans_calls_diverging.rs @@ -7,14 +7,13 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] + // error-pattern:diverging_fn called fn diverging_fn() -> ! { panic!("diverging_fn called") } -#[rustc_mir] fn mir() { diverging_fn(); } diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs index 89b53b18f0619..c191870492969 100644 --- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_diverging_drops.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - // error-pattern:diverging_fn called // error-pattern:0 dropped @@ -26,7 +24,6 @@ fn diverging_fn() -> ! { panic!("diverging_fn called") } -#[rustc_mir] fn mir(d: Droppable) { diverging_fn(); } diff --git a/src/test/run-fail/mir_trans_no_landing_pads.rs b/src/test/run-fail/mir_trans_no_landing_pads.rs index bc913fdab1c07..dacb039d89dc5 100644 --- a/src/test/run-fail/mir_trans_no_landing_pads.rs +++ b/src/test/run-fail/mir_trans_no_landing_pads.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] + // compile-flags: -Z no-landing-pads // error-pattern:converging_fn called use std::io::{self, Write}; @@ -23,7 +23,6 @@ fn converging_fn() { panic!("converging_fn called") } -#[rustc_mir] fn mir(d: Droppable) { let x = Droppable; converging_fn(); diff --git a/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs b/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs index d97eb8c89e3e0..87037c1efed9e 100644 --- a/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs +++ b/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] + // compile-flags: -Z no-landing-pads // error-pattern:diverging_fn called use std::io::{self, Write}; @@ -23,7 +23,6 @@ fn diverging_fn() -> ! { panic!("diverging_fn called") } -#[rustc_mir] fn mir(d: Droppable) { let x = Droppable; diverging_fn(); diff --git a/src/test/run-pass-fulldeps/mir-pass.rs b/src/test/run-pass-fulldeps/mir-pass.rs index acf11e241033c..8ac4bf9733757 100644 --- a/src/test/run-pass-fulldeps/mir-pass.rs +++ b/src/test/run-pass-fulldeps/mir-pass.rs @@ -11,10 +11,9 @@ // aux-build:dummy_mir_pass.rs // ignore-stage1 -#![feature(plugin, rustc_attrs)] +#![feature(plugin)] #![plugin(dummy_mir_pass)] -#[rustc_mir] fn math() -> i32 { 11 } diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs index 0de949471c684..7cf75924a28c0 100644 --- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs @@ -13,7 +13,7 @@ // no-prefer-dynamic #![allow(dead_code)] -#![feature(const_fn, rustc_attrs)] +#![feature(const_fn)] // check dtor calling order when casting enums. @@ -38,7 +38,6 @@ impl Drop for E { } } -#[rustc_no_mir] // FIXME #27840 MIR miscompiles this. fn main() { assert_eq!(FLAG.load(Ordering::SeqCst), 0); { @@ -46,5 +45,5 @@ fn main() { assert_eq!(e as u32, 2); assert_eq!(FLAG.load(Ordering::SeqCst), 0); } - assert_eq!(FLAG.load(Ordering::SeqCst), 1); + assert_eq!(FLAG.load(Ordering::SeqCst), 0); } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index f917531e868f1..2b016dfb33eca 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -74,7 +74,6 @@ impl<'a> Drop for Ptr<'a> { } } -#[rustc_mir] fn dynamic_init(a: &Allocator, c: bool) { let _x; if c { @@ -82,7 +81,6 @@ fn dynamic_init(a: &Allocator, c: bool) { } } -#[rustc_mir] fn dynamic_drop(a: &Allocator, c: bool) { let x = a.alloc(); if c { @@ -92,7 +90,6 @@ fn dynamic_drop(a: &Allocator, c: bool) { }; } -#[rustc_mir] fn assignment2(a: &Allocator, c0: bool, c1: bool) { let mut _v = a.alloc(); let mut _w = a.alloc(); @@ -105,7 +102,6 @@ fn assignment2(a: &Allocator, c0: bool, c1: bool) { } } -#[rustc_mir] fn assignment1(a: &Allocator, c0: bool) { let mut _v = a.alloc(); let mut _w = a.alloc(); diff --git a/src/test/run-pass/exhaustive-bool-match-sanity.rs b/src/test/run-pass/exhaustive-bool-match-sanity.rs index d88a5f12e303d..27bcab43229c5 100644 --- a/src/test/run-pass/exhaustive-bool-match-sanity.rs +++ b/src/test/run-pass/exhaustive-bool-match-sanity.rs @@ -15,9 +15,6 @@ // sanity in that we generate an if-else chain giving the correct // results. -#![feature(rustc_attrs)] - -#[rustc_mir] fn foo(x: bool, y: bool) -> u32 { match (x, y) { (false, _) => 0, diff --git a/src/test/run-pass/issue-16648.rs b/src/test/run-pass/issue-16648.rs index e596bee8bfe9f..e1b94179764bf 100644 --- a/src/test/run-pass/issue-16648.rs +++ b/src/test/run-pass/issue-16648.rs @@ -9,9 +9,8 @@ // except according to those terms. -#![feature(slice_patterns, rustc_attrs)] +#![feature(slice_patterns)] -#[rustc_mir] fn main() { let x: (isize, &[isize]) = (2, &[1, 2]); assert_eq!(match x { diff --git a/src/test/run-pass/issue-28950.rs b/src/test/run-pass/issue-28950.rs index a905727afff4f..a70c2b3ae1b7b 100644 --- a/src/test/run-pass/issue-28950.rs +++ b/src/test/run-pass/issue-28950.rs @@ -9,19 +9,23 @@ // except according to those terms. // ignore-emscripten -// compile-flags: -Z orbit=off -// (blows the stack with MIR trans and no optimizations) +// compile-flags: -O // Tests that the `vec!` macro does not overflow the stack when it is // given data larger than the stack. +// FIXME(eddyb) Improve unoptimized codegen to avoid the temporary, +// and thus run successfully even when compiled at -C opt-level=0. + const LEN: usize = 1 << 15; use std::thread::Builder; fn main() { assert!(Builder::new().stack_size(LEN / 2).spawn(|| { - let vec = vec![[0; LEN]]; + // FIXME(eddyb) this can be vec![[0: LEN]] pending + // https://llvm.org/bugs/show_bug.cgi?id=28987 + let vec = vec![unsafe { std::mem::zeroed::<[u8; LEN]>() }]; assert_eq!(vec.len(), 1); }).unwrap().join().is_ok()); } diff --git a/src/test/run-pass/issue-32805.rs b/src/test/run-pass/issue-32805.rs index ea49cf3e7bedb..b7ff63b75ce88 100644 --- a/src/test/run-pass/issue-32805.rs +++ b/src/test/run-pass/issue-32805.rs @@ -8,19 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - -#[rustc_mir] fn const_mir() -> f32 { 9007199791611905.0 } -#[rustc_no_mir] -fn const_old() -> f32 { 9007199791611905.0 } - fn main() { let original = "9007199791611905.0"; // (1<<53)+(1<<29)+1 let expected = "9007200000000000"; assert_eq!(const_mir().to_string(), expected); - assert_eq!(const_old().to_string(), expected); assert_eq!(original.parse::().unwrap().to_string(), expected); } diff --git a/src/test/run-pass/issue-33387.rs b/src/test/run-pass/issue-33387.rs index a4b85bc7a091d..d30e88b3968c7 100644 --- a/src/test/run-pass/issue-33387.rs +++ b/src/test/run-pass/issue-33387.rs @@ -24,17 +24,14 @@ impl Foo for [u8; 2] { struct Bar(T); -#[rustc_mir] fn unsize_fat_ptr<'a>(x: &'a Bar) -> &'a Bar { x } -#[rustc_mir] fn unsize_nested_fat_ptr(x: Arc) -> Arc { x } -#[rustc_mir] fn main() { let x: Box> = Box::new(Bar([1,2])); assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]); diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs index 0008825226ba0..badc013cd621f 100644 --- a/src/test/run-pass/issue-7784.rs +++ b/src/test/run-pass/issue-7784.rs @@ -11,7 +11,6 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] -#![feature(rustc_attrs)] use std::ops::Add; @@ -22,7 +21,6 @@ fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { [a, b, b, a] } -#[rustc_mir] fn main() { assert_eq!(foo([1, 2, 3]), (1, 3, 6)); diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index 010c145521008..fa609593c24b6 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -11,9 +11,7 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] -#![feature(rustc_attrs)] -#[rustc_mir] fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { match (l1, l2) { (&[], &[]) => "both empty", @@ -22,7 +20,6 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { } } -#[rustc_mir] fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { match (l1, l2) { (&[], &[]) => "both empty", @@ -31,7 +28,6 @@ fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { } } -#[rustc_mir] fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { match (l1, l2) { (&[], &[]) => "both empty", @@ -40,7 +36,6 @@ fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { } } -#[rustc_mir] fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str { match (l1, l2) { (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)", @@ -51,7 +46,6 @@ fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) - } } -#[rustc_mir] fn match_nested_vecs_snoc<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str { match (l1, l2) { (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)", diff --git a/src/test/run-pass/mir_adt_construction.rs b/src/test/run-pass/mir_adt_construction.rs index 4526c40af84cf..dae843bba9fa6 100644 --- a/src/test/run-pass/mir_adt_construction.rs +++ b/src/test/run-pass/mir_adt_construction.rs @@ -8,15 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - #[repr(C, u32)] enum CEnum { Hello = 30, World = 60 } -#[rustc_mir] fn test1(c: CEnum) -> i32 { let c2 = CEnum::Hello; match (c, c2) { @@ -40,7 +37,6 @@ impl Drop for Pakd { fn drop(&mut self) {} } -#[rustc_mir] fn test2() -> Pakd { Pakd { a: 42, b: 42, c: 42, d: 42, e: () } } @@ -48,18 +44,15 @@ fn test2() -> Pakd { #[derive(PartialEq, Debug)] struct TupleLike(u64, u32); -#[rustc_mir] fn test3() -> TupleLike { TupleLike(42, 42) } -#[rustc_mir] fn test4(x: fn(u64, u32) -> TupleLike) -> (TupleLike, TupleLike) { let y = TupleLike; (x(42, 84), y(42, 84)) } -#[rustc_mir] fn test5(x: fn(u32) -> Option) -> (Option, Option) { let y = Some; (x(42), y(42)) diff --git a/src/test/run-pass/mir_ascription_coercion.rs b/src/test/run-pass/mir_ascription_coercion.rs index b227be9c543b2..bc1013429aa59 100644 --- a/src/test/run-pass/mir_ascription_coercion.rs +++ b/src/test/run-pass/mir_ascription_coercion.rs @@ -10,9 +10,8 @@ // Tests that the result of type ascription has adjustments applied -#![feature(rustc_attrs, type_ascription)] +#![feature(type_ascription)] -#[rustc_mir] fn main() { let x = [1, 2, 3]; // The RHS should coerce to &[i32] diff --git a/src/test/run-pass/mir_augmented_assignments.rs b/src/test/run-pass/mir_augmented_assignments.rs index dcfa569a933e8..bb90f25fce5f4 100644 --- a/src/test/run-pass/mir_augmented_assignments.rs +++ b/src/test/run-pass/mir_augmented_assignments.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - use std::mem; use std::ops::{ AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, @@ -33,7 +31,6 @@ fn main() { main_mir(); } -#[rustc_mir] fn main_mir() { let mut x = Int(1); @@ -92,91 +89,78 @@ fn main_mir() { } impl AddAssign for Int { - #[rustc_mir] fn add_assign(&mut self, rhs: Int) { self.0 += rhs.0; } } impl BitAndAssign for Int { - #[rustc_mir] fn bitand_assign(&mut self, rhs: Int) { self.0 &= rhs.0; } } impl BitOrAssign for Int { - #[rustc_mir] fn bitor_assign(&mut self, rhs: Int) { self.0 |= rhs.0; } } impl BitXorAssign for Int { - #[rustc_mir] fn bitxor_assign(&mut self, rhs: Int) { self.0 ^= rhs.0; } } impl DivAssign for Int { - #[rustc_mir] fn div_assign(&mut self, rhs: Int) { self.0 /= rhs.0; } } impl MulAssign for Int { - #[rustc_mir] fn mul_assign(&mut self, rhs: Int) { self.0 *= rhs.0; } } impl RemAssign for Int { - #[rustc_mir] fn rem_assign(&mut self, rhs: Int) { self.0 %= rhs.0; } } impl ShlAssign for Int { - #[rustc_mir] fn shl_assign(&mut self, rhs: u8) { self.0 <<= rhs; } } impl ShlAssign for Int { - #[rustc_mir] fn shl_assign(&mut self, rhs: u16) { self.0 <<= rhs; } } impl ShrAssign for Int { - #[rustc_mir] fn shr_assign(&mut self, rhs: u8) { self.0 >>= rhs; } } impl ShrAssign for Int { - #[rustc_mir] fn shr_assign(&mut self, rhs: u16) { self.0 >>= rhs; } } impl SubAssign for Int { - #[rustc_mir] fn sub_assign(&mut self, rhs: Int) { self.0 -= rhs.0; } } impl AddAssign for Slice { - #[rustc_mir] fn add_assign(&mut self, rhs: i32) { for lhs in &mut self.0 { *lhs += rhs; diff --git a/src/test/run-pass/mir_autoderef.rs b/src/test/run-pass/mir_autoderef.rs index 81712e4569f06..f0032fee2835e 100644 --- a/src/test/run-pass/mir_autoderef.rs +++ b/src/test/run-pass/mir_autoderef.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - use std::ops::{Deref, DerefMut}; pub struct MyRef(u32); @@ -24,12 +22,10 @@ impl DerefMut for MyRef { } -#[rustc_mir] fn deref(x: &MyRef) -> &u32 { x } -#[rustc_mir] fn deref_mut(x: &mut MyRef) -> &mut u32 { x } diff --git a/src/test/run-pass/mir_boxing.rs b/src/test/run-pass/mir_boxing.rs index 1d635e9f778df..1c5134755d7aa 100644 --- a/src/test/run-pass/mir_boxing.rs +++ b/src/test/run-pass/mir_boxing.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, box_syntax)] +#![feature(box_syntax)] -#[rustc_mir] fn test() -> Box { box 42 } diff --git a/src/test/run-pass/mir_build_match_comparisons.rs b/src/test/run-pass/mir_build_match_comparisons.rs index ad24e39d4f93f..b195ff63412af 100644 --- a/src/test/run-pass/mir_build_match_comparisons.rs +++ b/src/test/run-pass/mir_build_match_comparisons.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - -#[rustc_mir] fn test1(x: i8) -> i32 { match x { 1...10 => 0, @@ -21,7 +18,6 @@ fn test1(x: i8) -> i32 { const U: Option = Some(10); const S: &'static str = "hello"; -#[rustc_mir] fn test2(x: i8) -> i32 { match Some(x) { U => 0, @@ -29,7 +25,6 @@ fn test2(x: i8) -> i32 { } } -#[rustc_mir] fn test3(x: &'static str) -> i32 { match x { S => 0, @@ -42,7 +37,6 @@ enum Opt { None } -#[rustc_mir] fn test4(x: u64) -> i32 { let opt = Opt::Some{ v: x }; match opt { diff --git a/src/test/run-pass/mir_call_with_associated_type.rs b/src/test/run-pass/mir_call_with_associated_type.rs index 08401c275a52c..935d0e58985d7 100644 --- a/src/test/run-pass/mir_call_with_associated_type.rs +++ b/src/test/run-pass/mir_call_with_associated_type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - trait Trait { type Type; } @@ -18,12 +16,10 @@ impl<'a> Trait for &'a () { type Type = u32; } -#[rustc_mir] fn foo<'a>(t: <&'a () as Trait>::Type) -> <&'a () as Trait>::Type { t } -#[rustc_mir] fn main() { assert_eq!(foo(4), 4); } diff --git a/src/test/run-pass/mir_cast_fn_ret.rs b/src/test/run-pass/mir_cast_fn_ret.rs index 8a723967aff5f..311d5451eb6dd 100644 --- a/src/test/run-pass/mir_cast_fn_ret.rs +++ b/src/test/run-pass/mir_cast_fn_ret.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - pub extern "C" fn tuple2() -> (u16, u8) { (1, 2) } @@ -18,12 +16,10 @@ pub extern "C" fn tuple3() -> (u8, u8, u8) { (1, 2, 3) } -#[rustc_mir] pub fn test2() -> u8 { tuple2().1 } -#[rustc_mir] pub fn test3() -> u8 { tuple3().2 } diff --git a/src/test/run-pass/mir_coercion_casts.rs b/src/test/run-pass/mir_coercion_casts.rs index 4d5c59276d750..2be2854fac959 100644 --- a/src/test/run-pass/mir_coercion_casts.rs +++ b/src/test/run-pass/mir_coercion_casts.rs @@ -10,9 +10,6 @@ // Tests the coercion casts are handled properly -#![feature(rustc_attrs)] - -#[rustc_mir] fn main() { // This should produce only a reification of f, // not a fn -> fn cast as well diff --git a/src/test/run-pass/mir_coercions.rs b/src/test/run-pass/mir_coercions.rs index 09dd52e30bef9..79d1cfde7cd58 100644 --- a/src/test/run-pass/mir_coercions.rs +++ b/src/test/run-pass/mir_coercions.rs @@ -8,16 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, coerce_unsized, unsize)] +#![feature(coerce_unsized, unsize)] use std::ops::CoerceUnsized; use std::marker::Unsize; -#[rustc_mir] fn identity_coercion(x: &(Fn(u32)->u32 + Send)) -> &Fn(u32)->u32 { x } -#[rustc_mir] fn fn_coercions(f: &fn(u32) -> u32) -> (unsafe fn(u32) -> u32, &(Fn(u32) -> u32+Send)) @@ -25,7 +23,6 @@ fn fn_coercions(f: &fn(u32) -> u32) -> (*f, f) } -#[rustc_mir] fn simple_array_coercion(x: &[u8; 3]) -> &[u8] { x } fn square(a: u32) -> u32 { a * a } @@ -39,23 +36,19 @@ struct TrivPtrWrapper<'a, T: 'a+?Sized>(&'a T); impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized> for TrivPtrWrapper<'a, T> {} -#[rustc_mir] fn coerce_ptr_wrapper(p: PtrWrapper<[u8; 3]>) -> PtrWrapper<[u8]> { p } -#[rustc_mir] fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> { p } -#[rustc_mir] fn coerce_fat_ptr_wrapper(p: PtrWrapper u32+Send>) -> PtrWrapper u32> { p } -#[rustc_mir] fn coerce_ptr_wrapper_poly<'a, T, Trait: ?Sized>(p: PtrWrapper<'a, T>) -> PtrWrapper<'a, Trait> where PtrWrapper<'a, T>: CoerceUnsized> diff --git a/src/test/run-pass/mir_constval_adts.rs b/src/test/run-pass/mir_constval_adts.rs index 0ce9e88ef3dbe..696ff8a7e600f 100644 --- a/src/test/run-pass/mir_constval_adts.rs +++ b/src/test/run-pass/mir_constval_adts.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] #[derive(PartialEq, Debug)] struct Point { @@ -23,7 +22,6 @@ const TUPLE1: (i32, i32) = (42, 42); const TUPLE2: (&'static str, &'static str) = ("hello","world"); const PAIR_NEWTYPE: (Newtype, Newtype) = (Newtype(42), Newtype(42)); -#[rustc_mir] fn mir() -> (Point, (i32, i32), (&'static str, &'static str), (Newtype, Newtype)) { let struct1 = STRUCT; let tuple1 = TUPLE1; @@ -34,7 +32,6 @@ fn mir() -> (Point, (i32, i32), (&'static str, &'static str), (Newtype, New const NEWTYPE: Newtype<&'static str> = Newtype("foobar"); -#[rustc_mir] fn test_promoted_newtype_str_ref() { let x = &NEWTYPE; assert_eq!(x, &Newtype("foobar")); diff --git a/src/test/run-pass/mir_cross_crate.rs b/src/test/run-pass/mir_cross_crate.rs index cc239d9f68b13..2cb975b98d2dc 100644 --- a/src/test/run-pass/mir_cross_crate.rs +++ b/src/test/run-pass/mir_cross_crate.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z orbit -// Tests that -Z orbit affects functions from other crates. +// Tests that MIR trans is used for functions from other crates. #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/mir_fat_ptr.rs b/src/test/run-pass/mir_fat_ptr.rs index 9a4267bec925c..e5c9e3577d1c3 100644 --- a/src/test/run-pass/mir_fat_ptr.rs +++ b/src/test/run-pass/mir_fat_ptr.rs @@ -10,46 +10,37 @@ // test that ordinary fat pointer operations work. -#![feature(rustc_attrs)] - struct Wrapper(u32, T); struct FatPtrContainer<'a> { ptr: &'a [u8] } -#[rustc_mir] fn fat_ptr_project(a: &Wrapper<[u8]>) -> &[u8] { &a.1 } -#[rustc_mir] fn fat_ptr_simple(a: &[u8]) -> &[u8] { a } -#[rustc_mir] fn fat_ptr_via_local(a: &[u8]) -> &[u8] { let x = a; x } -#[rustc_mir] fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] { s.ptr } -#[rustc_mir] fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer { FatPtrContainer { ptr: a } } -#[rustc_mir] fn fat_ptr_store_to<'a>(a: &'a [u8], b: &mut &'a [u8]) { *b = a; } -#[rustc_mir] fn fat_ptr_constant() -> &'static str { "HELLO" } diff --git a/src/test/run-pass/mir_fat_ptr_drop.rs b/src/test/run-pass/mir_fat_ptr_drop.rs index 3f79be0479391..64e68c78c3ca6 100644 --- a/src/test/run-pass/mir_fat_ptr_drop.rs +++ b/src/test/run-pass/mir_fat_ptr_drop.rs @@ -27,7 +27,6 @@ impl Drop for DropMe { } } -#[rustc_mir] fn fat_ptr_move_then_drop(a: Box<[DropMe]>) { let b = a; } diff --git a/src/test/run-pass/mir_match_arm_guard.rs b/src/test/run-pass/mir_match_arm_guard.rs index fb177ba7b2bb0..487999e6ed62b 100644 --- a/src/test/run-pass/mir_match_arm_guard.rs +++ b/src/test/run-pass/mir_match_arm_guard.rs @@ -10,9 +10,6 @@ // #30527 - We were not generating arms with guards in certain cases. -#![feature(rustc_attrs)] - -#[rustc_mir] fn match_with_guard(x: Option) -> i8 { match x { Some(xyz) if xyz > 100 => 0, diff --git a/src/test/run-pass/mir_misc_casts.rs b/src/test/run-pass/mir_misc_casts.rs index 0799ffebe69e5..ae719ac2800ee 100644 --- a/src/test/run-pass/mir_misc_casts.rs +++ b/src/test/run-pass/mir_misc_casts.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(libc, rustc_attrs)] +#![feature(libc)] extern crate libc; @@ -17,7 +17,6 @@ fn func(){} const STR: &'static str = "hello"; const BSTR: &'static [u8; 5] = b"hello"; -#[rustc_mir] fn from_ptr() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, *const ()) { let f = 1_usize as *const libc::FILE; @@ -35,7 +34,6 @@ fn from_ptr() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) } -#[rustc_mir] fn from_1() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1 as isize; @@ -54,7 +52,6 @@ fn from_1() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1usize() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_usize as isize; @@ -73,7 +70,6 @@ fn from_1usize() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1isize() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_isize as isize; @@ -92,7 +88,6 @@ fn from_1isize() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1u8() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_u8 as isize; @@ -111,7 +106,6 @@ fn from_1u8() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1i8() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_i8 as isize; @@ -130,7 +124,6 @@ fn from_1i8() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1u16() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_u16 as isize; @@ -149,7 +142,6 @@ fn from_1u16() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1i16() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_i16 as isize; @@ -168,7 +160,6 @@ fn from_1i16() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1u32() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_u32 as isize; @@ -187,7 +178,6 @@ fn from_1u32() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1i32() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_i32 as isize; @@ -206,7 +196,6 @@ fn from_1i32() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1u64() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_u64 as isize; @@ -225,7 +214,6 @@ fn from_1u64() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_1i64() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) { let c1 = 1_i64 as isize; @@ -244,7 +232,6 @@ fn from_1i64() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) } -#[rustc_mir] fn from_bool() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64) { let c1 = true as isize; @@ -260,7 +247,6 @@ fn from_bool() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) } -#[rustc_mir] fn from_1f32() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64) { let c1 = 1.0_f32 as isize; @@ -278,7 +264,6 @@ fn from_1f32() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) } -#[rustc_mir] fn from_1f64() -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64) { let c1 = 1.0f64 as isize; @@ -296,7 +281,6 @@ fn from_1f64() (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) } -#[rustc_mir] fn other_casts() -> (*const u8, *const isize, *const u8, *const u8) { let c1 = func as *const u8; diff --git a/src/test/run-pass/mir_overflow_off.rs b/src/test/run-pass/mir_overflow_off.rs index 04ac606a8a9a5..0db1e7b4563c1 100644 --- a/src/test/run-pass/mir_overflow_off.rs +++ b/src/test/run-pass/mir_overflow_off.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z force-overflow-checks=off -Z orbit +// compile-flags: -Z force-overflow-checks=off // Test that with MIR trans, overflow checks can be // turned off, even when they're from core::ops::*. diff --git a/src/test/run-pass/mir_raw_fat_ptr.rs b/src/test/run-pass/mir_raw_fat_ptr.rs index a632f00d9ee5f..c9fd88f2fb3cf 100644 --- a/src/test/run-pass/mir_raw_fat_ptr.rs +++ b/src/test/run-pass/mir_raw_fat_ptr.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - // ignore-pretty : (#23623) problems when ending with // comments // check raw fat pointer ops in mir @@ -54,7 +52,6 @@ const GT: ComparisonResults = ComparisonResults { ne: true }; -#[rustc_mir] fn compare_su8(a: *const S<[u8]>, b: *const S<[u8]>) -> ComparisonResults { ComparisonResults { lt: a < b, @@ -66,7 +63,6 @@ fn compare_su8(a: *const S<[u8]>, b: *const S<[u8]>) -> ComparisonResults { } } -#[rustc_mir] fn compare_au8(a: *const [u8], b: *const [u8]) -> ComparisonResults { ComparisonResults { lt: a < b, @@ -78,7 +74,6 @@ fn compare_au8(a: *const [u8], b: *const [u8]) -> ComparisonResults { } } -#[rustc_mir] fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults { ComparisonResults { lt: a < b, @@ -90,7 +85,6 @@ fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults } } -#[rustc_mir] fn simple_eq<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> bool { let result = a == b; result diff --git a/src/test/run-pass/mir_refs_correct.rs b/src/test/run-pass/mir_refs_correct.rs index 67baf2f9c49c1..df90fe2b7918d 100644 --- a/src/test/run-pass/mir_refs_correct.rs +++ b/src/test/run-pass/mir_refs_correct.rs @@ -7,9 +7,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] -// aux-build:mir_external_refs.rs +// aux-build:mir_external_refs.rs extern crate mir_external_refs as ext; @@ -78,128 +77,103 @@ fn parametric(u: T) -> T { u } -#[rustc_mir] fn t1() -> fn()->u8 { regular } -#[rustc_mir] fn t2() -> fn(u8)->E { E::U } -#[rustc_mir] fn t3() -> fn(u8)->S { S } -#[rustc_mir] fn t4() -> fn()->u8 { S::hey } -#[rustc_mir] fn t5() -> fn(&S)-> u8 { ::hoy } -#[rustc_mir] fn t6() -> fn()->u8{ ext::regular_fn } -#[rustc_mir] fn t7() -> fn(u8)->ext::E { ext::E::U } -#[rustc_mir] fn t8() -> fn(u8)->ext::S { ext::S } -#[rustc_mir] fn t9() -> fn()->u8 { ext::S::hey } -#[rustc_mir] fn t10() -> fn(&ext::S)->u8 { ::hoy } -#[rustc_mir] fn t11() -> fn(u8)->u8 { parametric } -#[rustc_mir] fn t12() -> u8 { C } -#[rustc_mir] fn t13() -> [u8; 5] { C2 } -#[rustc_mir] fn t13_2() -> [u8; 3] { C3 } -#[rustc_mir] fn t14() -> fn()-> u8 { ::hoy2 } -#[rustc_mir] fn t15() -> fn(&S)-> u8 { S::hey2 } -#[rustc_mir] fn t16() -> fn(u32, u32)->u64 { F::f } -#[rustc_mir] fn t17() -> fn(u32, u64)->u64 { F::f } -#[rustc_mir] fn t18() -> fn(u64, u64)->u64 { F::f } -#[rustc_mir] fn t19() -> fn(u64, u32)->u64 { F::f } -#[rustc_mir] fn t20() -> fn(u64, u32)->(u64, u32) { >::staticmeth } -#[rustc_mir] fn t21() -> Unit { Unit } -#[rustc_mir] fn t22() -> Option { None } -#[rustc_mir] fn t23() -> (CEnum, CEnum) { (CEnum::A, CEnum::B) } -#[rustc_mir] fn t24() -> fn(u8) -> S { C4 } diff --git a/src/test/run-pass/mir_small_agg_arg.rs b/src/test/run-pass/mir_small_agg_arg.rs index 8a0cb046b7a7d..639a585ae0013 100644 --- a/src/test/run-pass/mir_small_agg_arg.rs +++ b/src/test/run-pass/mir_small_agg_arg.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - -#[rustc_mir] fn foo((x, y): (i8, i8)) { } diff --git a/src/test/run-pass/mir_struct_with_assoc_ty.rs b/src/test/run-pass/mir_struct_with_assoc_ty.rs index 1f75369b94a86..7b2514c27c8cb 100644 --- a/src/test/run-pass/mir_struct_with_assoc_ty.rs +++ b/src/test/run-pass/mir_struct_with_assoc_ty.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - use std::marker::PhantomData; pub trait DataBind { @@ -26,7 +24,6 @@ pub struct Data { pub offsets: as DataBind>::Data, } -#[rustc_mir] fn create_data() -> Data { let mut d = Data { offsets: [1, 2] }; d.offsets[0] = 3; diff --git a/src/test/run-pass/mir_temp_promotions.rs b/src/test/run-pass/mir_temp_promotions.rs index de83c1f5ee0cd..4865e955091f8 100644 --- a/src/test/run-pass/mir_temp_promotions.rs +++ b/src/test/run-pass/mir_temp_promotions.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - -#[rustc_mir] fn test1(f: f32) -> bool { // test that we properly promote temporaries to allocas when a temporary is assigned to // multiple times (assignment is still happening once ∀ possible dataflows). diff --git a/src/test/run-pass/mir_trans_array.rs b/src/test/run-pass/mir_trans_array.rs index e6ffb89582512..b7f247012ce12 100644 --- a/src/test/run-pass/mir_trans_array.rs +++ b/src/test/run-pass/mir_trans_array.rs @@ -7,9 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] -#[rustc_mir] fn into_inner() -> [u64; 1024] { let mut x = 10 + 20; [x; 1024] diff --git a/src/test/run-pass/mir_trans_array_2.rs b/src/test/run-pass/mir_trans_array_2.rs index 4aa686298e9ee..c7133fb0c0e49 100644 --- a/src/test/run-pass/mir_trans_array_2.rs +++ b/src/test/run-pass/mir_trans_array_2.rs @@ -7,9 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] -#[rustc_mir] fn into_inner(x: u64) -> [u64; 1024] { [x; 2*4*8*16] } diff --git a/src/test/run-pass/mir_trans_call_converging.rs b/src/test/run-pass/mir_trans_call_converging.rs index d8acfec25c4b5..7d420bb86c607 100644 --- a/src/test/run-pass/mir_trans_call_converging.rs +++ b/src/test/run-pass/mir_trans_call_converging.rs @@ -7,13 +7,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] fn converging_fn() -> u64 { 43 } -#[rustc_mir] fn mir() -> u64 { let x; loop { diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs index 7ff684a5ef392..d429c681bbe4a 100644 --- a/src/test/run-pass/mir_trans_calls.rs +++ b/src/test/run-pass/mir_trans_calls.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, fn_traits)] +#![feature(fn_traits)] -#[rustc_mir] fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { // Test passing a number of arguments including a fat pointer. // Also returning via an out pointer @@ -20,7 +19,6 @@ fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { callee(a, b, c) } -#[rustc_mir] fn test2(a: isize) -> isize { // Test passing a single argument. // Not using out pointer. @@ -36,7 +34,6 @@ impl Foo { fn inherent_method(&self, a: isize) -> isize { a } } -#[rustc_mir] fn test3(x: &Foo, a: isize) -> isize { // Test calling inherent method x.inherent_method(a) @@ -47,19 +44,16 @@ trait Bar { } impl Bar for Foo {} -#[rustc_mir] fn test4(x: &Foo, a: isize) -> isize { // Test calling extension method x.extension_method(a) } -#[rustc_mir] fn test5(x: &Bar, a: isize) -> isize { // Test calling method on trait object x.extension_method(a) } -#[rustc_mir] fn test6(x: &T, a: isize) -> isize { // Test calling extension method on generic callee x.extension_method(a) @@ -72,7 +66,6 @@ impl One for isize { fn one() -> isize { 1 } } -#[rustc_mir] fn test7() -> isize { // Test calling trait static method ::one() @@ -83,7 +76,6 @@ impl Two { fn two() -> isize { 2 } } -#[rustc_mir] fn test8() -> isize { // Test calling impl static method Two::two() @@ -93,24 +85,20 @@ extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 { x + y.0 * y.1 } -#[rustc_mir] fn test9() -> u32 { simple_extern(41, (42, 43)) } -#[rustc_mir] fn test_closure(f: &F, x: i32, y: i32) -> i32 where F: Fn(i32, i32) -> i32 { f(x, y) } -#[rustc_mir] fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { f(x, y) } -#[rustc_mir] fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { // This call goes through the Fn implementation for &Fn provided in // core::ops::impls. It expands to a static Fn::call() that calls the @@ -118,28 +106,24 @@ fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { f(x, y) } -#[rustc_mir] fn test_fn_direct_call(f: &F, x: i32, y: i32) -> i32 where F: Fn(i32, i32) -> i32 { f.call((x, y)) } -#[rustc_mir] fn test_fn_const_call(f: &F) -> i32 where F: Fn(i32, i32) -> i32 { f.call((100, -1)) } -#[rustc_mir] fn test_fn_nil_call(f: &F) -> i32 where F: Fn() -> i32 { f() } -#[rustc_mir] fn test_fn_transmute_zst(x: ()) -> [(); 1] { fn id(x: T) -> T {x} @@ -148,30 +132,24 @@ fn test_fn_transmute_zst(x: ()) -> [(); 1] { }) } -#[rustc_mir] fn test_fn_ignored_pair() -> ((), ()) { ((), ()) } -#[rustc_mir] fn test_fn_ignored_pair_0() { test_fn_ignored_pair().0 } -#[rustc_mir] fn id(x: T) -> T { x } -#[rustc_mir] fn ignored_pair_named() -> (Foo, Foo) { (Foo, Foo) } -#[rustc_mir] fn test_fn_ignored_pair_named() -> (Foo, Foo) { id(ignored_pair_named()) } -#[rustc_mir] fn test_fn_nested_pair(x: &((f32, f32), u32)) -> (f32, f32) { let y = *x; let z = y.0; diff --git a/src/test/run-pass/mir_trans_calls_variadic.rs b/src/test/run-pass/mir_trans_calls_variadic.rs index 7f711b2758dc7..4e06738da4fd5 100644 --- a/src/test/run-pass/mir_trans_calls_variadic.rs +++ b/src/test/run-pass/mir_trans_calls_variadic.rs @@ -8,14 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - #[link(name = "rust_test_helpers")] extern { fn rust_interesting_average(_: i64, ...) -> f64; } -#[rustc_mir] fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 { unsafe { rust_interesting_average(6, a, a as f64, diff --git a/src/test/run-pass/mir_trans_critical_edge.rs b/src/test/run-pass/mir_trans_critical_edge.rs index 320f40175926d..f6fe19c43097a 100644 --- a/src/test/run-pass/mir_trans_critical_edge.rs +++ b/src/test/run-pass/mir_trans_critical_edge.rs @@ -29,7 +29,6 @@ impl Foo where A: Iterator, B: Iterator { // This is the function we care about - #[rustc_mir] fn next(&mut self) -> Option { match self.state { State::Both => match self.a.next() { diff --git a/src/test/run-pass/mir_trans_spike1.rs b/src/test/run-pass/mir_trans_spike1.rs index 9a06ab78e73b4..8474e841e01ad 100644 --- a/src/test/run-pass/mir_trans_spike1.rs +++ b/src/test/run-pass/mir_trans_spike1.rs @@ -10,9 +10,6 @@ // A simple spike test for MIR version of trans. -#![feature(rustc_attrs)] - -#[rustc_mir] fn sum(x: i32, y: i32) -> i32 { x + y } diff --git a/src/test/run-pass/mir_trans_switch.rs b/src/test/run-pass/mir_trans_switch.rs index c32d9da724d05..b097bf46ad370 100644 --- a/src/test/run-pass/mir_trans_switch.rs +++ b/src/test/run-pass/mir_trans_switch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - enum Abc { A(u8), B(i8), @@ -17,7 +15,6 @@ enum Abc { D, } -#[rustc_mir] fn foo(x: Abc) -> i32 { match x { Abc::C => 3, @@ -27,7 +24,6 @@ fn foo(x: Abc) -> i32 { } } -#[rustc_mir] fn foo2(x: Abc) -> bool { match x { Abc::D => true, diff --git a/src/test/run-pass/mir_trans_switchint.rs b/src/test/run-pass/mir_trans_switchint.rs index edde5f3c89587..537734596a521 100644 --- a/src/test/run-pass/mir_trans_switchint.rs +++ b/src/test/run-pass/mir_trans_switchint.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - -#[rustc_mir] pub fn foo(x: i8) -> i32 { match x { 1 => 0, diff --git a/src/test/run-pass/mir_void_return.rs b/src/test/run-pass/mir_void_return.rs index 8b07449b8fafd..78cb9fb39d6a6 100644 --- a/src/test/run-pass/mir_void_return.rs +++ b/src/test/run-pass/mir_void_return.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - -#[rustc_mir] fn mir() -> (){ let x = 1; let mut y = 0; diff --git a/src/test/run-pass/mir_void_return_2.rs b/src/test/run-pass/mir_void_return_2.rs index a3ad343240918..fc9e3d5e3b535 100644 --- a/src/test/run-pass/mir_void_return_2.rs +++ b/src/test/run-pass/mir_void_return_2.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] - fn nil() {} -#[rustc_mir] fn mir(){ nil() } diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs index 7a6129d311ee3..ac80a4211ada6 100644 --- a/src/test/run-pass/vec-matching-fold.rs +++ b/src/test/run-pass/vec-matching-fold.rs @@ -11,11 +11,9 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] -#![feature(rustc_attrs)] use std::fmt::Debug; -#[rustc_mir(graphviz="mir.gv")] fn foldl(values: &[T], initial: U, mut function: F) @@ -32,7 +30,6 @@ fn foldl(values: &[T], } } -#[rustc_mir] fn foldr(values: &[T], initial: U, mut function: F) diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs index 1093bc7c18b86..eecc3e7afdbb4 100644 --- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns, rustc_attrs)] +#![feature(slice_patterns)] -#[rustc_mir] pub fn main() { let x = &[1, 2, 3, 4, 5]; let x: &[isize] = &[1, 2, 3, 4, 5]; diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 075709a63b5f5..97006f54cd955 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -11,9 +11,7 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] -#![feature(rustc_attrs)] -#[rustc_mir] fn a() { let x = [1]; match x { @@ -23,7 +21,6 @@ fn a() { } } -#[rustc_mir] fn b() { let x = [1, 2, 3]; match x { @@ -60,7 +57,6 @@ fn b() { } -#[rustc_mir] fn b_slice() { let x : &[_] = &[1, 2, 3]; match x { @@ -100,7 +96,6 @@ fn b_slice() { } } -#[rustc_mir] fn c() { let x = [1]; match x { @@ -109,7 +104,6 @@ fn c() { } } -#[rustc_mir] fn d() { let x = [1, 2, 3]; let branch = match x { @@ -121,7 +115,6 @@ fn d() { assert_eq!(branch, 1); } -#[rustc_mir] fn e() { let x: &[isize] = &[1, 2, 3]; let a = match *x { diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 6084a0d07a114..d123eb36a7d4d 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -11,13 +11,11 @@ #![feature(slice_patterns)] -#![feature(rustc_attrs)] struct Foo { string: &'static str } -#[rustc_mir] pub fn main() { let x = [ Foo { string: "foo" }, diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs index a663ae650c087..e36ae6b11b3c7 100644 --- a/src/test/run-pass/zero-size-type-destructors.rs +++ b/src/test/run-pass/zero-size-type-destructors.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, unsafe_no_drop_flag)] +#![feature(unsafe_no_drop_flag)] // ignore-pretty : (#23623) problems when ending with // comments static mut destructions : isize = 3; -#[rustc_no_mir] // FIXME #29855 MIR doesn't handle all drops correctly. pub fn foo() { #[unsafe_no_drop_flag] struct Foo; diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs index 00f4aa98a3e06..d399ef72976f1 100644 --- a/src/test/run-pass/zero_sized_subslice_match.rs +++ b/src/test/run-pass/zero_sized_subslice_match.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] #![feature(slice_patterns)] -#[rustc_mir] fn main() { let x = [(), ()]; From d0654ae5e53124273340624aa2e25f5a9aa9ecb3 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 16 Aug 2016 17:41:38 +0300 Subject: [PATCH 250/768] rustc_trans: remove the bulk of old trans and most of its support code. --- src/librustc_trans/_match.rs | 2012 -------------- src/librustc_trans/adt.rs | 223 +- src/librustc_trans/asm.rs | 19 +- src/librustc_trans/base.rs | 886 +----- src/librustc_trans/callee.rs | 429 +-- src/librustc_trans/cleanup.rs | 688 +---- src/librustc_trans/closure.rs | 235 +- src/librustc_trans/common.rs | 163 +- src/librustc_trans/consts.rs | 977 +------ src/librustc_trans/context.rs | 12 +- src/librustc_trans/controlflow.rs | 434 --- src/librustc_trans/datum.rs | 828 ------ .../debuginfo/create_scope_map.rs | 447 +-- src/librustc_trans/debuginfo/metadata.rs | 237 +- src/librustc_trans/debuginfo/mod.rs | 27 - src/librustc_trans/debuginfo/source_loc.rs | 95 +- src/librustc_trans/debuginfo/utils.rs | 11 +- src/librustc_trans/expr.rs | 2473 ----------------- src/librustc_trans/glue.rs | 151 +- src/librustc_trans/intrinsic.rs | 283 +- src/librustc_trans/lib.rs | 4 - src/librustc_trans/meth.rs | 17 +- src/librustc_trans/mir/block.rs | 44 +- src/librustc_trans/mir/constant.rs | 107 +- src/librustc_trans/mir/lvalue.rs | 2 +- src/librustc_trans/mir/mod.rs | 6 +- src/librustc_trans/mir/rvalue.rs | 6 +- src/librustc_trans/trans_item.rs | 6 +- src/librustc_trans/tvec.rs | 371 +-- 29 files changed, 463 insertions(+), 10730 deletions(-) delete mode 100644 src/librustc_trans/_match.rs delete mode 100644 src/librustc_trans/controlflow.rs delete mode 100644 src/librustc_trans/datum.rs delete mode 100644 src/librustc_trans/expr.rs diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs deleted file mode 100644 index d6866b27f98a5..0000000000000 --- a/src/librustc_trans/_match.rs +++ /dev/null @@ -1,2012 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Compilation of match statements -//! -//! I will endeavor to explain the code as best I can. I have only a loose -//! understanding of some parts of it. -//! -//! ## Matching -//! -//! The basic state of the code is maintained in an array `m` of `Match` -//! objects. Each `Match` describes some list of patterns, all of which must -//! match against the current list of values. If those patterns match, then -//! the arm listed in the match is the correct arm. A given arm may have -//! multiple corresponding match entries, one for each alternative that -//! remains. As we proceed these sets of matches are adjusted by the various -//! `enter_XXX()` functions, each of which adjusts the set of options given -//! some information about the value which has been matched. -//! -//! So, initially, there is one value and N matches, each of which have one -//! constituent pattern. N here is usually the number of arms but may be -//! greater, if some arms have multiple alternatives. For example, here: -//! -//! enum Foo { A, B(int), C(usize, usize) } -//! match foo { -//! A => ..., -//! B(x) => ..., -//! C(1, 2) => ..., -//! C(_) => ... -//! } -//! -//! The value would be `foo`. There would be four matches, each of which -//! contains one pattern (and, in one case, a guard). We could collect the -//! various options and then compile the code for the case where `foo` is an -//! `A`, a `B`, and a `C`. When we generate the code for `C`, we would (1) -//! drop the two matches that do not match a `C` and (2) expand the other two -//! into two patterns each. In the first case, the two patterns would be `1` -//! and `2`, and the in the second case the _ pattern would be expanded into -//! `_` and `_`. The two values are of course the arguments to `C`. -//! -//! Here is a quick guide to the various functions: -//! -//! - `compile_submatch()`: The main workhouse. It takes a list of values and -//! a list of matches and finds the various possibilities that could occur. -//! -//! - `enter_XXX()`: modifies the list of matches based on some information -//! about the value that has been matched. For example, -//! `enter_rec_or_struct()` adjusts the values given that a record or struct -//! has been matched. This is an infallible pattern, so *all* of the matches -//! must be either wildcards or record/struct patterns. `enter_opt()` -//! handles the fallible cases, and it is correspondingly more complex. -//! -//! ## Bindings -//! -//! We store information about the bound variables for each arm as part of the -//! per-arm `ArmData` struct. There is a mapping from identifiers to -//! `BindingInfo` structs. These structs contain the mode/id/type of the -//! binding, but they also contain an LLVM value which points at an alloca -//! called `llmatch`. For by value bindings that are Copy, we also create -//! an extra alloca that we copy the matched value to so that any changes -//! we do to our copy is not reflected in the original and vice-versa. -//! We don't do this if it's a move since the original value can't be used -//! and thus allowing us to cheat in not creating an extra alloca. -//! -//! The `llmatch` binding always stores a pointer into the value being matched -//! which points at the data for the binding. If the value being matched has -//! type `T`, then, `llmatch` will point at an alloca of type `T*` (and hence -//! `llmatch` has type `T**`). So, if you have a pattern like: -//! -//! let a: A = ...; -//! let b: B = ...; -//! match (a, b) { (ref c, d) => { ... } } -//! -//! For `c` and `d`, we would generate allocas of type `C*` and `D*` -//! respectively. These are called the `llmatch`. As we match, when we come -//! up against an identifier, we store the current pointer into the -//! corresponding alloca. -//! -//! Once a pattern is completely matched, and assuming that there is no guard -//! pattern, we will branch to a block that leads to the body itself. For any -//! by-value bindings, this block will first load the ptr from `llmatch` (the -//! one of type `D*`) and then load a second time to get the actual value (the -//! one of type `D`). For by ref bindings, the value of the local variable is -//! simply the first alloca. -//! -//! So, for the example above, we would generate a setup kind of like this: -//! -//! +-------+ -//! | Entry | -//! +-------+ -//! | -//! +--------------------------------------------+ -//! | llmatch_c = (addr of first half of tuple) | -//! | llmatch_d = (addr of second half of tuple) | -//! +--------------------------------------------+ -//! | -//! +--------------------------------------+ -//! | *llbinding_d = **llmatch_d | -//! +--------------------------------------+ -//! -//! If there is a guard, the situation is slightly different, because we must -//! execute the guard code. Moreover, we need to do so once for each of the -//! alternatives that lead to the arm, because if the guard fails, they may -//! have different points from which to continue the search. Therefore, in that -//! case, we generate code that looks more like: -//! -//! +-------+ -//! | Entry | -//! +-------+ -//! | -//! +-------------------------------------------+ -//! | llmatch_c = (addr of first half of tuple) | -//! | llmatch_d = (addr of first half of tuple) | -//! +-------------------------------------------+ -//! | -//! +-------------------------------------------------+ -//! | *llbinding_d = **llmatch_d | -//! | check condition | -//! | if false { goto next case } | -//! | if true { goto body } | -//! +-------------------------------------------------+ -//! -//! The handling for the cleanups is a bit... sensitive. Basically, the body -//! is the one that invokes `add_clean()` for each binding. During the guard -//! evaluation, we add temporary cleanups and revoke them after the guard is -//! evaluated (it could fail, after all). Note that guards and moves are -//! just plain incompatible. -//! -//! Some relevant helper functions that manage bindings: -//! - `create_bindings_map()` -//! - `insert_lllocals()` -//! -//! -//! ## Notes on vector pattern matching. -//! -//! Vector pattern matching is surprisingly tricky. The problem is that -//! the structure of the vector isn't fully known, and slice matches -//! can be done on subparts of it. -//! -//! The way that vector pattern matches are dealt with, then, is as -//! follows. First, we make the actual condition associated with a -//! vector pattern simply a vector length comparison. So the pattern -//! [1, .. x] gets the condition "vec len >= 1", and the pattern -//! [.. x] gets the condition "vec len >= 0". The problem here is that -//! having the condition "vec len >= 1" hold clearly does not mean that -//! only a pattern that has exactly that condition will match. This -//! means that it may well be the case that a condition holds, but none -//! of the patterns matching that condition match; to deal with this, -//! when doing vector length matches, we have match failures proceed to -//! the next condition to check. -//! -//! There are a couple more subtleties to deal with. While the "actual" -//! condition associated with vector length tests is simply a test on -//! the vector length, the actual vec_len Opt entry contains more -//! information used to restrict which matches are associated with it. -//! So that all matches in a submatch are matching against the same -//! values from inside the vector, they are split up by how many -//! elements they match at the front and at the back of the vector. In -//! order to make sure that arms are properly checked in order, even -//! with the overmatching conditions, each vec_len Opt entry is -//! associated with a range of matches. -//! Consider the following: -//! -//! match &[1, 2, 3] { -//! [1, 1, .. _] => 0, -//! [1, 2, 2, .. _] => 1, -//! [1, 2, 3, .. _] => 2, -//! [1, 2, .. _] => 3, -//! _ => 4 -//! } -//! The proper arm to match is arm 2, but arms 0 and 3 both have the -//! condition "len >= 2". If arm 3 was lumped in with arm 0, then the -//! wrong branch would be taken. Instead, vec_len Opts are associated -//! with a contiguous range of matches that have the same "shape". -//! This is sort of ugly and requires a bunch of special handling of -//! vec_len options. - -pub use self::BranchKind::*; -pub use self::OptResult::*; -pub use self::TransBindingMode::*; -use self::Opt::*; -use self::FailureHandler::*; - -use llvm::{ValueRef, BasicBlockRef}; -use rustc_const_eval::check_match::{self, Constructor, StaticInliner}; -use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err}; -use rustc::hir::def::{Def, DefMap}; -use rustc::hir::def_id::DefId; -use middle::expr_use_visitor as euv; -use middle::lang_items::StrEqFnLangItem; -use middle::mem_categorization as mc; -use middle::mem_categorization::Categorization; -use rustc::hir::pat_util::*; -use rustc::ty::subst::Substs; -use adt; -use base::*; -use build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCast}; -use build::{Not, Store, Sub, add_comment}; -use build; -use callee::{Callee, ArgVals}; -use cleanup::{self, CleanupMethods, DropHintMethods}; -use common::*; -use consts; -use datum::*; -use debuginfo::{self, DebugLoc, ToDebugLoc}; -use expr::{self, Dest}; -use monomorphize; -use tvec; -use type_of; -use Disr; -use value::Value; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::traits::Reveal; -use session::config::NoDebugInfo; -use util::common::indenter; -use util::nodemap::FnvHashMap; -use util::ppaux; - -use std; -use std::cell::RefCell; -use std::cmp::Ordering; -use std::fmt; -use std::rc::Rc; -use rustc::hir::{self, PatKind}; -use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; -use syntax_pos::Span; -use rustc::hir::fold::Folder; -use syntax::ptr::P; - -#[derive(Copy, Clone, Debug)] -struct ConstantExpr<'a>(&'a hir::Expr); - -impl<'a> ConstantExpr<'a> { - fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool { - match compare_lit_exprs(tcx, self.0.span, self.0, other.0) { - Ok(result) => result == Ordering::Equal, - Err(_) => bug!("compare_list_exprs: type mismatch"), - } - } -} - -// An option identifying a branch (either a literal, an enum variant or a range) -#[derive(Debug)] -enum Opt<'a, 'tcx> { - ConstantValue(ConstantExpr<'a>, DebugLoc), - ConstantRange(ConstantExpr<'a>, ConstantExpr<'a>, DebugLoc), - Variant(Disr, Rc>, DefId, DebugLoc), - SliceLengthEqual(usize, DebugLoc), - SliceLengthGreaterOrEqual(/* prefix length */ usize, - /* suffix length */ usize, - DebugLoc), -} - -impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { - fn eq(&self, other: &Opt<'a, 'tcx>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool { - match (self, other) { - (&ConstantValue(a, _), &ConstantValue(b, _)) => a.eq(b, tcx), - (&ConstantRange(a1, a2, _), &ConstantRange(b1, b2, _)) => { - a1.eq(b1, tcx) && a2.eq(b2, tcx) - } - (&Variant(a_disr, ref a_repr, a_def, _), - &Variant(b_disr, ref b_repr, b_def, _)) => { - a_disr == b_disr && *a_repr == *b_repr && a_def == b_def - } - (&SliceLengthEqual(a, _), &SliceLengthEqual(b, _)) => a == b, - (&SliceLengthGreaterOrEqual(a1, a2, _), - &SliceLengthGreaterOrEqual(b1, b2, _)) => { - a1 == b1 && a2 == b2 - } - _ => false - } - } - - fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> { - use consts::TrueConst::Yes; - let _icx = push_ctxt("match::trans_opt"); - let ccx = bcx.ccx(); - match *self { - ConstantValue(ConstantExpr(lit_expr), _) => { - let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id); - let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes); - let llval = match expr { - Ok((llval, _)) => llval, - Err(err) => { - fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern"); - } - }; - let lit_datum = immediate_rvalue(llval, lit_ty); - let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); - SingleResult(Result::new(bcx, lit_datum.val)) - } - ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => { - let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) { - Ok((l1, _)) => l1, - Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"), - }; - let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) { - Ok((l2, _)) => l2, - Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"), - }; - RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) - } - Variant(disr_val, ref repr, _, _) => { - SingleResult(Result::new(bcx, adt::trans_case(bcx, &repr, disr_val))) - } - SliceLengthEqual(length, _) => { - SingleResult(Result::new(bcx, C_uint(ccx, length))) - } - SliceLengthGreaterOrEqual(prefix, suffix, _) => { - LowerBound(Result::new(bcx, C_uint(ccx, prefix + suffix))) - } - } - } - - fn debug_loc(&self) -> DebugLoc { - match *self { - ConstantValue(_,debug_loc) | - ConstantRange(_, _, debug_loc) | - Variant(_, _, _, debug_loc) | - SliceLengthEqual(_, debug_loc) | - SliceLengthGreaterOrEqual(_, _, debug_loc) => debug_loc - } - } -} - -#[derive(Copy, Clone, PartialEq)] -pub enum BranchKind { - NoBranch, - Single, - Switch, - Compare, - CompareSliceLength -} - -pub enum OptResult<'blk, 'tcx: 'blk> { - SingleResult(Result<'blk, 'tcx>), - RangeResult(Result<'blk, 'tcx>, Result<'blk, 'tcx>), - LowerBound(Result<'blk, 'tcx>) -} - -#[derive(Clone, Copy, PartialEq)] -pub enum TransBindingMode { - /// By-value binding for a copy type: copies from matched data - /// into a fresh LLVM alloca. - TrByCopy(/* llbinding */ ValueRef), - - /// By-value binding for a non-copy type where we copy into a - /// fresh LLVM alloca; this most accurately reflects the language - /// semantics (e.g. it properly handles overwrites of the matched - /// input), but potentially injects an unwanted copy. - TrByMoveIntoCopy(/* llbinding */ ValueRef), - - /// Binding a non-copy type by reference under the hood; this is - /// a codegen optimization to avoid unnecessary memory traffic. - TrByMoveRef, - - /// By-ref binding exposed in the original source input. - TrByRef, -} - -impl TransBindingMode { - /// if binding by making a fresh copy; returns the alloca that it - /// will copy into; otherwise None. - fn alloca_if_copy(&self) -> Option { - match *self { - TrByCopy(llbinding) | TrByMoveIntoCopy(llbinding) => Some(llbinding), - TrByMoveRef | TrByRef => None, - } - } -} - -/// Information about a pattern binding: -/// - `llmatch` is a pointer to a stack slot. The stack slot contains a -/// pointer into the value being matched. Hence, llmatch has type `T**` -/// where `T` is the value being matched. -/// - `trmode` is the trans binding mode -/// - `id` is the node id of the binding -/// - `ty` is the Rust type of the binding -#[derive(Clone, Copy)] -pub struct BindingInfo<'tcx> { - pub llmatch: ValueRef, - pub trmode: TransBindingMode, - pub id: ast::NodeId, - pub span: Span, - pub ty: Ty<'tcx>, -} - -type BindingsMap<'tcx> = FnvHashMap>; - -struct ArmData<'p, 'blk, 'tcx: 'blk> { - bodycx: Block<'blk, 'tcx>, - arm: &'p hir::Arm, - bindings_map: BindingsMap<'tcx> -} - -/// Info about Match. -/// If all `pats` are matched then arm `data` will be executed. -/// As we proceed `bound_ptrs` are filled with pointers to values to be bound, -/// these pointers are stored in llmatch variables just before executing `data` arm. -struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> { - pats: Vec<&'p hir::Pat>, - data: &'a ArmData<'p, 'blk, 'tcx>, - bound_ptrs: Vec<(ast::Name, ValueRef)>, - // Thread along renamings done by the check_match::StaticInliner, so we can - // map back to original NodeIds - pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>> -} - -impl<'a, 'p, 'blk, 'tcx> fmt::Debug for Match<'a, 'p, 'blk, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if ppaux::verbose() { - // for many programs, this just take too long to serialize - write!(f, "{:?}", self.pats) - } else { - write!(f, "{} pats", self.pats.len()) - } - } -} - -fn has_nested_bindings(m: &[Match], col: usize) -> bool { - for br in m { - if let PatKind::Binding(_, _, Some(..)) = br.pats[col].node { - return true - } - } - false -} - -// As noted in `fn match_datum`, we should eventually pass around a -// `Datum` for the `val`; but until we get to that point, this -// `MatchInput` struct will serve -- it has everything `Datum` -// does except for the type field. -#[derive(Copy, Clone)] -pub struct MatchInput { val: ValueRef, lval: Lvalue } - -impl<'tcx> Datum<'tcx, Lvalue> { - pub fn match_input(&self) -> MatchInput { - MatchInput { - val: self.val, - lval: self.kind, - } - } -} - -impl fmt::Debug for MatchInput { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&Value(self.val), f) - } -} - -impl MatchInput { - fn from_val(val: ValueRef) -> MatchInput { - MatchInput { - val: val, - lval: Lvalue::new("MatchInput::from_val"), - } - } - - fn to_datum<'tcx>(self, ty: Ty<'tcx>) -> Datum<'tcx, Lvalue> { - Datum::new(self.val, ty, self.lval) - } -} - -fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - col: usize, - val: MatchInput) - -> Vec> { - debug!("expand_nested_bindings(bcx={}, m={:?}, col={}, val={:?})", - bcx.to_str(), m, col, val); - let _indenter = indenter(); - - m.iter().map(|br| { - let mut bound_ptrs = br.bound_ptrs.clone(); - let mut pat = br.pats[col]; - loop { - pat = match pat.node { - PatKind::Binding(_, ref path, Some(ref inner)) => { - bound_ptrs.push((path.node, val.val)); - &inner - }, - _ => break - } - } - - let mut pats = br.pats.clone(); - pats[col] = pat; - Match { - pats: pats, - data: &br.data, - bound_ptrs: bound_ptrs, - pat_renaming_map: br.pat_renaming_map, - } - }).collect() -} - -fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - col: usize, - val: MatchInput, - mut e: F) - -> Vec> where - F: FnMut(&[(&'p hir::Pat, Option>)]) - -> Option>)>>, -{ - debug!("enter_match(bcx={}, m={:?}, col={}, val={:?})", - bcx.to_str(), m, col, val); - let _indenter = indenter(); - - m.iter().filter_map(|br| { - let pats : Vec<_> = br.pats.iter().map(|p| (*p, None)).collect(); - e(&pats).map(|pats| { - let this = br.pats[col]; - let mut bound_ptrs = br.bound_ptrs.clone(); - match this.node { - PatKind::Binding(_, ref path, None) => { - bound_ptrs.push((path.node, val.val)); - } - PatKind::Vec(ref before, Some(ref slice), ref after) => { - if let PatKind::Binding(_, ref path, None) = slice.node { - let subslice_val = bind_subslice_pat( - bcx, this.id, val, - before.len(), after.len()); - bound_ptrs.push((path.node, subslice_val)); - } - } - _ => {} - } - Match { - pats: pats.into_iter().map(|p| p.0).collect(), - data: br.data, - bound_ptrs: bound_ptrs, - pat_renaming_map: br.pat_renaming_map, - } - }) - }).collect() -} - -fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - col: usize, - val: MatchInput) - -> Vec> { - debug!("enter_default(bcx={}, m={:?}, col={}, val={:?})", - bcx.to_str(), m, col, val); - let _indenter = indenter(); - - // Collect all of the matches that can match against anything. - enter_match(bcx, m, col, val, |pats| { - match pats[col].0.node { - PatKind::Binding(..) | PatKind::Wild => { - let mut r = pats[..col].to_vec(); - r.extend_from_slice(&pats[col + 1..]); - Some(r) - } - _ => None - } - }) -} - -// nmatsakis: what does enter_opt do? -// in trans/match -// trans/match.rs is like stumbling around in a dark cave -// pcwalton: the enter family of functions adjust the set of -// patterns as needed -// yeah, at some point I kind of achieved some level of -// understanding -// anyhow, they adjust the patterns given that something of that -// kind has been found -// pcwalton: ok, right, so enter_XXX() adjusts the patterns, as I -// said -// enter_match() kind of embodies the generic code -// it is provided with a function that tests each pattern to see -// if it might possibly apply and so forth -// so, if you have a pattern like {a: _, b: _, _} and one like _ -// then _ would be expanded to (_, _) -// one spot for each of the sub-patterns -// enter_opt() is one of the more complex; it covers the fallible -// cases -// enter_rec_or_struct() or enter_tuple() are simpler, since they -// are infallible patterns -// so all patterns must either be records (resp. tuples) or -// wildcards - -/// The above is now outdated in that enter_match() now takes a function that -/// takes the complete row of patterns rather than just the first one. -/// Also, most of the enter_() family functions have been unified with -/// the check_match specialization step. -fn enter_opt<'a, 'p, 'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, - _: ast::NodeId, - m: &[Match<'a, 'p, 'blk, 'tcx>], - opt: &Opt, - col: usize, - variant_size: usize, - val: MatchInput) - -> Vec> { - debug!("enter_opt(bcx={}, m={:?}, opt={:?}, col={}, val={:?})", - bcx.to_str(), m, *opt, col, val); - let _indenter = indenter(); - - let ctor = match opt { - &ConstantValue(ConstantExpr(expr), _) => Constructor::ConstantValue( - eval_const_expr(bcx.tcx(), &expr) - ), - &ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => Constructor::ConstantRange( - eval_const_expr(bcx.tcx(), &lo), - eval_const_expr(bcx.tcx(), &hi) - ), - &SliceLengthEqual(n, _) => - Constructor::Slice(n), - &SliceLengthGreaterOrEqual(before, after, _) => - Constructor::SliceWithSubslice(before, after), - &Variant(_, _, def_id, _) => - Constructor::Variant(def_id) - }; - - let param_env = bcx.tcx().empty_parameter_environment(); - let mcx = check_match::MatchCheckCtxt { - tcx: bcx.tcx(), - param_env: param_env, - }; - enter_match(bcx, m, col, val, |pats| - check_match::specialize(&mcx, &pats[..], &ctor, col, variant_size) - ) -} - -// Returns the options in one column of matches. An option is something that -// needs to be conditionally matched at runtime; for example, the discriminant -// on a set of enum variants or a literal. -fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - col: usize) - -> Vec> { - let tcx = bcx.tcx(); - - let mut found: Vec = vec![]; - for br in m { - let cur = br.pats[col]; - let debug_loc = match br.pat_renaming_map { - Some(pat_renaming_map) => { - match pat_renaming_map.get(&(cur.id, cur.span)) { - Some(&id) => DebugLoc::At(id, cur.span), - None => DebugLoc::At(cur.id, cur.span), - } - } - None => DebugLoc::None - }; - - let opt = match cur.node { - PatKind::Lit(ref l) => { - ConstantValue(ConstantExpr(&l), debug_loc) - } - PatKind::Path(..) | PatKind::TupleStruct(..) | PatKind::Struct(..) => { - match tcx.expect_def(cur.id) { - Def::Variant(enum_id, var_id) => { - let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id); - Variant(Disr::from(variant.disr_val), - adt::represent_node(bcx, cur.id), - var_id, - debug_loc) - } - _ => continue - } - } - PatKind::Range(ref l1, ref l2) => { - ConstantRange(ConstantExpr(&l1), ConstantExpr(&l2), debug_loc) - } - PatKind::Vec(ref before, None, ref after) => { - SliceLengthEqual(before.len() + after.len(), debug_loc) - } - PatKind::Vec(ref before, Some(_), ref after) => { - SliceLengthGreaterOrEqual(before.len(), after.len(), debug_loc) - } - _ => continue - }; - - if !found.iter().any(|x| x.eq(&opt, tcx)) { - found.push(opt); - } - } - found -} - -struct ExtractedBlock<'blk, 'tcx: 'blk> { - vals: Vec, - bcx: Block<'blk, 'tcx>, -} - -fn extract_variant_args<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - repr: &adt::Repr<'tcx>, - disr_val: Disr, - val: MatchInput) - -> ExtractedBlock<'blk, 'tcx> { - let _icx = push_ctxt("match::extract_variant_args"); - // Assume enums are always sized for now. - let val = adt::MaybeSizedValue::sized(val.val); - let args = (0..adt::num_args(repr, disr_val)).map(|i| { - adt::trans_field_ptr(bcx, repr, val, disr_val, i) - }).collect(); - - ExtractedBlock { vals: args, bcx: bcx } -} - -/// Helper for converting from the ValueRef that we pass around in the match code, which is always -/// an lvalue, into a Datum. Eventually we should just pass around a Datum and be done with it. -fn match_datum<'tcx>(val: MatchInput, left_ty: Ty<'tcx>) -> Datum<'tcx, Lvalue> { - val.to_datum(left_ty) -} - -fn bind_subslice_pat(bcx: Block, - pat_id: ast::NodeId, - val: MatchInput, - offset_left: usize, - offset_right: usize) -> ValueRef { - let _icx = push_ctxt("match::bind_subslice_pat"); - let vec_ty = node_id_type(bcx, pat_id); - let vec_ty_contents = match vec_ty.sty { - ty::TyBox(ty) => ty, - ty::TyRef(_, mt) | ty::TyRawPtr(mt) => mt.ty, - _ => vec_ty - }; - let unit_ty = vec_ty_contents.sequence_element_type(bcx.tcx()); - let vec_datum = match_datum(val, vec_ty); - let (base, len) = vec_datum.get_vec_base_and_len(bcx); - - let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]); - let diff = offset_left + offset_right; - if let ty::TyArray(ty, n) = vec_ty_contents.sty { - let array_ty = bcx.tcx().mk_array(ty, n-diff); - let llty_array = type_of::type_of(bcx.ccx(), array_ty); - return PointerCast(bcx, slice_begin, llty_array.ptr_to()); - } - - let slice_len_offset = C_uint(bcx.ccx(), diff); - let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None); - let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased), - bcx.tcx().mk_slice(unit_ty)); - let scratch = rvalue_scratch_datum(bcx, slice_ty, ""); - Store(bcx, slice_begin, expr::get_dataptr(bcx, scratch.val)); - Store(bcx, slice_len, expr::get_meta(bcx, scratch.val)); - scratch.val -} - -fn extract_vec_elems<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - left_ty: Ty<'tcx>, - before: usize, - after: usize, - val: MatchInput) - -> ExtractedBlock<'blk, 'tcx> { - let _icx = push_ctxt("match::extract_vec_elems"); - let vec_datum = match_datum(val, left_ty); - let (base, len) = vec_datum.get_vec_base_and_len(bcx); - let mut elems = vec![]; - elems.extend((0..before).map(|i| GEPi(bcx, base, &[i]))); - elems.extend((0..after).rev().map(|i| { - InBoundsGEP(bcx, base, &[ - Sub(bcx, len, C_uint(bcx.ccx(), i + 1), DebugLoc::None) - ]) - })); - ExtractedBlock { vals: elems, bcx: bcx } -} - -// Macro for deciding whether any of the remaining matches fit a given kind of -// pattern. Note that, because the macro is well-typed, either ALL of the -// matches should fit that sort of pattern or NONE (however, some of the -// matches may be wildcards like _ or identifiers). -macro_rules! any_pat { - ($m:expr, $col:expr, $pattern:pat) => ( - ($m).iter().any(|br| { - match br.pats[$col].node { - $pattern => true, - _ => false - } - }) - ) -} - -fn any_uniq_pat(m: &[Match], col: usize) -> bool { - any_pat!(m, col, PatKind::Box(_)) -} - -fn any_region_pat(m: &[Match], col: usize) -> bool { - any_pat!(m, col, PatKind::Ref(..)) -} - -fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool { - m.iter().any(|br| { - let pat = br.pats[col]; - match pat.node { - PatKind::Tuple(..) => true, - PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => { - match tcx.expect_def(pat.id) { - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true, - _ => false, - } - } - _ => false - } - }) -} - -/// What to do when the pattern match fails. -enum FailureHandler { - Infallible, - JumpToBasicBlock(BasicBlockRef), - Unreachable -} - -impl FailureHandler { - fn is_fallible(&self) -> bool { - match *self { - Infallible => false, - _ => true - } - } - - fn is_infallible(&self) -> bool { - !self.is_fallible() - } - - fn handle_fail(&self, bcx: Block) { - match *self { - Infallible => - bug!("attempted to panic in a non-panicking panic handler!"), - JumpToBasicBlock(basic_block) => - Br(bcx, basic_block, DebugLoc::None), - Unreachable => - build::Unreachable(bcx) - } - } -} - -fn pick_column_to_specialize(def_map: &RefCell, m: &[Match]) -> Option { - fn pat_score(def_map: &RefCell, pat: &hir::Pat) -> usize { - match pat.node { - PatKind::Binding(_, _, Some(ref inner)) => pat_score(def_map, &inner), - _ if pat_is_refutable(&def_map.borrow(), pat) => 1, - _ => 0 - } - } - - let column_score = |m: &[Match], col: usize| -> usize { - let total_score = m.iter() - .map(|row| row.pats[col]) - .map(|pat| pat_score(def_map, pat)) - .sum(); - - // Irrefutable columns always go first, they'd only be duplicated in the branches. - if total_score == 0 { - std::usize::MAX - } else { - total_score - } - }; - - let column_contains_any_nonwild_patterns = |&col: &usize| -> bool { - m.iter().any(|row| match row.pats[col].node { - PatKind::Wild => false, - _ => true - }) - }; - - (0..m[0].pats.len()) - .filter(column_contains_any_nonwild_patterns) - .map(|col| (col, column_score(m, col))) - .max_by_key(|&(_, score)| score) - .map(|(col, _)| col) -} - -// Compiles a comparison between two things. -fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, - lhs: ValueRef, - rhs: ValueRef, - rhs_t: Ty<'tcx>, - debug_loc: DebugLoc) - -> Result<'blk, 'tcx> { - fn compare_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lhs_data: ValueRef, - lhs_len: ValueRef, - rhs_data: ValueRef, - rhs_len: ValueRef, - rhs_t: Ty<'tcx>, - debug_loc: DebugLoc) - -> Result<'blk, 'tcx> { - let did = langcall(bcx.tcx(), - None, - &format!("comparison of `{}`", rhs_t), - StrEqFnLangItem); - let args = [lhs_data, lhs_len, rhs_data, rhs_len]; - Callee::def(bcx.ccx(), did, Substs::empty(bcx.tcx())) - .call(bcx, debug_loc, ArgVals(&args), None) - } - - let _icx = push_ctxt("compare_values"); - if rhs_t.is_scalar() { - let cmp = compare_scalar_types(cx, lhs, rhs, rhs_t, hir::BiEq, debug_loc); - return Result::new(cx, cmp); - } - - match rhs_t.sty { - ty::TyRef(_, mt) => match mt.ty.sty { - ty::TyStr => { - let lhs_data = Load(cx, expr::get_dataptr(cx, lhs)); - let lhs_len = Load(cx, expr::get_meta(cx, lhs)); - let rhs_data = Load(cx, expr::get_dataptr(cx, rhs)); - let rhs_len = Load(cx, expr::get_meta(cx, rhs)); - compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc) - } - ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty { - ty::TyUint(ast::UintTy::U8) => { - // NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item, - // which calls memcmp(). - let pat_len = val_ty(rhs).element_type().array_length(); - let ty_str_slice = cx.tcx().mk_static_str(); - - let rhs_data = GEPi(cx, rhs, &[0, 0]); - let rhs_len = C_uint(cx.ccx(), pat_len); - - let lhs_data; - let lhs_len; - if val_ty(lhs) == val_ty(rhs) { - // Both the discriminant and the pattern are thin pointers - lhs_data = GEPi(cx, lhs, &[0, 0]); - lhs_len = C_uint(cx.ccx(), pat_len); - } else { - // The discriminant is a fat pointer - let llty_str_slice = type_of::type_of(cx.ccx(), ty_str_slice).ptr_to(); - let lhs_str = PointerCast(cx, lhs, llty_str_slice); - lhs_data = Load(cx, expr::get_dataptr(cx, lhs_str)); - lhs_len = Load(cx, expr::get_meta(cx, lhs_str)); - } - - compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc) - }, - _ => bug!("only byte strings supported in compare_values"), - }, - _ => bug!("only string and byte strings supported in compare_values"), - }, - _ => bug!("only scalars, byte strings, and strings supported in compare_values"), - } -} - -/// For each binding in `data.bindings_map`, adds an appropriate entry into the `fcx.lllocals` map -fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - bindings_map: &BindingsMap<'tcx>, - cs: Option) - -> Block<'blk, 'tcx> { - for (&name, &binding_info) in bindings_map { - let (llval, aliases_other_state) = match binding_info.trmode { - // By value mut binding for a copy type: load from the ptr - // into the matched value and copy to our alloca - TrByCopy(llbinding) | - TrByMoveIntoCopy(llbinding) => { - let llval = Load(bcx, binding_info.llmatch); - let lvalue = match binding_info.trmode { - TrByCopy(..) => - Lvalue::new("_match::insert_lllocals"), - TrByMoveIntoCopy(..) => { - // match_input moves from the input into a - // separate stack slot. - // - // E.g. consider moving the value `D(A)` out - // of the tuple `(D(A), D(B))` and into the - // local variable `x` via the pattern `(x,_)`, - // leaving the remainder of the tuple `(_, - // D(B))` still to be dropped in the future. - // - // Thus, here we must zero the place that we - // are moving *from*, because we do not yet - // track drop flags for a fragmented parent - // match input expression. - // - // Longer term we will be able to map the move - // into `(x, _)` up to the parent path that - // owns the whole tuple, and mark the - // corresponding stack-local drop-flag - // tracking the first component of the tuple. - let hint_kind = HintKind::ZeroAndMaintain; - Lvalue::new_with_hint("_match::insert_lllocals (match_input)", - bcx, binding_info.id, hint_kind) - } - _ => bug!(), - }; - let datum = Datum::new(llval, binding_info.ty, lvalue); - call_lifetime_start(bcx, llbinding); - bcx = datum.store_to(bcx, llbinding); - if let Some(cs) = cs { - bcx.fcx.schedule_lifetime_end(cs, llbinding); - } - - (llbinding, false) - }, - - // By value move bindings: load from the ptr into the matched value - TrByMoveRef => (Load(bcx, binding_info.llmatch), true), - - // By ref binding: use the ptr into the matched value - TrByRef => (binding_info.llmatch, true), - }; - - - // A local that aliases some other state must be zeroed, since - // the other state (e.g. some parent data that we matched - // into) will still have its subcomponents (such as this - // local) destructed at the end of the parent's scope. Longer - // term, we will properly map such parents to the set of - // unique drop flags for its fragments. - let hint_kind = if aliases_other_state { - HintKind::ZeroAndMaintain - } else { - HintKind::DontZeroJustUse - }; - let lvalue = Lvalue::new_with_hint("_match::insert_lllocals (local)", - bcx, - binding_info.id, - hint_kind); - let datum = Datum::new(llval, binding_info.ty, lvalue); - if let Some(cs) = cs { - let opt_datum = lvalue.dropflag_hint(bcx); - bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch); - bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty, opt_datum); - } - - debug!("binding {} to {:?}", binding_info.id, Value(llval)); - bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum); - debuginfo::create_match_binding_metadata(bcx, name, binding_info); - } - bcx -} - -fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - guard_expr: &hir::Expr, - data: &ArmData<'p, 'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - vals: &[MatchInput], - chk: &FailureHandler, - has_genuine_default: bool) - -> Block<'blk, 'tcx> { - debug!("compile_guard(bcx={}, guard_expr={:?}, m={:?}, vals={:?})", - bcx.to_str(), guard_expr, m, vals); - let _indenter = indenter(); - - let mut bcx = insert_lllocals(bcx, &data.bindings_map, None); - - let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr)); - let val = val.to_llbool(bcx); - - for (_, &binding_info) in &data.bindings_map { - if let Some(llbinding) = binding_info.trmode.alloca_if_copy() { - call_lifetime_end(bcx, llbinding) - } - } - - for (_, &binding_info) in &data.bindings_map { - bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id); - } - - with_cond(bcx, Not(bcx, val, guard_expr.debug_loc()), |bcx| { - for (_, &binding_info) in &data.bindings_map { - call_lifetime_end(bcx, binding_info.llmatch); - } - match chk { - // If the default arm is the only one left, move on to the next - // condition explicitly rather than (possibly) falling back to - // the default arm. - &JumpToBasicBlock(_) if m.len() == 1 && has_genuine_default => { - chk.handle_fail(bcx); - } - _ => { - compile_submatch(bcx, m, vals, chk, has_genuine_default); - } - }; - bcx - }) -} - -fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - vals: &[MatchInput], - chk: &FailureHandler, - has_genuine_default: bool) { - debug!("compile_submatch(bcx={}, m={:?}, vals=[{:?}])", - bcx.to_str(), m, vals); - let _indenter = indenter(); - let _icx = push_ctxt("match::compile_submatch"); - let mut bcx = bcx; - if m.is_empty() { - if chk.is_fallible() { - chk.handle_fail(bcx); - } - return; - } - - let tcx = bcx.tcx(); - let def_map = &tcx.def_map; - match pick_column_to_specialize(def_map, m) { - Some(col) => { - let val = vals[col]; - if has_nested_bindings(m, col) { - let expanded = expand_nested_bindings(bcx, m, col, val); - compile_submatch_continue(bcx, - &expanded[..], - vals, - chk, - col, - val, - has_genuine_default) - } else { - compile_submatch_continue(bcx, m, vals, chk, col, val, has_genuine_default) - } - } - None => { - let data = &m[0].data; - for &(ref name, ref value_ptr) in &m[0].bound_ptrs { - let binfo = *data.bindings_map.get(name).unwrap(); - call_lifetime_start(bcx, binfo.llmatch); - if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) { - expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch); - } - else { - Store(bcx, *value_ptr, binfo.llmatch); - } - } - match data.arm.guard { - Some(ref guard_expr) => { - bcx = compile_guard(bcx, - &guard_expr, - m[0].data, - &m[1..m.len()], - vals, - chk, - has_genuine_default); - } - _ => () - } - Br(bcx, data.bodycx.llbb, DebugLoc::None); - } - } -} - -fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], - vals: &[MatchInput], - chk: &FailureHandler, - col: usize, - val: MatchInput, - has_genuine_default: bool) { - let fcx = bcx.fcx; - let tcx = bcx.tcx(); - - let mut vals_left = vals[0..col].to_vec(); - vals_left.extend_from_slice(&vals[col + 1..]); - let ccx = bcx.fcx.ccx; - - // Find a real id (we're adding placeholder wildcard patterns, but - // each column is guaranteed to have at least one real pattern) - let pat_id = m.iter().map(|br| br.pats[col].id) - .find(|&id| id != DUMMY_NODE_ID) - .unwrap_or(DUMMY_NODE_ID); - - let left_ty = if pat_id == DUMMY_NODE_ID { - tcx.mk_nil() - } else { - node_id_type(bcx, pat_id) - }; - - let mcx = check_match::MatchCheckCtxt { - tcx: bcx.tcx(), - param_env: bcx.tcx().empty_parameter_environment(), - }; - let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) { - let repr = adt::represent_type(bcx.ccx(), left_ty); - let arg_count = adt::num_args(&repr, Disr(0)); - let (arg_count, struct_val) = if type_is_sized(bcx.tcx(), left_ty) { - (arg_count, val.val) - } else { - // For an unsized ADT (i.e. DST struct), we need to treat - // the last field specially: instead of simply passing a - // ValueRef pointing to that field, as with all the others, - // we skip it and instead construct a 'fat ptr' below. - (arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val.val))) - }; - let mut field_vals: Vec = (0..arg_count).map(|ix| - // By definition, these are all sized - adt::trans_field_ptr(bcx, &repr, adt::MaybeSizedValue::sized(struct_val), Disr(0), ix) - ).collect(); - - match left_ty.sty { - ty::TyStruct(def, substs) if !type_is_sized(bcx.tcx(), left_ty) => { - // The last field is technically unsized but - // since we can only ever match that field behind - // a reference we construct a fat ptr here. - let unsized_ty = def.struct_variant().fields.last().map(|field| { - monomorphize::field_ty(bcx.tcx(), substs, field) - }).unwrap(); - let scratch = alloc_ty(bcx, unsized_ty, "__struct_field_fat_ptr"); - - let meta = Load(bcx, expr::get_meta(bcx, val.val)); - let struct_val = adt::MaybeSizedValue::unsized_(struct_val, meta); - - let data = adt::trans_field_ptr(bcx, &repr, struct_val, Disr(0), arg_count); - Store(bcx, data, expr::get_dataptr(bcx, scratch)); - Store(bcx, meta, expr::get_meta(bcx, scratch)); - field_vals.push(scratch); - } - _ => {} - } - Some(field_vals) - } else if any_uniq_pat(m, col) || any_region_pat(m, col) { - let ptr = if type_is_fat_ptr(bcx.tcx(), left_ty) { - val.val - } else { - Load(bcx, val.val) - }; - Some(vec!(ptr)) - } else { - match left_ty.sty { - ty::TyArray(_, n) => { - let args = extract_vec_elems(bcx, left_ty, n, 0, val); - Some(args.vals) - } - _ => None - } - }; - match adt_vals { - Some(field_vals) => { - let pats = enter_match(bcx, m, col, val, |pats| - check_match::specialize(&mcx, pats, - &Constructor::Single, col, - field_vals.len()) - ); - let mut vals: Vec<_> = field_vals.into_iter() - .map(|v|MatchInput::from_val(v)) - .collect(); - vals.extend_from_slice(&vals_left); - compile_submatch(bcx, &pats, &vals, chk, has_genuine_default); - return; - } - _ => () - } - - // Decide what kind of branch we need - let opts = get_branches(bcx, m, col); - debug!("options={:?}", opts); - let mut kind = NoBranch; - let mut test_val = val.val; - debug!("test_val={:?}", Value(test_val)); - if !opts.is_empty() { - match opts[0] { - ConstantValue(..) | ConstantRange(..) => { - test_val = load_if_immediate(bcx, val.val, left_ty); - kind = if left_ty.is_integral() { - Switch - } else { - Compare - }; - } - Variant(_, ref repr, _, _) => { - let (the_kind, val_opt) = adt::trans_switch(bcx, &repr, - val.val, true); - kind = the_kind; - if let Some(tval) = val_opt { test_val = tval; } - } - SliceLengthEqual(..) | SliceLengthGreaterOrEqual(..) => { - let (_, len) = tvec::get_base_and_len(bcx, val.val, left_ty); - test_val = len; - kind = Switch; - } - } - } - for o in &opts { - match *o { - ConstantRange(..) => { kind = Compare; break }, - SliceLengthGreaterOrEqual(..) => { kind = CompareSliceLength; break }, - _ => () - } - } - let else_cx = match kind { - NoBranch | Single => bcx, - _ => bcx.fcx.new_temp_block("match_else") - }; - let sw = if kind == Switch { - build::Switch(bcx, test_val, else_cx.llbb, opts.len()) - } else { - C_int(ccx, 0) // Placeholder for when not using a switch - }; - - let defaults = enter_default(else_cx, m, col, val); - let exhaustive = chk.is_infallible() && defaults.is_empty(); - let len = opts.len(); - - if exhaustive && kind == Switch { - build::Unreachable(else_cx); - } - - // Compile subtrees for each option - for (i, opt) in opts.iter().enumerate() { - // In some cases of range and vector pattern matching, we need to - // override the failure case so that instead of failing, it proceeds - // to try more matching. branch_chk, then, is the proper failure case - // for the current conditional branch. - let mut branch_chk = None; - let mut opt_cx = else_cx; - let debug_loc = opt.debug_loc(); - - if kind == Switch || !exhaustive || i + 1 < len { - opt_cx = bcx.fcx.new_temp_block("match_case"); - match kind { - Single => Br(bcx, opt_cx.llbb, debug_loc), - Switch => { - match opt.trans(bcx) { - SingleResult(r) => { - AddCase(sw, r.val, opt_cx.llbb); - bcx = r.bcx; - } - _ => { - bug!( - "in compile_submatch, expected \ - opt.trans() to return a SingleResult") - } - } - } - Compare | CompareSliceLength => { - let t = if kind == Compare { - left_ty - } else { - tcx.types.usize // vector length - }; - let Result { bcx: after_cx, val: matches } = { - match opt.trans(bcx) { - SingleResult(Result { bcx, val }) => { - compare_values(bcx, test_val, val, t, debug_loc) - } - RangeResult(Result { val: vbegin, .. }, - Result { bcx, val: vend }) => { - let llge = compare_scalar_types(bcx, test_val, vbegin, - t, hir::BiGe, debug_loc); - let llle = compare_scalar_types(bcx, test_val, vend, - t, hir::BiLe, debug_loc); - Result::new(bcx, And(bcx, llge, llle, DebugLoc::None)) - } - LowerBound(Result { bcx, val }) => { - Result::new(bcx, compare_scalar_types(bcx, test_val, - val, t, hir::BiGe, - debug_loc)) - } - } - }; - bcx = fcx.new_temp_block("compare_next"); - - // If none of the sub-cases match, and the current condition - // is guarded or has multiple patterns, move on to the next - // condition, if there is any, rather than falling back to - // the default. - let guarded = m[i].data.arm.guard.is_some(); - let multi_pats = m[i].pats.len() > 1; - if i + 1 < len && (guarded || multi_pats || kind == CompareSliceLength) { - branch_chk = Some(JumpToBasicBlock(bcx.llbb)); - } - CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb, debug_loc); - } - _ => () - } - } else if kind == Compare || kind == CompareSliceLength { - Br(bcx, else_cx.llbb, debug_loc); - } - - let mut size = 0; - let mut unpacked = Vec::new(); - match *opt { - Variant(disr_val, ref repr, _, _) => { - let ExtractedBlock {vals: argvals, bcx: new_bcx} = - extract_variant_args(opt_cx, &repr, disr_val, val); - size = argvals.len(); - unpacked = argvals; - opt_cx = new_bcx; - } - SliceLengthEqual(len, _) => { - let args = extract_vec_elems(opt_cx, left_ty, len, 0, val); - size = args.vals.len(); - unpacked = args.vals.clone(); - opt_cx = args.bcx; - } - SliceLengthGreaterOrEqual(before, after, _) => { - let args = extract_vec_elems(opt_cx, left_ty, before, after, val); - size = args.vals.len(); - unpacked = args.vals.clone(); - opt_cx = args.bcx; - } - ConstantValue(..) | ConstantRange(..) => () - } - let opt_ms = enter_opt(opt_cx, pat_id, m, opt, col, size, val); - let mut opt_vals: Vec<_> = unpacked.into_iter() - .map(|v|MatchInput::from_val(v)) - .collect(); - opt_vals.extend_from_slice(&vals_left[..]); - compile_submatch(opt_cx, - &opt_ms[..], - &opt_vals[..], - branch_chk.as_ref().unwrap_or(chk), - has_genuine_default); - } - - // Compile the fall-through case, if any - if !exhaustive && kind != Single { - if kind == Compare || kind == CompareSliceLength { - Br(bcx, else_cx.llbb, DebugLoc::None); - } - match chk { - // If there is only one default arm left, move on to the next - // condition explicitly rather than (eventually) falling back to - // the last default arm. - &JumpToBasicBlock(_) if defaults.len() == 1 && has_genuine_default => { - chk.handle_fail(else_cx); - } - _ => { - compile_submatch(else_cx, - &defaults[..], - &vals_left[..], - chk, - has_genuine_default); - } - } - } -} - -pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - match_expr: &hir::Expr, - discr_expr: &hir::Expr, - arms: &[hir::Arm], - dest: Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("match::trans_match"); - trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest) -} - -/// Checks whether the binding in `discr` is assigned to anywhere in the expression `body` -fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool { - let (vid, field) = match discr.node { - hir::ExprPath(..) => match bcx.tcx().expect_def(discr.id) { - Def::Local(_, vid) | Def::Upvar(_, vid, _, _) => (vid, None), - _ => return false - }, - hir::ExprField(ref base, field) => { - let vid = match bcx.tcx().expect_def_or_none(base.id) { - Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid, - _ => return false - }; - (vid, Some(mc::NamedField(field.node))) - }, - hir::ExprTupField(ref base, field) => { - let vid = match bcx.tcx().expect_def_or_none(base.id) { - Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid, - _ => return false - }; - (vid, Some(mc::PositionalField(field.node))) - }, - _ => return false - }; - - let mut rc = ReassignmentChecker { - node: vid, - field: field, - reassigned: false - }; - bcx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| { - let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx); - visitor.walk_expr(body); - }); - rc.reassigned -} - -struct ReassignmentChecker { - node: ast::NodeId, - field: Option, - reassigned: bool -} - -// Determine if the expression we're matching on is reassigned to within -// the body of the match's arm. -// We only care for the `mutate` callback since this check only matters -// for cases where the matched value is moved. -impl<'tcx> euv::Delegate<'tcx> for ReassignmentChecker { - fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {} - fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {} - fn consume_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::ConsumeMode) {} - fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region, - _: ty::BorrowKind, _: euv::LoanCause) {} - fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} - - fn mutate(&mut self, _: ast::NodeId, _: Span, cmt: mc::cmt, _: euv::MutateMode) { - let cmt_id = |cmt: &mc::cmt| match cmt.cat { - Categorization::Upvar(mc::Upvar { id: ty::UpvarId { var_id: vid, ..}, ..}) | - Categorization::Local(vid) => Some(vid), - Categorization::Interior(ref base_cmt, mc::InteriorField(_)) => Some(base_cmt.id), - _ => None - }; - match cmt.cat { - Categorization::Upvar(mc::Upvar { id: ty::UpvarId { var_id: vid, .. }, .. }) | - Categorization::Local(vid) => self.reassigned |= self.node == vid, - ref cat => { - let mut cat = cat; - while let &Categorization::Interior(ref base_cmt, mc::InteriorField(field)) = cat { - if let Some(vid) = cmt_id(base_cmt) { - if self.node == vid && (self.field.is_none() || self.field == Some(field)) { - self.reassigned = true; - return; - } - } - cat = &base_cmt.cat; - } - } - } - } -} - -fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &hir::Pat, - discr: &hir::Expr, body: &hir::Expr) - -> BindingsMap<'tcx> { - // Create the bindings map, which is a mapping from each binding name - // to an alloca() that will be the value for that local variable. - // Note that we use the names because each binding will have many ids - // from the various alternatives. - let ccx = bcx.ccx(); - let reassigned = is_discr_reassigned(bcx, discr, body); - let mut bindings_map = FnvHashMap(); - pat_bindings(&pat, |bm, p_id, span, path1| { - let name = path1.node; - let variable_ty = node_id_type(bcx, p_id); - let llvariable_ty = type_of::type_of(ccx, variable_ty); - let tcx = bcx.tcx(); - let param_env = tcx.empty_parameter_environment(); - - let llmatch; - let trmode; - let moves_by_default = variable_ty.moves_by_default(tcx, ¶m_env, span); - match bm { - hir::BindByValue(_) if !moves_by_default || reassigned => - { - llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch"); - let llcopy = alloca(bcx, llvariable_ty, &bcx.name(name)); - trmode = if moves_by_default { - TrByMoveIntoCopy(llcopy) - } else { - TrByCopy(llcopy) - }; - } - hir::BindByValue(_) => { - // in this case, the final type of the variable will be T, - // but during matching we need to store a *T as explained - // above - llmatch = alloca(bcx, llvariable_ty.ptr_to(), &bcx.name(name)); - trmode = TrByMoveRef; - } - hir::BindByRef(_) => { - llmatch = alloca(bcx, llvariable_ty, &bcx.name(name)); - trmode = TrByRef; - } - }; - bindings_map.insert(name, BindingInfo { - llmatch: llmatch, - trmode: trmode, - id: p_id, - span: span, - ty: variable_ty - }); - }); - return bindings_map; -} - -fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, - match_id: ast::NodeId, - discr_expr: &hir::Expr, - arms: &[hir::Arm], - dest: Dest) -> Block<'blk, 'tcx> { - let _icx = push_ctxt("match::trans_match_inner"); - let fcx = scope_cx.fcx; - let mut bcx = scope_cx; - let tcx = bcx.tcx(); - - let discr_datum = unpack_datum!(bcx, expr::trans_to_lvalue(bcx, discr_expr, - "match")); - if bcx.unreachable.get() { - return bcx; - } - - let t = node_id_type(bcx, discr_expr.id); - let chk = if t.is_uninhabited(tcx) { - Unreachable - } else { - Infallible - }; - - let arm_datas: Vec = arms.iter().map(|arm| ArmData { - bodycx: fcx.new_id_block("case_body", arm.body.id), - arm: arm, - bindings_map: create_bindings_map(bcx, &arm.pats[0], discr_expr, &arm.body) - }).collect(); - - let mut pat_renaming_map = if scope_cx.sess().opts.debuginfo != NoDebugInfo { - Some(FnvHashMap()) - } else { - None - }; - - let arm_pats: Vec>> = { - let mut static_inliner = StaticInliner::new(scope_cx.tcx(), - pat_renaming_map.as_mut()); - arm_datas.iter().map(|arm_data| { - arm_data.arm.pats.iter().map(|p| static_inliner.fold_pat((*p).clone())).collect() - }).collect() - }; - - let mut matches = Vec::new(); - for (arm_data, pats) in arm_datas.iter().zip(&arm_pats) { - matches.extend(pats.iter().map(|p| Match { - pats: vec![&p], - data: arm_data, - bound_ptrs: Vec::new(), - pat_renaming_map: pat_renaming_map.as_ref() - })); - } - - // `compile_submatch` works one column of arm patterns a time and - // then peels that column off. So as we progress, it may become - // impossible to tell whether we have a genuine default arm, i.e. - // `_ => foo` or not. Sometimes it is important to know that in order - // to decide whether moving on to the next condition or falling back - // to the default arm. - let has_default = arms.last().map_or(false, |arm| { - arm.pats.len() == 1 - && arm.pats.last().unwrap().node == PatKind::Wild - }); - - compile_submatch(bcx, &matches[..], &[discr_datum.match_input()], &chk, has_default); - - let mut arm_cxs = Vec::new(); - for arm_data in &arm_datas { - let mut bcx = arm_data.bodycx; - - // insert bindings into the lllocals map and add cleanups - let cs = fcx.push_custom_cleanup_scope(); - bcx = insert_lllocals(bcx, &arm_data.bindings_map, Some(cleanup::CustomScope(cs))); - bcx = expr::trans_into(bcx, &arm_data.arm.body, dest); - bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cs); - arm_cxs.push(bcx); - } - - bcx = scope_cx.fcx.join_blocks(match_id, &arm_cxs[..]); - return bcx; -} - -/// Generates code for a local variable declaration like `let ;` or `let = -/// `. -pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - local: &hir::Local) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("match::store_local"); - let mut bcx = bcx; - let tcx = bcx.tcx(); - let pat = &local.pat; - - fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - pat: &hir::Pat) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("create_dummy_locals"); - // create dummy memory for the variables if we have no - // value to store into them immediately - let tcx = bcx.tcx(); - pat_bindings(pat, |_, p_id, _, path1| { - let scope = cleanup::var_scope(tcx, p_id); - bcx = mk_binding_alloca( - bcx, p_id, path1.node, scope, (), - "_match::store_local::create_dummy_locals", - |(), bcx, Datum { val: llval, ty, kind }| { - // Dummy-locals start out uninitialized, so set their - // drop-flag hints (if any) to "moved." - if let Some(hint) = kind.dropflag_hint(bcx) { - let moved_hint = adt::DTOR_MOVED_HINT; - debug!("store moved_hint={} for hint={:?}, uninitialized dummy", - moved_hint, hint); - Store(bcx, C_u8(bcx.fcx.ccx, moved_hint), hint.to_value().value()); - } - - if kind.drop_flag_info.must_zero() { - // if no drop-flag hint, or the hint requires - // we maintain the embedded drop-flag, then - // mark embedded drop-flag(s) as moved - // (i.e. "already dropped"). - drop_done_fill_mem(bcx, llval, ty); - } - bcx - }); - }); - bcx - } - - match local.init { - Some(ref init_expr) => { - // Optimize the "let x = expr" case. This just writes - // the result of evaluating `expr` directly into the alloca - // for `x`. Often the general path results in similar or the - // same code post-optimization, but not always. In particular, - // in unsafe code, you can have expressions like - // - // let x = intrinsics::uninit(); - // - // In such cases, the more general path is unsafe, because - // it assumes it is matching against a valid value. - if let Some(name) = simple_name(pat) { - let var_scope = cleanup::var_scope(tcx, local.id); - return mk_binding_alloca( - bcx, pat.id, name, var_scope, (), - "_match::store_local", - |(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &init_expr, - expr::SaveIn(v))); - } - - // General path. - let init_datum = - unpack_datum!(bcx, expr::trans_to_lvalue(bcx, &init_expr, "let")); - if bcx.sess().asm_comments() { - add_comment(bcx, "creating zeroable ref llval"); - } - let var_scope = cleanup::var_scope(tcx, local.id); - bind_irrefutable_pat(bcx, pat, init_datum.match_input(), var_scope) - } - None => { - create_dummy_locals(bcx, pat) - } - } -} - -fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, - p_id: ast::NodeId, - name: ast::Name, - cleanup_scope: cleanup::ScopeId, - arg: A, - caller_name: &'static str, - populate: F) - -> Block<'blk, 'tcx> where - F: FnOnce(A, Block<'blk, 'tcx>, Datum<'tcx, Lvalue>) -> Block<'blk, 'tcx>, -{ - let var_ty = node_id_type(bcx, p_id); - - // Allocate memory on stack for the binding. - let llval = alloc_ty(bcx, var_ty, &bcx.name(name)); - let lvalue = Lvalue::new_with_hint(caller_name, bcx, p_id, HintKind::DontZeroJustUse); - let datum = Datum::new(llval, var_ty, lvalue); - - debug!("mk_binding_alloca cleanup_scope={:?} llval={:?} var_ty={:?}", - cleanup_scope, Value(llval), var_ty); - - // Subtle: be sure that we *populate* the memory *before* - // we schedule the cleanup. - call_lifetime_start(bcx, llval); - let bcx = populate(arg, bcx, datum); - bcx.fcx.schedule_lifetime_end(cleanup_scope, llval); - bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx)); - - // Now that memory is initialized and has cleanup scheduled, - // insert datum into the local variable map. - bcx.fcx.lllocals.borrow_mut().insert(p_id, datum); - bcx -} - -/// A simple version of the pattern matching code that only handles -/// irrefutable patterns. This is used in let/argument patterns, -/// not in match statements. Unifying this code with the code above -/// sounds nice, but in practice it produces very inefficient code, -/// since the match code is so much more general. In most cases, -/// LLVM is able to optimize the code, but it causes longer compile -/// times and makes the generated code nigh impossible to read. -/// -/// # Arguments -/// - bcx: starting basic block context -/// - pat: the irrefutable pattern being matched. -/// - val: the value being matched -- must be an lvalue (by ref, with cleanup) -pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - pat: &hir::Pat, - val: MatchInput, - cleanup_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { - debug!("bind_irrefutable_pat(bcx={}, pat={:?}, val={:?})", - bcx.to_str(), pat, val); - - if bcx.sess().asm_comments() { - add_comment(bcx, &format!("bind_irrefutable_pat(pat={:?})", - pat)); - } - - let _indenter = indenter(); - - let _icx = push_ctxt("match::bind_irrefutable_pat"); - let mut bcx = bcx; - let tcx = bcx.tcx(); - let ccx = bcx.ccx(); - match pat.node { - PatKind::Binding(pat_binding_mode, ref path1, ref inner) => { - // Allocate the stack slot where the value of this - // binding will live and place it into the appropriate - // map. - bcx = mk_binding_alloca(bcx, pat.id, path1.node, cleanup_scope, (), - "_match::bind_irrefutable_pat", - |(), bcx, Datum { val: llval, ty, kind: _ }| { - match pat_binding_mode { - hir::BindByValue(_) => { - // By value binding: move the value that `val` - // points at into the binding's stack slot. - let d = val.to_datum(ty); - d.store_to(bcx, llval) - } - - hir::BindByRef(_) => { - // By ref binding: the value of the variable - // is the pointer `val` itself or fat pointer referenced by `val` - if type_is_fat_ptr(bcx.tcx(), ty) { - expr::copy_fat_ptr(bcx, val.val, llval); - } - else { - Store(bcx, val.val, llval); - } - - bcx - } - } - }); - - if let Some(ref inner_pat) = *inner { - bcx = bind_irrefutable_pat(bcx, &inner_pat, val, cleanup_scope); - } - } - PatKind::TupleStruct(_, ref sub_pats, ddpos) => { - match bcx.tcx().expect_def(pat.id) { - Def::Variant(enum_id, var_id) => { - let repr = adt::represent_node(bcx, pat.id); - let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id); - let args = extract_variant_args(bcx, - &repr, - Disr::from(vinfo.disr_val), - val); - for (i, subpat) in sub_pats.iter() - .enumerate_and_adjust(vinfo.fields.len(), ddpos) { - bcx = bind_irrefutable_pat( - bcx, - subpat, - MatchInput::from_val(args.vals[i]), - cleanup_scope); - } - } - Def::Struct(..) => { - let expected_len = match *ccx.tcx().pat_ty(&pat) { - ty::TyS{sty: ty::TyStruct(adt_def, _), ..} => { - adt_def.struct_variant().fields.len() - } - ref ty => { - span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty); - } - }; - - let repr = adt::represent_node(bcx, pat.id); - let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in sub_pats.iter().enumerate_and_adjust(expected_len, ddpos) { - let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); - bcx = bind_irrefutable_pat( - bcx, - &elem, - MatchInput::from_val(fldptr), - cleanup_scope); - } - } - _ => { - // Nothing to do here. - } - } - } - PatKind::Struct(_, ref fields, _) => { - let tcx = bcx.tcx(); - let pat_ty = node_id_type(bcx, pat.id); - let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); - let pat_v = VariantInfo::of_node(tcx, pat_ty, pat.id); - - let val = if type_is_sized(tcx, pat_ty) { - adt::MaybeSizedValue::sized(val.val) - } else { - let data = Load(bcx, expr::get_dataptr(bcx, val.val)); - let meta = Load(bcx, expr::get_meta(bcx, val.val)); - adt::MaybeSizedValue::unsized_(data, meta) - }; - - for f in fields { - let name = f.node.name; - let field_idx = pat_v.field_index(name); - let mut fldptr = adt::trans_field_ptr( - bcx, - &pat_repr, - val, - pat_v.discr, - field_idx); - - let fty = pat_v.fields[field_idx].1; - // If it's not sized, then construct a fat pointer instead of - // a regular one - if !type_is_sized(tcx, fty) { - let scratch = alloc_ty(bcx, fty, "__struct_field_fat_ptr"); - debug!("Creating fat pointer {:?}", Value(scratch)); - Store(bcx, fldptr, expr::get_dataptr(bcx, scratch)); - Store(bcx, val.meta, expr::get_meta(bcx, scratch)); - fldptr = scratch; - } - bcx = bind_irrefutable_pat(bcx, - &f.node.pat, - MatchInput::from_val(fldptr), - cleanup_scope); - } - } - PatKind::Tuple(ref elems, ddpos) => { - match tcx.node_id_to_type(pat.id).sty { - ty::TyTuple(ref tys) => { - let repr = adt::represent_node(bcx, pat.id); - let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate_and_adjust(tys.len(), ddpos) { - let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); - bcx = bind_irrefutable_pat( - bcx, - &elem, - MatchInput::from_val(fldptr), - cleanup_scope); - } - } - ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), - } - } - PatKind::Box(ref inner) => { - let pat_ty = node_id_type(bcx, inner.id); - // Pass along DSTs as fat pointers. - let val = if type_is_fat_ptr(tcx, pat_ty) { - // We need to check for this, as the pattern could be binding - // a fat pointer by-value. - if let PatKind::Binding(hir::BindByRef(..),_,_) = inner.node { - val.val - } else { - Load(bcx, val.val) - } - } else if type_is_sized(tcx, pat_ty) { - Load(bcx, val.val) - } else { - val.val - }; - bcx = bind_irrefutable_pat( - bcx, &inner, MatchInput::from_val(val), cleanup_scope); - } - PatKind::Ref(ref inner, _) => { - let pat_ty = node_id_type(bcx, inner.id); - // Pass along DSTs as fat pointers. - let val = if type_is_fat_ptr(tcx, pat_ty) { - // We need to check for this, as the pattern could be binding - // a fat pointer by-value. - if let PatKind::Binding(hir::BindByRef(..),_,_) = inner.node { - val.val - } else { - Load(bcx, val.val) - } - } else if type_is_sized(tcx, pat_ty) { - Load(bcx, val.val) - } else { - val.val - }; - bcx = bind_irrefutable_pat( - bcx, - &inner, - MatchInput::from_val(val), - cleanup_scope); - } - PatKind::Vec(ref before, ref slice, ref after) => { - let pat_ty = node_id_type(bcx, pat.id); - let mut extracted = extract_vec_elems(bcx, pat_ty, before.len(), after.len(), val); - match slice { - &Some(_) => { - extracted.vals.insert( - before.len(), - bind_subslice_pat(bcx, pat.id, val, before.len(), after.len()) - ); - } - &None => () - } - bcx = before - .iter() - .chain(slice.iter()) - .chain(after.iter()) - .zip(extracted.vals) - .fold(bcx, |bcx, (inner, elem)| { - bind_irrefutable_pat( - bcx, - &inner, - MatchInput::from_val(elem), - cleanup_scope) - }); - } - PatKind::Path(..) | PatKind::Wild | - PatKind::Lit(..) | PatKind::Range(..) => () - } - return bcx; -} diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index d48ec98a20dfb..c0841bb167341 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -53,14 +53,9 @@ use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; use syntax::attr; use syntax::attr::IntType; -use _match; use abi::FAT_PTR_ADDR; -use base::InitAlloca; use build::*; -use cleanup; -use cleanup::CleanupMethods; use common::*; -use datum; use debuginfo::DebugLoc; use glue; use machine; @@ -69,6 +64,12 @@ use type_::Type; use type_of; use value::Value; +#[derive(Copy, Clone, PartialEq)] +pub enum BranchKind { + Switch, + Single +} + type Hint = attr::ReprAttr; // Representation of the context surrounding an unsized type. I want @@ -178,14 +179,6 @@ impl MaybeSizedValue { } } -/// Convenience for `represent_type`. There should probably be more or -/// these, for places in trans where the `Ty` isn't directly -/// available. -pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - node: ast::NodeId) -> Rc> { - represent_type(bcx.ccx(), node_id_type(bcx, node)) -} - /// Decides how to represent a given type. pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) @@ -201,38 +194,8 @@ pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, repr } -const fn repeat_u8_as_u32(val: u8) -> u32 { - (val as u32) << 24 | (val as u32) << 16 | (val as u32) << 8 | val as u32 -} - -const fn repeat_u8_as_u64(val: u8) -> u64 { - (repeat_u8_as_u32(val) as u64) << 32 | repeat_u8_as_u32(val) as u64 -} - -/// `DTOR_NEEDED_HINT` is a stack-local hint that just means -/// "we do not know whether the destructor has run or not; check the -/// drop-flag embedded in the value itself." -pub const DTOR_NEEDED_HINT: u8 = 0x3d; - -/// `DTOR_MOVED_HINT` is a stack-local hint that means "this value has -/// definitely been moved; you do not need to run its destructor." -/// -/// (However, for now, such values may still end up being explicitly -/// zeroed by the generated code; this is the distinction between -/// `datum::DropFlagInfo::ZeroAndMaintain` versus -/// `datum::DropFlagInfo::DontZeroJustUse`.) -pub const DTOR_MOVED_HINT: u8 = 0x2d; - -pub const DTOR_NEEDED: u8 = 0xd4; -#[allow(dead_code)] -pub const DTOR_NEEDED_U64: u64 = repeat_u8_as_u64(DTOR_NEEDED); - -pub const DTOR_DONE: u8 = 0x1d; -#[allow(dead_code)] -pub const DTOR_DONE_U64: u64 = repeat_u8_as_u64(DTOR_DONE); - fn dtor_to_init_u8(dtor: bool) -> u8 { - if dtor { DTOR_NEEDED } else { 0 } + if dtor { 1 } else { 0 } } pub trait GetDtorType<'tcx> { fn dtor_type(self) -> Ty<'tcx>; } @@ -240,10 +203,6 @@ impl<'a, 'tcx> GetDtorType<'tcx> for TyCtxt<'a, 'tcx, 'tcx> { fn dtor_type(self) -> Ty<'tcx> { self.types.u8 } } -fn dtor_active(flag: u8) -> bool { - flag != 0 -} - fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Repr<'tcx> { match t.sty { @@ -873,22 +832,19 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>, /// Obtain a representation of the discriminant sufficient to translate /// destructuring; this may or may not involve the actual discriminant. -/// -/// This should ideally be less tightly tied to `_match`. pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, scrutinee: ValueRef, range_assert: bool) - -> (_match::BranchKind, Option) { + -> (BranchKind, Option) { match *r { CEnum(..) | General(..) | RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { - (_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, - range_assert))) + (BranchKind::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, range_assert))) } Univariant(..) => { // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants). - (_match::Single, None) + (BranchKind::Single, None) } } } @@ -1001,21 +957,12 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true), val); } - General(ity, ref cases, dtor) => { - if dtor_active(dtor) { - let ptr = trans_field_ptr(bcx, r, MaybeSizedValue::sized(val), discr, - cases[discr.0 as usize].fields.len() - 2); - Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED), ptr); - } + General(ity, _, _) => { Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true), StructGEP(bcx, val, 0)); } - Univariant(ref st, dtor) => { + Univariant(_, _) => { assert_eq!(discr, Disr(0)); - if dtor_active(dtor) { - Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED), - StructGEP(bcx, val, st.fields.len() - 1)); - } } RawNullablePointer { nndiscr, nnty, ..} => { if discr != nndiscr { @@ -1046,28 +993,6 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) { } } -/// The number of fields in a given case; for use when obtaining this -/// information from the type or definition is less convenient. -pub fn num_args(r: &Repr, discr: Disr) -> usize { - match *r { - CEnum(..) => 0, - Univariant(ref st, dtor) => { - assert_eq!(discr, Disr(0)); - st.fields.len() - (if dtor_active(dtor) { 1 } else { 0 }) - } - General(_, ref cases, dtor) => { - cases[discr.0 as usize].fields.len() - 1 - (if dtor_active(dtor) { 1 } else { 0 }) - } - RawNullablePointer { nndiscr, ref nullfields, .. } => { - if discr == nndiscr { 1 } else { nullfields.len() } - } - StructWrappedNullablePointer { ref nonnull, nndiscr, - ref nullfields, .. } => { - if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() } - } - } -} - /// Access a field, at a point when the value's case is known. pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef { @@ -1218,108 +1143,6 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, bcx.pointercast(byte_ptr, ll_fty.ptr_to()) } -pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - r: &Repr<'tcx>, - value: ValueRef, - mut f: F) - -> Block<'blk, 'tcx> where - F: FnMut(Block<'blk, 'tcx>, &Struct<'tcx>, ValueRef) -> Block<'blk, 'tcx>, -{ - let fcx = bcx.fcx; - match *r { - Univariant(ref st, _) => { - f(bcx, st, value) - } - General(ity, ref cases, _) => { - let ccx = bcx.ccx(); - - // See the comments in trans/base.rs for more information (inside - // iter_structural_ty), but the gist here is that if the enum's - // discriminant is *not* in the range that we're expecting (in which - // case we'll take the fall-through branch on the switch - // instruction) then we can't just optimize this to an Unreachable - // block. - // - // Currently we still have filling drop, so this means that the drop - // glue for enums may be called when the enum has been paved over - // with the "I've been dropped" value. In this case the default - // branch of the switch instruction will actually be taken at - // runtime, so the basic block isn't actually unreachable, so we - // need to make it do something with defined behavior. In this case - // we just return early from the function. - // - // Note that this is also why the `trans_get_discr` below has - // `false` to indicate that loading the discriminant should - // not have a range assert. - let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void"); - RetVoid(ret_void_cx, DebugLoc::None); - - let discr_val = trans_get_discr(bcx, r, value, None, false); - let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len()); - let bcx_next = fcx.new_temp_block("enum-variant-iter-next"); - - for (discr, case) in cases.iter().enumerate() { - let mut variant_cx = fcx.new_temp_block( - &format!("enum-variant-iter-{}", &discr.to_string()) - ); - let rhs_val = C_integral(ll_inttype(ccx, ity), discr as u64, true); - AddCase(llswitch, rhs_val, variant_cx.llbb); - - let fields = case.fields.iter().map(|&ty| - type_of::type_of(bcx.ccx(), ty)).collect::>(); - let real_ty = Type::struct_(ccx, &fields[..], case.packed); - let variant_value = PointerCast(variant_cx, value, real_ty.ptr_to()); - - variant_cx = f(variant_cx, case, variant_value); - Br(variant_cx, bcx_next.llbb, DebugLoc::None); - } - - bcx_next - } - _ => bug!() - } -} - -/// Access the struct drop flag, if present. -pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - r: &Repr<'tcx>, - val: ValueRef) - -> datum::DatumBlock<'blk, 'tcx, datum::Expr> -{ - let tcx = bcx.tcx(); - let ptr_ty = bcx.tcx().mk_imm_ptr(tcx.dtor_type()); - match *r { - Univariant(ref st, dtor) if dtor_active(dtor) => { - let flag_ptr = StructGEP(bcx, val, st.fields.len() - 1); - datum::immediate_rvalue_bcx(bcx, flag_ptr, ptr_ty).to_expr_datumblock() - } - General(_, _, dtor) if dtor_active(dtor) => { - let fcx = bcx.fcx; - let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum( - bcx, tcx.dtor_type(), "drop_flag", - InitAlloca::Uninit("drop flag itself has no dtor"), - cleanup::CustomScope(custom_cleanup_scope), |bcx, _| { - debug!("no-op populate call for trans_drop_flag_ptr on dtor_type={:?}", - tcx.dtor_type()); - bcx - } - )); - bcx = fold_variants(bcx, r, val, |variant_cx, st, value| { - let ptr = struct_field_ptr(&variant_cx.build(), st, - MaybeSizedValue::sized(value), - (st.fields.len() - 1), false); - datum::Datum::new(ptr, ptr_ty, datum::Lvalue::new("adt::trans_drop_flag_ptr")) - .store_to(variant_cx, scratch.val) - }); - let expr_datum = scratch.to_expr_datum(); - fcx.pop_custom_cleanup_scope(custom_cleanup_scope); - datum::DatumBlock::new(bcx, expr_datum) - } - _ => bug!("tried to get drop flag of non-droppable type") - } -} - /// Construct a constant value, suitable for initializing a /// GlobalVariable, given a case and constant values for its fields. /// Note that this may have a different LLVM type (and different @@ -1458,28 +1281,6 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef { #[inline] fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a } -/// Get the discriminant of a constant value. -pub fn const_get_discrim(r: &Repr, val: ValueRef) -> Disr { - match *r { - CEnum(ity, _, _) => { - match ity { - attr::SignedInt(..) => Disr(const_to_int(val) as u64), - attr::UnsignedInt(..) => Disr(const_to_uint(val)), - } - } - General(ity, _, _) => { - match ity { - attr::SignedInt(..) => Disr(const_to_int(const_get_elt(val, &[0])) as u64), - attr::UnsignedInt(..) => Disr(const_to_uint(const_get_elt(val, &[0]))) - } - } - Univariant(..) => Disr(0), - RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { - bug!("const discrim access of non c-like enum") - } - } -} - /// Extract a field of a constant value, as appropriate for its /// representation. /// diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 5514fb0f4efc3..308118b1fbc6c 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -14,28 +14,29 @@ use llvm::{self, ValueRef}; use base; use build::*; use common::*; -use datum::{Datum, Lvalue}; use type_of; use type_::Type; -use rustc::hir as ast; +use rustc::hir; +use rustc::ty::Ty; + use std::ffi::CString; use syntax::ast::AsmDialect; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - ia: &ast::InlineAsm, - outputs: Vec>, + ia: &hir::InlineAsm, + outputs: Vec<(ValueRef, Ty<'tcx>)>, mut inputs: Vec) { let mut ext_constraints = vec![]; let mut output_types = vec![]; // Prepare the output operands let mut indirect_outputs = vec![]; - for (i, (out, out_datum)) in ia.outputs.iter().zip(&outputs).enumerate() { + for (i, (out, &(val, ty))) in ia.outputs.iter().zip(&outputs).enumerate() { let val = if out.is_rw || out.is_indirect { - Some(base::load_ty(bcx, out_datum.val, out_datum.ty)) + Some(base::load_ty(bcx, val, ty)) } else { None }; @@ -46,7 +47,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, if out.is_indirect { indirect_outputs.push(val.unwrap()); } else { - output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty)); + output_types.push(type_of::type_of(bcx.ccx(), ty)); } } if !indirect_outputs.is_empty() { @@ -100,9 +101,9 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Again, based on how many outputs we have let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect); - for (i, (_, datum)) in outputs.enumerate() { + for (i, (_, &(val, _))) in outputs.enumerate() { let v = if num_outputs == 1 { r } else { ExtractValue(bcx, r, i) }; - Store(bcx, v, datum.val); + Store(bcx, v, val); } // Store expn_id in a metadata node so we can map LLVM errors diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a1f3e4e5b59c6..2f215ab113513 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -33,12 +33,10 @@ use super::ModuleTranslation; use assert_module_sources; use back::link; use back::linker::LinkerInfo; -use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; +use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; -use rustc::cfg; use rustc::hir::def_id::DefId; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; -use rustc::hir::pat_util::simple_name; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -47,35 +45,27 @@ use rustc::dep_graph::{DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::mir::mir_map::MirMap; -use rustc_data_structures::graph::OUTGOING; +use session::config::{self, NoDebugInfo}; use rustc_incremental::IncrementalHashesMap; -use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; -use _match; use abi::{self, Abi, FnType}; use adt; use attributes; use build::*; use builder::{Builder, noname}; -use callee::{Callee, CallArgs, ArgExprs, ArgVals}; -use cleanup::{self, CleanupMethods, DropHint}; -use closure; -use common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral}; +use callee::{Callee}; +use common::{Block, C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; use common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; -use common::{CrateContext, DropFlagHintsMap, Field, FunctionContext}; -use common::{Result, NodeIdAndSpan, VariantInfo}; -use common::{node_id_type, fulfill_obligation}; -use common::{type_is_immediate, type_is_zero_size, val_ty}; +use common::{CrateContext, Field, FunctionContext}; +use common::{Result, VariantInfo}; +use common::{fulfill_obligation}; +use common::{type_is_zero_size, val_ty}; use common; use consts; use context::{SharedCrateContext, CrateContextList}; -use controlflow; -use datum; -use debuginfo::{self, DebugLoc, ToDebugLoc}; +use debuginfo::{self, DebugLoc}; use declare; -use expr; -use glue; use inline; use machine; use machine::{llalign_of_min, llsize_of}; @@ -91,9 +81,8 @@ use type_::Type; use type_of; use value::Value; use Disr; -use util::common::indenter; use util::sha2::Sha256; -use util::nodemap::{NodeMap, NodeSet, FnvHashSet}; +use util::nodemap::{NodeSet, FnvHashSet}; use arena::TypedArena; use libc::c_uint; @@ -104,12 +93,10 @@ use std::collections::HashMap; use std::ptr; use std::rc::Rc; use std::str; -use std::{i8, i16, i32, i64}; +use std::i32; use syntax_pos::{Span, DUMMY_SP}; -use syntax::parse::token::InternedString; use syntax::attr::AttrMetaMethods; use syntax::attr; -use rustc::hir::intravisit::{self, Visitor}; use rustc::hir; use syntax::ast; @@ -192,8 +179,12 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { } } -pub fn kind_for_closure(ccx: &CrateContext, closure_id: DefId) -> ty::ClosureKind { - *ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap() +pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef { + StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA) +} + +pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { + StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR) } fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId { @@ -220,7 +211,7 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Allocate space: let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem); let r = Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx())) - .call(bcx, debug_loc, ArgVals(&[size, align]), None); + .call(bcx, debug_loc, &[size, align], None); Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } @@ -430,8 +421,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, let value = if common::type_is_sized(cx.tcx(), t) { adt::MaybeSizedValue::sized(av) } else { - let data = Load(cx, expr::get_dataptr(cx, av)); - let info = Load(cx, expr::get_meta(cx, av)); + let data = Load(cx, get_dataptr(cx, av)); + let info = Load(cx, get_meta(cx, av)); adt::MaybeSizedValue::unsized_(data, info) }; @@ -446,10 +437,10 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, let val = if common::type_is_sized(cx.tcx(), field_ty) { llfld_a } else { - let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter"); - Store(cx, llfld_a, expr::get_dataptr(cx, scratch.val)); - Store(cx, value.meta, expr::get_meta(cx, scratch.val)); - scratch.val + let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, get_dataptr(cx, scratch)); + Store(cx, value.meta, get_meta(cx, scratch)); + scratch }; cx = f(cx, val, field_ty); } @@ -462,7 +453,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } } ty::TyArray(_, n) => { - let (base, len) = tvec::get_fixed_base_and_len(cx, value.value, n); + let base = get_dataptr(cx, value.value); + let len = C_uint(cx.ccx(), n); let unit_ty = t.sequence_element_type(cx.tcx()); cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); } @@ -488,14 +480,14 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, // comparison know not to proceed when the discriminants differ. match adt::trans_switch(cx, &repr, av, false) { - (_match::Single, None) => { + (adt::BranchKind::Single, None) => { if n_variants != 0 { assert!(n_variants == 1); cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), &en.variants[0], substs, &mut f); } } - (_match::Switch, Some(lldiscrim_a)) => { + (adt::BranchKind::Switch, Some(lldiscrim_a)) => { cx = f(cx, lldiscrim_a, cx.tcx().types.isize); // Create a fall-through basic block for the "else" case of @@ -511,13 +503,13 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, // from the outer function, and any other use case will only // call this for an already-valid enum in which case the `ret // void` will never be hit. - let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void"); + let ret_void_cx = fcx.new_block("enum-iter-ret-void"); RetVoid(ret_void_cx, DebugLoc::None); let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); - let next_cx = fcx.new_temp_block("enum-iter-next"); + let next_cx = fcx.new_block("enum-iter-next"); for variant in &en.variants { - let variant_cx = fcx.new_temp_block(&format!("enum-iter-variant-{}", + let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", &variant.disr_val .to_string())); let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); @@ -733,101 +725,6 @@ fn cast_shift_rhs(op: hir::BinOp_, } } -pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, - val_t: Ty<'tcx>) - -> (Type, u64) { - match val_t.sty { - ty::TyInt(t) => { - let llty = Type::int_from_ty(cx.ccx(), t); - let min = match t { - ast::IntTy::Is if llty == Type::i32(cx.ccx()) => i32::MIN as u64, - ast::IntTy::Is => i64::MIN as u64, - ast::IntTy::I8 => i8::MIN as u64, - ast::IntTy::I16 => i16::MIN as u64, - ast::IntTy::I32 => i32::MIN as u64, - ast::IntTy::I64 => i64::MIN as u64, - }; - (llty, min) - } - _ => bug!(), - } -} - -pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>, - call_info: NodeIdAndSpan, - divrem: hir::BinOp, - lhs: ValueRef, - rhs: ValueRef, - rhs_t: Ty<'tcx>) - -> Block<'blk, 'tcx> { - use rustc_const_math::{ConstMathErr, Op}; - - let (zero_err, overflow_err) = if divrem.node == hir::BiDiv { - (ConstMathErr::DivisionByZero, ConstMathErr::Overflow(Op::Div)) - } else { - (ConstMathErr::RemainderByZero, ConstMathErr::Overflow(Op::Rem)) - }; - let debug_loc = call_info.debug_loc(); - - let (is_zero, is_signed) = match rhs_t.sty { - ty::TyInt(t) => { - let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0, false); - (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), true) - } - ty::TyUint(t) => { - let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false); - (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false) - } - ty::TyStruct(def, _) if def.is_simd() => { - let mut res = C_bool(cx.ccx(), false); - for i in 0..rhs_t.simd_size(cx.tcx()) { - res = Or(cx, - res, - IsNull(cx, ExtractElement(cx, rhs, C_int(cx.ccx(), i as i64))), - debug_loc); - } - (res, false) - } - _ => { - bug!("fail-if-zero on unexpected type: {}", rhs_t); - } - }; - let bcx = with_cond(cx, is_zero, |bcx| { - controlflow::trans_fail(bcx, call_info, InternedString::new(zero_err.description())) - }); - - // To quote LLVM's documentation for the sdiv instruction: - // - // Division by zero leads to undefined behavior. Overflow also leads - // to undefined behavior; this is a rare case, but can occur, for - // example, by doing a 32-bit division of -2147483648 by -1. - // - // In order to avoid undefined behavior, we perform runtime checks for - // signed division/remainder which would trigger overflow. For unsigned - // integers, no action beyond checking for zero need be taken. - if is_signed { - let (llty, min) = llty_and_min_for_signed_ty(cx, rhs_t); - let minus_one = ICmp(bcx, - llvm::IntEQ, - rhs, - C_integral(llty, !0, false), - debug_loc); - with_cond(bcx, minus_one, |bcx| { - let is_min = ICmp(bcx, - llvm::IntEQ, - lhs, - C_integral(llty, min, true), - debug_loc); - with_cond(bcx, is_min, |bcx| { - controlflow::trans_fail(bcx, call_info, - InternedString::new(overflow_err.description())) - }) - }) - } else { - bcx - } -} - pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef, llargs: &[ValueRef], @@ -838,21 +735,12 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return (C_null(Type::i8(bcx.ccx())), bcx); } - match bcx.opt_node_id { - None => { - debug!("invoke at ???"); - } - Some(id) => { - debug!("invoke at {}", bcx.tcx().map.node_to_string(id)); - } - } - if need_invoke(bcx) { debug!("invoking {:?} at {:?}", Value(llfn), bcx.llbb); for &llarg in llargs { debug!("arg: {:?}", Value(llarg)); } - let normal_bcx = bcx.fcx.new_temp_block("normal-return"); + let normal_bcx = bcx.fcx.new_block("normal-return"); let landing_pad = bcx.fcx.get_landing_pad(); let llresult = Invoke(bcx, @@ -894,14 +782,6 @@ pub fn need_invoke(bcx: Block) -> bool { } } -pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>) -> ValueRef { - let _icx = push_ctxt("load_if_immediate"); - if type_is_immediate(cx.ccx(), t) { - return load_ty(cx, v, t); - } - return v; -} - /// Helper for loading values from memory. Does the necessary conversion if the in-memory type /// differs from the type used for SSA values. Also handles various special cases where the type /// gives us better information about what we are loading. @@ -957,10 +837,10 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t if common::type_is_fat_ptr(cx.tcx(), t) { Store(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), - expr::get_dataptr(cx, dst)); + get_dataptr(cx, dst)); Store(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), - expr::get_meta(cx, dst)); + get_meta(cx, dst)); } else { Store(cx, from_immediate(cx, v), dst); } @@ -972,8 +852,8 @@ pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, dst: ValueRef, _ty: Ty<'tcx>) { // FIXME: emit metadata - Store(cx, data, expr::get_dataptr(cx, dst)); - Store(cx, extra, expr::get_meta(cx, dst)); + Store(cx, data, get_dataptr(cx, dst)); + Store(cx, extra, get_meta(cx, dst)); } pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, @@ -981,8 +861,8 @@ pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, _ty: Ty<'tcx>) -> (ValueRef, ValueRef) { // FIXME: emit metadata - (Load(cx, expr::get_dataptr(cx, src)), - Load(cx, expr::get_meta(cx, src))) + (Load(cx, get_dataptr(cx, src)), + Load(cx, get_meta(cx, src))) } pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef { @@ -1001,19 +881,6 @@ pub fn to_immediate(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef { } } -pub fn init_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, local: &hir::Local) -> Block<'blk, 'tcx> { - debug!("init_local(bcx={}, local.id={})", bcx.to_str(), local.id); - let _indenter = indenter(); - let _icx = push_ctxt("init_local"); - _match::store_local(bcx, local) -} - -pub fn raw_block<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, - llbb: BasicBlockRef) - -> Block<'blk, 'tcx> { - common::BlockS::new(llbb, None, fcx) -} - pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> Block<'blk, 'tcx> where F: FnOnce(Block<'blk, 'tcx>) -> Block<'blk, 'tcx> { @@ -1024,8 +891,8 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> } let fcx = bcx.fcx; - let next_cx = fcx.new_temp_block("next"); - let cond_cx = fcx.new_temp_block("cond"); + let next_cx = fcx.new_block("next"); + let cond_cx = fcx.new_block("cond"); CondBr(bcx, val, cond_cx.llbb, next_cx.llbb, DebugLoc::None); let after_cx = f(cond_cx); if !after_cx.terminated.get() { @@ -1099,7 +966,7 @@ pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) { } else { let exc_ptr = ExtractValue(bcx, lpval, 0); bcx.fcx.eh_unwind_resume() - .call(bcx, DebugLoc::None, ArgVals(&[exc_ptr]), None); + .call(bcx, DebugLoc::None, &[exc_ptr], None); } } @@ -1142,15 +1009,6 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dst: ValueRef, src: ValueRe } } -pub fn drop_done_fill_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) { - if cx.unreachable.get() { - return; - } - let _icx = push_ctxt("drop_done_fill_mem"); - let bcx = cx; - memfill(&B(bcx), llptr, t, adt::DTOR_DONE); -} - pub fn init_zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) { if cx.unreachable.get() { return; @@ -1190,82 +1048,11 @@ pub fn call_memset<'bcx, 'tcx>(b: &Builder<'bcx, 'tcx>, b.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None); } - -/// In general, when we create an scratch value in an alloca, the -/// creator may not know if the block (that initializes the scratch -/// with the desired value) actually dominates the cleanup associated -/// with the scratch value. -/// -/// To deal with this, when we do an alloca (at the *start* of whole -/// function body), we optionally can also set the associated -/// dropped-flag state of the alloca to "dropped." -#[derive(Copy, Clone, Debug)] -pub enum InitAlloca { - /// Indicates that the state should have its associated drop flag - /// set to "dropped" at the point of allocation. - Dropped, - /// Indicates the value of the associated drop flag is irrelevant. - /// The embedded string literal is a programmer provided argument - /// for why. This is a safeguard forcing compiler devs to - /// document; it might be a good idea to also emit this as a - /// comment with the alloca itself when emitting LLVM output.ll. - Uninit(&'static str), -} - - pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - t: Ty<'tcx>, + ty: Ty<'tcx>, name: &str) -> ValueRef { - // pnkfelix: I do not know why alloc_ty meets the assumptions for - // passing Uninit, but it was never needed (even back when we had - // the original boolean `zero` flag on `lvalue_scratch_datum`). - alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name) -} - -/// This variant of `fn alloc_ty` does not necessarily assume that the -/// alloca should be created with no initial value. Instead the caller -/// controls that assumption via the `init` flag. -/// -/// Note that if the alloca *is* initialized via `init`, then we will -/// also inject an `llvm.lifetime.start` before that initialization -/// occurs, and thus callers should not call_lifetime_start -/// themselves. But if `init` says "uninitialized", then callers are -/// in charge of choosing where to call_lifetime_start and -/// subsequently populate the alloca. -/// -/// (See related discussion on PR #30823.) -pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - t: Ty<'tcx>, - init: InitAlloca, - name: &str) -> ValueRef { - let _icx = push_ctxt("alloc_ty"); - let ccx = bcx.ccx(); - let ty = type_of::type_of(ccx, t); - assert!(!t.has_param_types()); - match init { - InitAlloca::Dropped => alloca_dropped(bcx, t, name), - InitAlloca::Uninit(_) => alloca(bcx, ty, name), - } -} - -pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef { - let _icx = push_ctxt("alloca_dropped"); - let llty = type_of::type_of(cx.ccx(), ty); - if cx.unreachable.get() { - unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); } - } - let p = alloca(cx, llty, name); - let b = cx.fcx.ccx.builder(); - b.position_before(cx.fcx.alloca_insert_pt.get().unwrap()); - - // This is just like `call_lifetime_start` (but latter expects a - // Block, which we do not have for `alloca_insert_pt`). - core_lifetime_emit(cx.ccx(), p, Lifetime::Start, |ccx, size, lifetime_start| { - let ptr = b.pointercast(p, Type::i8p(ccx)); - b.call(lifetime_start, &[C_u64(ccx, size), ptr], None); - }); - memfill(&b, p, ty, adt::DTOR_DONE); - p + assert!(!ty.has_param_types()); + alloca(bcx, type_of::type_of(bcx.ccx(), ty), name) } pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef { @@ -1279,121 +1066,6 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef { Alloca(cx, ty, name) } -pub fn set_value_name(val: ValueRef, name: &str) { - unsafe { - let name = CString::new(name).unwrap(); - llvm::LLVMSetValueName(val, name.as_ptr()); - } -} - -struct FindNestedReturn { - found: bool, -} - -impl FindNestedReturn { - fn new() -> FindNestedReturn { - FindNestedReturn { - found: false, - } - } -} - -impl<'v> Visitor<'v> for FindNestedReturn { - fn visit_expr(&mut self, e: &hir::Expr) { - match e.node { - hir::ExprRet(..) => { - self.found = true; - } - _ => intravisit::walk_expr(self, e), - } - } -} - -fn build_cfg<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: ast::NodeId) - -> (ast::NodeId, Option) { - let blk = match tcx.map.find(id) { - Some(hir_map::NodeItem(i)) => { - match i.node { - hir::ItemFn(_, _, _, _, _, ref blk) => { - blk - } - _ => bug!("unexpected item variant in has_nested_returns"), - } - } - Some(hir_map::NodeTraitItem(trait_item)) => { - match trait_item.node { - hir::MethodTraitItem(_, Some(ref body)) => body, - _ => { - bug!("unexpected variant: trait item other than a provided method in \ - has_nested_returns") - } - } - } - Some(hir_map::NodeImplItem(impl_item)) => { - match impl_item.node { - hir::ImplItemKind::Method(_, ref body) => body, - _ => { - bug!("unexpected variant: non-method impl item in has_nested_returns") - } - } - } - Some(hir_map::NodeExpr(e)) => { - match e.node { - hir::ExprClosure(_, _, ref blk, _) => blk, - _ => bug!("unexpected expr variant in has_nested_returns"), - } - } - Some(hir_map::NodeVariant(..)) | - Some(hir_map::NodeStructCtor(..)) => return (ast::DUMMY_NODE_ID, None), - - // glue, shims, etc - None if id == ast::DUMMY_NODE_ID => return (ast::DUMMY_NODE_ID, None), - - _ => bug!("unexpected variant in has_nested_returns: {}", - tcx.node_path_str(id)), - }; - - (blk.id, Some(cfg::CFG::new(tcx, blk))) -} - -// Checks for the presence of "nested returns" in a function. -// Nested returns are when the inner expression of a return expression -// (the 'expr' in 'return expr') contains a return expression. Only cases -// where the outer return is actually reachable are considered. Implicit -// returns from the end of blocks are considered as well. -// -// This check is needed to handle the case where the inner expression is -// part of a larger expression that may have already partially-filled the -// return slot alloca. This can cause errors related to clean-up due to -// the clobbering of the existing value in the return slot. -fn has_nested_returns(tcx: TyCtxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool { - for index in cfg.graph.depth_traverse(cfg.entry, OUTGOING) { - let n = cfg.graph.node_data(index); - match tcx.map.find(n.id()) { - Some(hir_map::NodeExpr(ex)) => { - if let hir::ExprRet(Some(ref ret_expr)) = ex.node { - let mut visitor = FindNestedReturn::new(); - intravisit::walk_expr(&mut visitor, &ret_expr); - if visitor.found { - return true; - } - } - } - Some(hir_map::NodeBlock(blk)) if blk.id == blk_id => { - let mut visitor = FindNestedReturn::new(); - walk_list!(&mut visitor, visit_expr, &blk.expr); - if visitor.found { - return true; - } - } - _ => {} - } - } - - return false; -} - impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { /// Create a function context for the given function. /// Beware that you must call `fcx.init` or `fcx.bind_args` @@ -1401,15 +1073,15 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>, llfndecl: ValueRef, fn_ty: FnType, - definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi, ast::NodeId)>, + definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi)>, block_arena: &'blk TypedArena>) -> FunctionContext<'blk, 'tcx> { - let (param_substs, def_id, inlined_id) = match definition { - Some((instance, _, _, inlined_id)) => { + let (param_substs, def_id) = match definition { + Some((instance, _, _)) => { common::validate_substs(instance.substs); - (instance.substs, Some(instance.def), Some(inlined_id)) + (instance.substs, Some(instance.def)) } - None => (Substs::empty(ccx.tcx()), None, None) + None => (Substs::empty(ccx.tcx()), None) }; let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id)); @@ -1417,13 +1089,6 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { debug!("FunctionContext::new({})", definition.map_or(String::new(), |d| d.0.to_string())); - let cfg = inlined_id.map(|id| build_cfg(ccx.tcx(), id)); - let nested_returns = if let Some((blk_id, Some(ref cfg))) = cfg { - has_nested_returns(ccx.tcx(), cfg, blk_id) - } else { - false - }; - let no_debug = if let Some(id) = local_id { ccx.tcx().map.attrs(id) .iter().any(|item| item.check_name("no_debug")) @@ -1434,44 +1099,34 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { false }; - let mir = def_id.and_then(|id| ccx.get_mir(id)); - - let debug_context = if let (false, Some(definition)) = (no_debug, definition) { - let (instance, sig, abi, _) = definition; + let debug_context = if let (false, Some((instance, sig, abi))) = (no_debug, definition) { debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl) } else { debuginfo::empty_function_debug_context(ccx) }; FunctionContext { - needs_ret_allocas: nested_returns && mir.is_none(), - mir: mir, + mir: def_id.and_then(|id| ccx.get_mir(id)), llfn: llfndecl, llretslotptr: Cell::new(None), param_env: ccx.tcx().empty_parameter_environment(), alloca_insert_pt: Cell::new(None), - llreturn: Cell::new(None), landingpad_alloca: Cell::new(None), - lllocals: RefCell::new(NodeMap()), - llupvars: RefCell::new(NodeMap()), - lldropflag_hints: RefCell::new(DropFlagHintsMap::new()), fn_ty: fn_ty, param_substs: param_substs, - span: inlined_id.and_then(|id| ccx.tcx().map.opt_span(id)), + span: None, block_arena: block_arena, lpad_arena: TypedArena::new(), ccx: ccx, debug_context: debug_context, scopes: RefCell::new(Vec::new()), - cfg: cfg.and_then(|(_, cfg)| cfg) } } /// Performs setup on a newly created function, creating the entry /// scope block and allocating space for the return pointer. - pub fn init(&'blk self, skip_retptr: bool, fn_did: Option) - -> Block<'blk, 'tcx> { - let entry_bcx = self.new_temp_block("entry-block"); + pub fn init(&'blk self, skip_retptr: bool) -> Block<'blk, 'tcx> { + let entry_bcx = self.new_block("entry-block"); // Use a dummy instruction as the insertion point for all allocas. // This is later removed in FunctionContext::cleanup. @@ -1489,244 +1144,26 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { // which will hold the pointer to the right alloca which has the // final ret value let llty = self.fn_ty.ret.memory_ty(self.ccx); - let slot = if self.needs_ret_allocas { - // Let's create the stack slot - let slot = AllocaFcx(self, llty.ptr_to(), "llretslotptr"); - - // and if we're using an out pointer, then store that in our newly made slot - if self.fn_ty.ret.is_indirect() { - let outptr = get_param(self.llfn, 0); - - let b = self.ccx.builder(); - b.position_before(self.alloca_insert_pt.get().unwrap()); - b.store(outptr, slot); - } - - slot + // But if there are no nested returns, we skip the indirection + // and have a single retslot + let slot = if self.fn_ty.ret.is_indirect() { + get_param(self.llfn, 0) } else { - // But if there are no nested returns, we skip the indirection - // and have a single retslot - if self.fn_ty.ret.is_indirect() { - get_param(self.llfn, 0) - } else { - AllocaFcx(self, llty, "sret_slot") - } + AllocaFcx(self, llty, "sret_slot") }; self.llretslotptr.set(Some(slot)); } - // Create the drop-flag hints for every unfragmented path in the function. - let tcx = self.ccx.tcx(); - let tables = tcx.tables.borrow(); - let mut hints = self.lldropflag_hints.borrow_mut(); - let fragment_infos = tcx.fragment_infos.borrow(); - - // Intern table for drop-flag hint datums. - let mut seen = HashMap::new(); - - let fragment_infos = fn_did.and_then(|did| fragment_infos.get(&did)); - if let Some(fragment_infos) = fragment_infos { - for &info in fragment_infos { - - let make_datum = |id| { - let init_val = C_u8(self.ccx, adt::DTOR_NEEDED_HINT); - let llname = &format!("dropflag_hint_{}", id); - debug!("adding hint {}", llname); - let ty = tcx.types.u8; - let ptr = alloc_ty(entry_bcx, ty, llname); - Store(entry_bcx, init_val, ptr); - let flag = datum::Lvalue::new_dropflag_hint("FunctionContext::init"); - datum::Datum::new(ptr, ty, flag) - }; - - let (var, datum) = match info { - ty::FragmentInfo::Moved { var, .. } | - ty::FragmentInfo::Assigned { var, .. } => { - let opt_datum = seen.get(&var).cloned().unwrap_or_else(|| { - let ty = tables.node_types[&var]; - if self.type_needs_drop(ty) { - let datum = make_datum(var); - seen.insert(var, Some(datum.clone())); - Some(datum) - } else { - // No drop call needed, so we don't need a dropflag hint - None - } - }); - if let Some(datum) = opt_datum { - (var, datum) - } else { - continue - } - } - }; - match info { - ty::FragmentInfo::Moved { move_expr: expr_id, .. } => { - debug!("FragmentInfo::Moved insert drop hint for {}", expr_id); - hints.insert(expr_id, DropHint::new(var, datum)); - } - ty::FragmentInfo::Assigned { assignee_id: expr_id, .. } => { - debug!("FragmentInfo::Assigned insert drop hint for {}", expr_id); - hints.insert(expr_id, DropHint::new(var, datum)); - } - } - } - } - entry_bcx } - /// Creates lvalue datums for each of the incoming function arguments, - /// matches all argument patterns against them to produce bindings, - /// and returns the entry block (see FunctionContext::init). - fn bind_args(&'blk self, - args: &[hir::Arg], - abi: Abi, - id: ast::NodeId, - closure_env: closure::ClosureEnv, - arg_scope: cleanup::CustomScopeIndex) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("FunctionContext::bind_args"); - let fn_did = self.ccx.tcx().map.local_def_id(id); - let mut bcx = self.init(false, Some(fn_did)); - let arg_scope_id = cleanup::CustomScope(arg_scope); - - let mut idx = 0; - let mut llarg_idx = self.fn_ty.ret.is_indirect() as usize; - - let has_tupled_arg = match closure_env { - closure::ClosureEnv::NotClosure => abi == Abi::RustCall, - closure::ClosureEnv::Closure(..) => { - closure_env.load(bcx, arg_scope_id); - let env_arg = &self.fn_ty.args[idx]; - idx += 1; - if env_arg.pad.is_some() { - llarg_idx += 1; - } - if !env_arg.is_ignore() { - llarg_idx += 1; - } - false - } - }; - let tupled_arg_id = if has_tupled_arg { - args[args.len() - 1].id - } else { - ast::DUMMY_NODE_ID - }; - - // Return an array wrapping the ValueRefs that we get from `get_param` for - // each argument into datums. - // - // For certain mode/type combinations, the raw llarg values are passed - // by value. However, within the fn body itself, we want to always - // have all locals and arguments be by-ref so that we can cancel the - // cleanup and for better interaction with LLVM's debug info. So, if - // the argument would be passed by value, we store it into an alloca. - // This alloca should be optimized away by LLVM's mem-to-reg pass in - // the event it's not truly needed. - let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor"); - for hir_arg in args { - let arg_ty = node_id_type(bcx, hir_arg.id); - let arg_datum = if hir_arg.id != tupled_arg_id { - let arg = &self.fn_ty.args[idx]; - idx += 1; - if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo { - // Don't copy an indirect argument to an alloca, the caller - // already put it in a temporary alloca and gave it up, unless - // we emit extra-debug-info, which requires local allocas :(. - let llarg = get_param(self.llfn, llarg_idx as c_uint); - llarg_idx += 1; - self.schedule_lifetime_end(arg_scope_id, llarg); - self.schedule_drop_mem(arg_scope_id, llarg, arg_ty, None); - - datum::Datum::new(llarg, - arg_ty, - datum::Lvalue::new("FunctionContext::bind_args")) - } else { - unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", - uninit_reason, - arg_scope_id, |bcx, dst| { - debug!("FunctionContext::bind_args: {:?}: {:?}", hir_arg, arg_ty); - let b = &bcx.build(); - if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { - let meta = &self.fn_ty.args[idx]; - idx += 1; - arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst)); - meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst)); - } else { - arg.store_fn_arg(b, &mut llarg_idx, dst); - } - bcx - })) - } - } else { - // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. - let tupled_arg_tys = match arg_ty.sty { - ty::TyTuple(ref tys) => tys, - _ => bug!("last argument of `rust-call` fn isn't a tuple?!") - }; - - unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, - arg_ty, - "tupled_args", - uninit_reason, - arg_scope_id, - |bcx, llval| { - debug!("FunctionContext::bind_args: tupled {:?}: {:?}", hir_arg, arg_ty); - for (j, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() { - let dst = StructGEP(bcx, llval, j); - let arg = &self.fn_ty.args[idx]; - idx += 1; - let b = &bcx.build(); - if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) { - let meta = &self.fn_ty.args[idx]; - idx += 1; - arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst)); - meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst)); - } else { - arg.store_fn_arg(b, &mut llarg_idx, dst); - } - } - bcx - })) - }; - - let pat = &hir_arg.pat; - bcx = if let Some(name) = simple_name(pat) { - // Generate nicer LLVM for the common case of fn a pattern - // like `x: T` - set_value_name(arg_datum.val, &bcx.name(name)); - self.lllocals.borrow_mut().insert(pat.id, arg_datum); - bcx - } else { - // General path. Copy out the values that are used in the - // pattern. - _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id) - }; - debuginfo::create_argument_metadata(bcx, hir_arg); - } - - bcx - } - /// Ties up the llstaticallocas -> llloadenv -> lltop edges, /// and builds the return block. - pub fn finish(&'blk self, last_bcx: Block<'blk, 'tcx>, + pub fn finish(&'blk self, ret_cx: Block<'blk, 'tcx>, ret_debug_loc: DebugLoc) { let _icx = push_ctxt("FunctionContext::finish"); - let ret_cx = match self.llreturn.get() { - Some(llreturn) => { - if !last_bcx.terminated.get() { - Br(last_bcx, llreturn, DebugLoc::None); - } - raw_block(self, llreturn) - } - None => last_bcx, - }; - self.build_return_block(ret_cx, ret_debug_loc); DebugLoc::None.apply(self); @@ -1738,15 +1175,11 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { ret_debug_location: DebugLoc) { if self.llretslotptr.get().is_none() || ret_cx.unreachable.get() || - (!self.needs_ret_allocas && self.fn_ty.ret.is_indirect()) { + self.fn_ty.ret.is_indirect() { return RetVoid(ret_cx, ret_debug_location); } - let retslot = if self.needs_ret_allocas { - Load(ret_cx, self.llretslotptr.get().unwrap()) - } else { - self.llretslotptr.get().unwrap() - }; + let retslot = self.llretslotptr.get().unwrap(); let retptr = Value(retslot); let llty = self.fn_ty.ret.original_ty; match (retptr.get_dominating_store(ret_cx), self.fn_ty.ret.cast) { @@ -1805,14 +1238,10 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { /// /// If the function closes over its environment a closure will be returned. pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - decl: &hir::FnDecl, - body: &hir::Block, llfndecl: ValueRef, instance: Instance<'tcx>, - inlined_id: ast::NodeId, sig: &ty::FnSig<'tcx>, - abi: Abi, - closure_env: closure::ClosureEnv) { + abi: Abi) { ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); let _icx = push_ctxt("trans_closure"); @@ -1832,86 +1261,21 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fcx = FunctionContext::new(ccx, llfndecl, fn_ty, - Some((instance, sig, abi, inlined_id)), + Some((instance, sig, abi)), &arena); - if fcx.mir.is_some() { - return mir::trans_mir(&fcx); - } else { - span_bug!(body.span, "attempted translation of `{}` w/o MIR", instance); - } - - debuginfo::fill_scope_map_for_function(&fcx, decl, body, inlined_id); - - // cleanup scope for the incoming arguments - let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node( - ccx, inlined_id, body.span, true); - let arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc); - - // Set up arguments to the function. - debug!("trans_closure: function: {:?}", Value(fcx.llfn)); - let bcx = fcx.bind_args(&decl.inputs, abi, inlined_id, closure_env, arg_scope); - - // Up until here, IR instructions for this function have explicitly not been annotated with - // source code location, so we don't step into call setup code. From here on, source location - // emitting should be enabled. - debuginfo::start_emitting_source_locations(&fcx); - - let dest = if fcx.fn_ty.ret.is_ignore() { - expr::Ignore - } else { - expr::SaveIn(fcx.get_ret_slot(bcx, "iret_slot")) - }; - - // This call to trans_block is the place where we bridge between - // translation calls that don't have a return value (trans_crate, - // trans_mod, trans_item, et cetera) and those that do - // (trans_block, trans_expr, et cetera). - let mut bcx = controlflow::trans_block(bcx, body, dest); - - match dest { - expr::SaveIn(slot) if fcx.needs_ret_allocas => { - Store(bcx, slot, fcx.llretslotptr.get().unwrap()); - } - _ => {} + if fcx.mir.is_none() { + bug!("attempted translation of `{}` w/o MIR", instance); } - match fcx.llreturn.get() { - Some(_) => { - Br(bcx, fcx.return_exit_block(), DebugLoc::None); - fcx.pop_custom_cleanup_scope(arg_scope); - } - None => { - // Microoptimization writ large: avoid creating a separate - // llreturn basic block - bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope); - } - }; - - // Put return block after all other blocks. - // This somewhat improves single-stepping experience in debugger. - unsafe { - let llreturn = fcx.llreturn.get(); - if let Some(llreturn) = llreturn { - llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb); - } - } - - // Insert the mandatory first few basic blocks before lltop. - fcx.finish(bcx, fn_cleanup_debug_loc.debug_loc()); + mir::trans_mir(&fcx); } pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let local_instance = inline::maybe_inline_instance(ccx, instance); - - let fn_node_id = ccx.tcx().map.as_local_node_id(local_instance.def).unwrap(); - - let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(fn_node_id)); + let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); debug!("trans_instance(instance={:?})", instance); let _icx = push_ctxt("trans_instance"); - let item = ccx.tcx().map.find(fn_node_id).unwrap(); - let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty; let fn_ty = ccx.tcx().erase_regions(&fn_ty); let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty); @@ -1920,100 +1284,13 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let sig = ccx.tcx().normalize_associated_type(&sig); let abi = fn_ty.fn_abi(); + let local_instance = inline::maybe_inline_instance(ccx, instance); let lldecl = match ccx.instances().borrow().get(&local_instance) { Some(&val) => val, None => bug!("Instance `{:?}` not already declared", instance) }; - match item { - hir_map::NodeItem(&hir::Item { - node: hir::ItemFn(ref decl, _, _, _, _, ref body), .. - }) | - hir_map::NodeTraitItem(&hir::TraitItem { - node: hir::MethodTraitItem( - hir::MethodSig { ref decl, .. }, Some(ref body)), .. - }) | - hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method( - hir::MethodSig { ref decl, .. }, ref body), .. - }) => { - trans_closure(ccx, decl, body, lldecl, instance, - fn_node_id, &sig, abi, closure::ClosureEnv::NotClosure); - } - _ => bug!("Instance is a {:?}?", item) - } -} - -pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - ctor_ty: Ty<'tcx>, - disr: Disr, - args: CallArgs, - dest: expr::Dest, - debug_loc: DebugLoc) - -> Result<'blk, 'tcx> { - - let ccx = bcx.fcx.ccx; - - let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); - let sig = ccx.tcx().normalize_associated_type(&sig); - let result_ty = sig.output; - - // Get location to store the result. If the user does not care about - // the result, just make a stack slot - let llresult = match dest { - expr::SaveIn(d) => d, - expr::Ignore => { - if !type_is_zero_size(ccx, result_ty) { - let llresult = alloc_ty(bcx, result_ty, "constructor_result"); - call_lifetime_start(bcx, llresult); - llresult - } else { - C_undef(type_of::type_of(ccx, result_ty).ptr_to()) - } - } - }; - - if !type_is_zero_size(ccx, result_ty) { - match args { - ArgExprs(exprs) => { - let fields = exprs.iter().map(|x| &**x).enumerate().collect::>(); - bcx = expr::trans_adt(bcx, - result_ty, - disr, - &fields[..], - None, - expr::SaveIn(llresult), - debug_loc); - } - _ => bug!("expected expr as arguments for variant/struct tuple constructor"), - } - } else { - // Just eval all the expressions (if any). Since expressions in Rust can have arbitrary - // contents, there could be side-effects we need from them. - match args { - ArgExprs(exprs) => { - for expr in exprs { - bcx = expr::trans_into(bcx, expr, expr::Ignore); - } - } - _ => (), - } - } - - // If the caller doesn't care about the result - // drop the temporary we made - let bcx = match dest { - expr::SaveIn(_) => bcx, - expr::Ignore => { - let bcx = glue::drop_ty(bcx, llresult, result_ty, debug_loc); - if !type_is_zero_size(ccx, result_ty) { - call_lifetime_end(bcx, llresult); - } - bcx - } - }; - - Result::new(bcx, llresult) + trans_closure(ccx, lldecl, instance, &sig, abi); } pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -2031,12 +1308,10 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let (arena, fcx): (TypedArena<_>, FunctionContext); arena = TypedArena::new(); fcx = FunctionContext::new(ccx, llfndecl, fn_ty, None, &arena); - let bcx = fcx.init(false, None); - - assert!(!fcx.needs_ret_allocas); + let bcx = fcx.init(false); if !fcx.fn_ty.ret.is_ignore() { - let dest = fcx.get_ret_slot(bcx, "eret_slot"); + let dest = fcx.llretslotptr.get().unwrap(); let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value let repr = adt::represent_type(ccx, sig.output); let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize; @@ -2049,8 +1324,8 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { let meta = &fcx.fn_ty.args[arg_idx]; arg_idx += 1; - arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, lldestptr)); - meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, lldestptr)); + arg.store_fn_arg(b, &mut llarg_idx, get_dataptr(bcx, lldestptr)); + meta.store_fn_arg(b, &mut llarg_idx, get_meta(bcx, lldestptr)); } else { arg.store_fn_arg(b, &mut llarg_idx, lldestptr); } @@ -2126,7 +1401,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { return; } - let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx).val; + let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx); let et = ccx.sess().entry_type.get().unwrap(); match et { @@ -2168,7 +1443,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { Err(s) => ccx.sess().fatal(&s) }; let empty_substs = Substs::empty(ccx.tcx()); - let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx).val; + let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx); let args = { let opaque_rust_main = llvm::LLVMBuildPointerCast(bld, @@ -2495,12 +1770,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.sess.opts.debug_assertions }; - let check_dropflag = if let Some(v) = tcx.sess.opts.debugging_opts.force_dropflag_checks { - v - } else { - tcx.sess.opts.debug_assertions - }; - let link_meta = link::build_link_meta(incremental_hashes_map, name); let shared_ccx = SharedCrateContext::new(tcx, @@ -2509,8 +1778,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Sha256::new(), link_meta.clone(), reachable, - check_overflow, - check_dropflag); + check_overflow); // Translate the metadata. let metadata = time(tcx.sess.time_passes(), "write metadata", || { write_metadata(&shared_ccx, shared_ccx.reachable()) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index d50959b5ab302..b661383d6060f 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -15,39 +15,29 @@ //! closure. pub use self::CalleeData::*; -pub use self::CallArgs::*; use arena::TypedArena; use back::symbol_names; -use llvm::{self, ValueRef, get_params}; +use llvm::{ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::hir::map as hir_map; use abi::{Abi, FnType}; -use adt; use attributes; use base; use base::*; use build::*; -use cleanup; -use cleanup::CleanupMethods; use closure; -use common::{self, Block, Result, CrateContext, FunctionContext, C_undef}; +use common::{self, Block, Result, CrateContext, FunctionContext}; use consts; -use datum::*; use debuginfo::DebugLoc; use declare; -use expr; -use glue; use inline; -use intrinsic; -use machine::llalign_of_min; use meth; use monomorphize::{self, Instance}; use trans_item::TransItem; -use type_::Type; use type_of; use value::Value; use Disr; @@ -56,7 +46,6 @@ use rustc::hir; use syntax_pos::DUMMY_SP; use errors; -use syntax::ptr::P; #[derive(Debug)] pub enum CalleeData { @@ -80,10 +69,10 @@ pub struct Callee<'tcx> { impl<'tcx> Callee<'tcx> { /// Function pointer. - pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> { + pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> { Callee { - data: Fn(datum.val), - ty: datum.ty + data: Fn(llfn), + ty: ty } } @@ -132,7 +121,10 @@ impl<'tcx> Callee<'tcx> { abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic } => Intrinsic, - _ => return Callee::ptr(get_fn(ccx, def_id, substs)) + _ => { + let (llfn, ty) = get_fn(ccx, def_id, substs); + return Callee::ptr(llfn, ty); + } }; Callee { @@ -163,7 +155,8 @@ impl<'tcx> Callee<'tcx> { // That is because default methods have the same ID as the // trait method used to look up the impl method that ended // up here, so calling Callee::def would infinitely recurse. - Callee::ptr(get_fn(ccx, mth.method.def_id, mth.substs)) + let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs); + Callee::ptr(llfn, ty) } traits::VtableClosure(vtable_closure) => { // The substitutions should have no type parameters remaining @@ -180,7 +173,7 @@ impl<'tcx> Callee<'tcx> { _ => bug!("expected fn item type, found {}", method_ty) }; - Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) + Callee::ptr(llfn, fn_ptr_ty) } traits::VtableFnPointer(vtable_fn_pointer) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); @@ -192,7 +185,7 @@ impl<'tcx> Callee<'tcx> { _ => bug!("expected fn item type, found {}", method_ty) }; - Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) + Callee::ptr(llfn, fn_ptr_ty) } traits::VtableObject(ref data) => { Callee { @@ -236,30 +229,22 @@ impl<'tcx> Callee<'tcx> { /// function. pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc, - args: CallArgs<'a, 'tcx>, - dest: Option) + args: &[ValueRef], + dest: Option) -> Result<'blk, 'tcx> { trans_call_inner(bcx, debug_loc, self, args, dest) } /// Turn the callee into a function pointer. - pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) - -> Datum<'tcx, Rvalue> { - let fn_ptr_ty = match self.ty.sty { - ty::TyFnDef(_, _, f) => ccx.tcx().mk_fn_ptr(f), - _ => self.ty - }; + pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { match self.data { - Fn(llfn) => { - immediate_rvalue(llfn, fn_ptr_ty) - } + Fn(llfn) => llfn, Virtual(idx) => { - let llfn = meth::trans_object_shim(ccx, self.ty, idx); - immediate_rvalue(llfn, fn_ptr_ty) + meth::trans_object_shim(ccx, self.ty, idx) } NamedTupleConstructor(_) => match self.ty.sty { ty::TyFnDef(def_id, substs, _) => { - return get_fn(ccx, def_id, substs); + return get_fn(ccx, def_id, substs).0; } _ => bug!("expected fn item type, found {}", self.ty) }, @@ -310,7 +295,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let llfnpointer = match bare_fn_ty.sty { ty::TyFnDef(def_id, substs, _) => { // Function definitions have to be turned into a pointer. - let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val; + let llfn = Callee::def(ccx, def_id, substs).reify(ccx); if !is_by_ref { // A by-value fn item is ignored, so the shim has // the same signature as the original function. @@ -380,7 +365,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena); - let mut bcx = fcx.init(false, None); + let mut bcx = fcx.init(false); let llargs = get_params(fcx.llfn); @@ -394,17 +379,13 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( } }); - assert!(!fcx.needs_ret_allocas); - - let dest = fcx.llretslotptr.get().map(|_| - expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot")) - ); + let dest = fcx.llretslotptr.get(); let callee = Callee { data: Fn(llfnpointer), ty: bare_fn_ty }; - bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; + bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx; fcx.finish(bcx, DebugLoc::None); @@ -424,7 +405,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) - -> Datum<'tcx, Rvalue> { + -> (ValueRef, Ty<'tcx>) { let tcx = ccx.tcx(); debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs); @@ -475,7 +456,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => bug!("expected fn item type, found {}", fn_ty) }; assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val)); - return immediate_rvalue(val, fn_ptr_ty); + return (val, fn_ptr_ty); } // Find the actual function pointer. @@ -490,7 +471,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let instance = Instance::mono(ccx.shared(), def_id); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - return immediate_rvalue(llfn, fn_ptr_ty); + return (llfn, fn_ptr_ty); } let local_id = ccx.tcx().map.as_local_node_id(def_id); @@ -573,17 +554,17 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, llfn); - immediate_rvalue(llfn, fn_ptr_ty) + (llfn, fn_ptr_ty) } // ______________________________________________________________________ // Translating calls -fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc, callee: Callee<'tcx>, - args: CallArgs<'a, 'tcx>, - dest: Option) + args: &[ValueRef], + opt_llretslot: Option) -> Result<'blk, 'tcx> { // Introduce a temporary cleanup scope that will contain cleanups // for the arguments while they are being evaluated. The purpose @@ -595,65 +576,16 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let fcx = bcx.fcx; let ccx = fcx.ccx; - let abi = callee.ty.fn_abi(); - let sig = callee.ty.fn_sig(); - let output = bcx.tcx().erase_late_bound_regions(&sig.output()); - let output = bcx.tcx().normalize_associated_type(&output); - - let extra_args = match args { - ArgExprs(args) if abi != Abi::RustCall => { - args[sig.0.inputs.len()..].iter().map(|expr| { - common::expr_ty_adjusted(bcx, expr) - }).collect() - } - _ => vec![] - }; - let fn_ty = callee.direct_fn_type(ccx, &extra_args); + let fn_ret = callee.ty.fn_ret(); + let fn_ty = callee.direct_fn_type(ccx, &[]); let mut callee = match callee.data { - Intrinsic => { - assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic); - assert!(dest.is_some()); - - return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty, - args, dest.unwrap(), - debug_loc); - } - NamedTupleConstructor(disr) => { - assert!(dest.is_some()); - - return base::trans_named_tuple_constructor(bcx, - callee.ty, - disr, - args, - dest.unwrap(), - debug_loc); + NamedTupleConstructor(_) | Intrinsic => { + bug!("{:?} calls should not go through Callee::call", callee); } f => f }; - // Generate a location to store the result. If the user does - // not care about the result, just make a stack slot. - let opt_llretslot = dest.and_then(|dest| match dest { - expr::SaveIn(dst) => Some(dst), - expr::Ignore => { - let needs_drop = || bcx.fcx.type_needs_drop(output); - if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() { - // Push the out-pointer if we use an out-pointer for this - // return type, otherwise push "undef". - if fn_ty.ret.is_ignore() { - Some(C_undef(fn_ty.ret.original_ty.ptr_to())) - } else { - let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret"); - call_lifetime_start(bcx, llresult); - Some(llresult) - } - } else { - None - } - } - }); - // If there no destination, return must be direct, with no cast. if opt_llretslot.is_none() { assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none()); @@ -669,17 +601,24 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, llargs.push(llretslot); } - let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); - bcx = trans_args(bcx, abi, &fn_ty, &mut callee, args, &mut llargs, - cleanup::CustomScope(arg_cleanup_scope)); - fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); + match callee { + Virtual(idx) => { + llargs.push(args[0]); + + let fn_ptr = meth::get_virtual_method(bcx, args[1], idx); + let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to(); + callee = Fn(PointerCast(bcx, fn_ptr, llty)); + llargs.extend_from_slice(&args[2..]); + } + _ => llargs.extend_from_slice(args) + } let llfn = match callee { Fn(f) => f, _ => bug!("expected fn pointer callee, found {:?}", callee) }; - let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc); + let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc); if !bcx.unreachable.get() { fn_ty.apply_attrs_callsite(llret); @@ -695,283 +634,9 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } - fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope); - - // If the caller doesn't care about the result of this fn call, - // drop the temporary slot we made. - match (dest, opt_llretslot) { - (Some(expr::Ignore), Some(llretslot)) => { - // drop the value if it is not being saved. - bcx = glue::drop_ty(bcx, llretslot, output, debug_loc); - call_lifetime_end(bcx, llretslot); - } - _ => {} - } - - // FIXME(canndrew): This is_never should really be an is_uninhabited - if output.is_never() { + if fn_ret.0.is_never() { Unreachable(bcx); } Result::new(bcx, llret) } - -pub enum CallArgs<'a, 'tcx> { - /// Supply value of arguments as a list of expressions that must be - /// translated. This is used in the common case of `foo(bar, qux)`. - ArgExprs(&'a [P]), - - /// Supply value of arguments as a list of LLVM value refs; frequently - /// used with lang items and so forth, when the argument is an internal - /// value. - ArgVals(&'a [ValueRef]), - - /// For overloaded operators: `(lhs, Option(rhs))`. - /// `lhs` is the left-hand-side and `rhs` is the datum - /// of the right-hand-side argument (if any). - ArgOverloadedOp(Datum<'tcx, Expr>, Option>), - - /// Supply value of arguments as a list of expressions that must be - /// translated, for overloaded call operators. - ArgOverloadedCall(Vec<&'a hir::Expr>), -} - -fn trans_args_under_call_abi<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, - arg_exprs: &[P], - callee: &mut CalleeData, - fn_ty: &FnType, - llargs: &mut Vec, - arg_cleanup_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> -{ - let mut arg_idx = 0; - - // Translate the `self` argument first. - let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); - bcx = trans_arg_datum(bcx, - arg_datum, - callee, fn_ty, &mut arg_idx, - arg_cleanup_scope, - llargs); - - // Now untuple the rest of the arguments. - let tuple_expr = &arg_exprs[1]; - let tuple_type = common::node_id_type(bcx, tuple_expr.id); - - match tuple_type.sty { - ty::TyTuple(ref field_types) => { - let tuple_datum = unpack_datum!(bcx, - expr::trans(bcx, &tuple_expr)); - let tuple_lvalue_datum = - unpack_datum!(bcx, - tuple_datum.to_lvalue_datum(bcx, - "args", - tuple_expr.id)); - let repr = adt::represent_type(bcx.ccx(), tuple_type); - let repr_ptr = &repr; - for (i, field_type) in field_types.iter().enumerate() { - let arg_datum = tuple_lvalue_datum.get_element( - bcx, - field_type, - |srcval| { - adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i) - }).to_expr_datum(); - bcx = trans_arg_datum(bcx, - arg_datum, - callee, fn_ty, &mut arg_idx, - arg_cleanup_scope, - llargs); - } - } - _ => { - span_bug!(tuple_expr.span, - "argument to `.call()` wasn't a tuple?!") - } - }; - - bcx -} - -pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - abi: Abi, - fn_ty: &FnType, - callee: &mut CalleeData, - args: CallArgs<'a, 'tcx>, - llargs: &mut Vec, - arg_cleanup_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { - debug!("trans_args(abi={})", abi); - - let _icx = push_ctxt("trans_args"); - - let mut bcx = bcx; - let mut arg_idx = 0; - - // First we figure out the caller's view of the types of the arguments. - // This will be needed if this is a generic call, because the callee has - // to cast her view of the arguments to the caller's view. - match args { - ArgExprs(arg_exprs) => { - if abi == Abi::RustCall { - // This is only used for direct calls to the `call`, - // `call_mut` or `call_once` functions. - return trans_args_under_call_abi(bcx, - arg_exprs, callee, fn_ty, - llargs, - arg_cleanup_scope) - } - - for arg_expr in arg_exprs { - let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr)); - bcx = trans_arg_datum(bcx, - arg_datum, - callee, fn_ty, &mut arg_idx, - arg_cleanup_scope, - llargs); - } - } - ArgOverloadedCall(arg_exprs) => { - for expr in arg_exprs { - let arg_datum = - unpack_datum!(bcx, expr::trans(bcx, expr)); - bcx = trans_arg_datum(bcx, - arg_datum, - callee, fn_ty, &mut arg_idx, - arg_cleanup_scope, - llargs); - } - } - ArgOverloadedOp(lhs, rhs) => { - bcx = trans_arg_datum(bcx, lhs, - callee, fn_ty, &mut arg_idx, - arg_cleanup_scope, - llargs); - - if let Some(rhs) = rhs { - bcx = trans_arg_datum(bcx, rhs, - callee, fn_ty, &mut arg_idx, - arg_cleanup_scope, - llargs); - } - } - ArgVals(vs) => { - match *callee { - Virtual(idx) => { - llargs.push(vs[0]); - - let fn_ptr = meth::get_virtual_method(bcx, vs[1], idx); - let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to(); - *callee = Fn(PointerCast(bcx, fn_ptr, llty)); - llargs.extend_from_slice(&vs[2..]); - } - _ => llargs.extend_from_slice(vs) - } - } - } - - bcx -} - -fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - arg_datum: Datum<'tcx, Expr>, - callee: &mut CalleeData, - fn_ty: &FnType, - next_idx: &mut usize, - arg_cleanup_scope: cleanup::ScopeId, - llargs: &mut Vec) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_arg_datum"); - let mut bcx = bcx; - - debug!("trans_arg_datum({:?})", arg_datum); - - let arg = &fn_ty.args[*next_idx]; - *next_idx += 1; - - // Fill padding with undef value, where applicable. - if let Some(ty) = arg.pad { - llargs.push(C_undef(ty)); - } - - // Determine whether we want a by-ref datum even if not appropriate. - let want_by_ref = arg.is_indirect() || arg.cast.is_some(); - - let fat_ptr = common::type_is_fat_ptr(bcx.tcx(), arg_datum.ty); - let (by_ref, val) = if fat_ptr && !bcx.fcx.type_needs_drop(arg_datum.ty) { - (true, arg_datum.val) - } else { - // Make this an rvalue, since we are going to be - // passing ownership. - let arg_datum = unpack_datum!( - bcx, arg_datum.to_rvalue_datum(bcx, "arg")); - - // Now that arg_datum is owned, get it into the appropriate - // mode (ref vs value). - let arg_datum = unpack_datum!(bcx, if want_by_ref { - arg_datum.to_ref_datum(bcx) - } else { - arg_datum.to_appropriate_datum(bcx) - }); - - // Technically, ownership of val passes to the callee. - // However, we must cleanup should we panic before the - // callee is actually invoked. - (arg_datum.kind.is_by_ref(), - arg_datum.add_clean(bcx.fcx, arg_cleanup_scope)) - }; - - if arg.is_ignore() { - return bcx; - } - - debug!("--- trans_arg_datum passing {:?}", Value(val)); - - if fat_ptr { - // Fat pointers should be passed without any transformations. - assert!(!arg.is_indirect() && arg.cast.is_none()); - llargs.push(Load(bcx, expr::get_dataptr(bcx, val))); - - let info_arg = &fn_ty.args[*next_idx]; - *next_idx += 1; - assert!(!info_arg.is_indirect() && info_arg.cast.is_none()); - let info = Load(bcx, expr::get_meta(bcx, val)); - - if let Virtual(idx) = *callee { - // We have to grab the fn pointer from the vtable when - // handling the first argument, ensure that here. - assert_eq!(*next_idx, 2); - assert!(info_arg.is_ignore()); - let fn_ptr = meth::get_virtual_method(bcx, info, idx); - let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to(); - *callee = Fn(PointerCast(bcx, fn_ptr, llty)); - } else { - assert!(!info_arg.is_ignore()); - llargs.push(info); - } - return bcx; - } - - let mut val = val; - if by_ref && !arg.is_indirect() { - // Have to load the argument, maybe while casting it. - if arg.original_ty == Type::i1(bcx.ccx()) { - // We store bools as i8 so we need to truncate to i1. - val = LoadRangeAssert(bcx, val, 0, 2, llvm::False); - val = Trunc(bcx, val, arg.original_ty); - } else if let Some(ty) = arg.cast { - val = Load(bcx, PointerCast(bcx, val, ty.ptr_to())); - if !bcx.unreachable.get() { - let llalign = llalign_of_min(bcx.ccx(), arg.ty); - unsafe { - llvm::LLVMSetAlignment(val, llalign); - } - } - } else { - val = Load(bcx, val); - } - } - - llargs.push(val); - bcx -} diff --git a/src/librustc_trans/cleanup.rs b/src/librustc_trans/cleanup.rs index 3081f055bb4dd..d368ce47430b7 100644 --- a/src/librustc_trans/cleanup.rs +++ b/src/librustc_trans/cleanup.rs @@ -114,37 +114,22 @@ //! code for `expr` itself is responsible for freeing any other byproducts //! that may be in play. -pub use self::ScopeId::*; -pub use self::CleanupScopeKind::*; pub use self::EarlyExitLabel::*; -pub use self::Heap::*; use llvm::{BasicBlockRef, ValueRef}; use base; use build; use common; -use common::{Block, FunctionContext, NodeIdAndSpan, LandingPad}; -use datum::{Datum, Lvalue}; -use debuginfo::{DebugLoc, ToDebugLoc}; +use common::{Block, FunctionContext, LandingPad}; +use debuginfo::{DebugLoc}; use glue; -use middle::region; use type_::Type; use value::Value; -use rustc::ty::{Ty, TyCtxt}; - -use std::fmt; -use syntax::ast; - -pub struct CleanupScope<'blk, 'tcx: 'blk> { - // The id of this cleanup scope. If the id is None, - // this is a *temporary scope* that is pushed during trans to - // cleanup miscellaneous garbage that trans may generate whose - // lifetime is a subset of some expression. See module doc for - // more details. - kind: CleanupScopeKind<'blk, 'tcx>, +use rustc::ty::Ty; +pub struct CleanupScope<'tcx> { // Cleanups to run upon scope exit. - cleanups: Vec>, + cleanups: Vec>, // The debug location any drop calls generated for this scope will be // associated with. @@ -159,37 +144,9 @@ pub struct CustomScopeIndex { index: usize } -pub const EXIT_BREAK: usize = 0; -pub const EXIT_LOOP: usize = 1; -pub const EXIT_MAX: usize = 2; - -pub enum CleanupScopeKind<'blk, 'tcx: 'blk> { - CustomScopeKind, - AstScopeKind(ast::NodeId), - LoopScopeKind(ast::NodeId, [Block<'blk, 'tcx>; EXIT_MAX]) -} - -impl<'blk, 'tcx: 'blk> fmt::Debug for CleanupScopeKind<'blk, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CustomScopeKind => write!(f, "CustomScopeKind"), - AstScopeKind(nid) => write!(f, "AstScopeKind({})", nid), - LoopScopeKind(nid, ref blks) => { - write!(f, "LoopScopeKind({}, [", nid)?; - for blk in blks { - write!(f, "{:p}, ", blk)?; - } - write!(f, "])") - } - } - } -} - #[derive(Copy, Clone, PartialEq, Debug)] pub enum EarlyExitLabel { UnwindExit(UnwindKind), - ReturnExit, - LoopExit(ast::NodeId, usize) } #[derive(Copy, Clone, Debug)] @@ -205,97 +162,8 @@ pub struct CachedEarlyExit { last_cleanup: usize, } -pub trait Cleanup<'tcx> { - fn must_unwind(&self) -> bool; - fn is_lifetime_end(&self) -> bool; - fn trans<'blk>(&self, - bcx: Block<'blk, 'tcx>, - debug_loc: DebugLoc) - -> Block<'blk, 'tcx>; -} - -pub type CleanupObj<'tcx> = Box+'tcx>; - -#[derive(Copy, Clone, Debug)] -pub enum ScopeId { - AstScope(ast::NodeId), - CustomScope(CustomScopeIndex) -} - -#[derive(Copy, Clone, Debug)] -pub struct DropHint(pub ast::NodeId, pub K); - -pub type DropHintDatum<'tcx> = DropHint>; -pub type DropHintValue = DropHint; - -impl DropHint { - pub fn new(id: ast::NodeId, k: K) -> DropHint { DropHint(id, k) } -} - -impl DropHint { - pub fn value(&self) -> ValueRef { self.1 } -} - -pub trait DropHintMethods { - type ValueKind; - fn to_value(&self) -> Self::ValueKind; -} -impl<'tcx> DropHintMethods for DropHintDatum<'tcx> { - type ValueKind = DropHintValue; - fn to_value(&self) -> DropHintValue { DropHint(self.0, self.1.val) } -} - -impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { - /// Invoked when we start to trans the code contained within a new cleanup scope. - fn push_ast_cleanup_scope(&self, debug_loc: NodeIdAndSpan) { - debug!("push_ast_cleanup_scope({})", - self.ccx.tcx().map.node_to_string(debug_loc.id)); - - // FIXME(#2202) -- currently closure bodies have a parent - // region, which messes up the assertion below, since there - // are no cleanup scopes on the stack at the start of - // trans'ing a closure body. I think though that this should - // eventually be fixed by closure bodies not having a parent - // region, though that's a touch unclear, and it might also be - // better just to narrow this assertion more (i.e., by - // excluding id's that correspond to closure bodies only). For - // now we just say that if there is already an AST scope on the stack, - // this new AST scope had better be its immediate child. - let top_scope = self.top_ast_scope(); - let region_maps = &self.ccx.tcx().region_maps; - if top_scope.is_some() { - assert!((region_maps - .opt_encl_scope(region_maps.node_extent(debug_loc.id)) - .map(|s|s.node_id(region_maps)) == top_scope) - || - (region_maps - .opt_encl_scope(region_maps.lookup_code_extent( - region::CodeExtentData::DestructionScope(debug_loc.id))) - .map(|s|s.node_id(region_maps)) == top_scope)); - } - - self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id), - debug_loc.debug_loc())); - } - - fn push_loop_cleanup_scope(&self, - id: ast::NodeId, - exits: [Block<'blk, 'tcx>; EXIT_MAX]) { - debug!("push_loop_cleanup_scope({})", - self.ccx.tcx().map.node_to_string(id)); - assert_eq!(Some(id), self.top_ast_scope()); - - // Just copy the debuginfo source location from the enclosing scope - let debug_loc = self.scopes - .borrow() - .last() - .unwrap() - .debug_loc; - - self.push_scope(CleanupScope::new(LoopScopeKind(id, exits), debug_loc)); - } - - fn push_custom_cleanup_scope(&self) -> CustomScopeIndex { +impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { + pub fn push_custom_cleanup_scope(&self) -> CustomScopeIndex { let index = self.scopes_len(); debug!("push_custom_cleanup_scope(): {}", index); @@ -306,53 +174,14 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { .map(|opt_scope| opt_scope.debug_loc) .unwrap_or(DebugLoc::None); - self.push_scope(CleanupScope::new(CustomScopeKind, debug_loc)); - CustomScopeIndex { index: index } - } - - fn push_custom_cleanup_scope_with_debug_loc(&self, - debug_loc: NodeIdAndSpan) - -> CustomScopeIndex { - let index = self.scopes_len(); - debug!("push_custom_cleanup_scope(): {}", index); - - self.push_scope(CleanupScope::new(CustomScopeKind, - debug_loc.debug_loc())); + self.push_scope(CleanupScope::new(debug_loc)); CustomScopeIndex { index: index } } - /// Removes the cleanup scope for id `cleanup_scope`, which must be at the top of the cleanup - /// stack, and generates the code to do its cleanups for normal exit. - fn pop_and_trans_ast_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, - cleanup_scope: ast::NodeId) - -> Block<'blk, 'tcx> { - debug!("pop_and_trans_ast_cleanup_scope({})", - self.ccx.tcx().map.node_to_string(cleanup_scope)); - - assert!(self.top_scope(|s| s.kind.is_ast_with_id(cleanup_scope))); - - let scope = self.pop_scope(); - self.trans_scope_cleanups(bcx, &scope) - } - - /// Removes the loop cleanup scope for id `cleanup_scope`, which must be at the top of the - /// cleanup stack. Does not generate any cleanup code, since loop scopes should exit by - /// branching to a block generated by `normal_exit_block`. - fn pop_loop_cleanup_scope(&self, - cleanup_scope: ast::NodeId) { - debug!("pop_loop_cleanup_scope({})", - self.ccx.tcx().map.node_to_string(cleanup_scope)); - - assert!(self.top_scope(|s| s.kind.is_loop_with_id(cleanup_scope))); - - let _ = self.pop_scope(); - } - /// Removes the top cleanup scope from the stack without executing its cleanups. The top /// cleanup scope must be the temporary scope `custom_scope`. - fn pop_custom_cleanup_scope(&self, - custom_scope: CustomScopeIndex) { + pub fn pop_custom_cleanup_scope(&self, + custom_scope: CustomScopeIndex) { debug!("pop_custom_cleanup_scope({})", custom_scope.index); assert!(self.is_valid_to_pop_custom_scope(custom_scope)); let _ = self.pop_scope(); @@ -360,10 +189,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { /// Removes the top cleanup scope from the stack, which must be a temporary scope, and /// generates the code to do its cleanups for normal exit. - fn pop_and_trans_custom_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, - custom_scope: CustomScopeIndex) - -> Block<'blk, 'tcx> { + pub fn pop_and_trans_custom_cleanup_scope(&self, + bcx: Block<'blk, 'tcx>, + custom_scope: CustomScopeIndex) + -> Block<'blk, 'tcx> { debug!("pop_and_trans_custom_cleanup_scope({:?})", custom_scope); assert!(self.is_valid_to_pop_custom_scope(custom_scope)); @@ -371,100 +200,27 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { self.trans_scope_cleanups(bcx, &scope) } - /// Returns the id of the top-most loop scope - fn top_loop_scope(&self) -> ast::NodeId { - for scope in self.scopes.borrow().iter().rev() { - if let LoopScopeKind(id, _) = scope.kind { - return id; - } - } - bug!("no loop scope found"); - } - - /// Returns a block to branch to which will perform all pending cleanups and - /// then break/continue (depending on `exit`) out of the loop with id - /// `cleanup_scope` - fn normal_exit_block(&'blk self, - cleanup_scope: ast::NodeId, - exit: usize) -> BasicBlockRef { - self.trans_cleanups_to_exit_scope(LoopExit(cleanup_scope, exit)) - } - - /// Returns a block to branch to which will perform all pending cleanups and - /// then return from this function - fn return_exit_block(&'blk self) -> BasicBlockRef { - self.trans_cleanups_to_exit_scope(ReturnExit) - } - - fn schedule_lifetime_end(&self, - cleanup_scope: ScopeId, - val: ValueRef) { - let drop = box LifetimeEnd { - ptr: val, - }; - - debug!("schedule_lifetime_end({:?}, val={:?})", - cleanup_scope, Value(val)); - - self.schedule_clean(cleanup_scope, drop as CleanupObj); - } - /// Schedules a (deep) drop of `val`, which is a pointer to an instance of /// `ty` - fn schedule_drop_mem(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>, - drop_hint: Option>) { + pub fn schedule_drop_mem(&self, + cleanup_scope: CustomScopeIndex, + val: ValueRef, + ty: Ty<'tcx>) { if !self.type_needs_drop(ty) { return; } - let drop_hint = drop_hint.map(|hint|hint.to_value()); - let drop = box DropValue { + let drop = DropValue { is_immediate: false, val: val, ty: ty, - fill_on_drop: false, skip_dtor: false, - drop_hint: drop_hint, }; - debug!("schedule_drop_mem({:?}, val={:?}, ty={:?}) fill_on_drop={} skip_dtor={}", + debug!("schedule_drop_mem({:?}, val={:?}, ty={:?}) skip_dtor={}", cleanup_scope, Value(val), ty, - drop.fill_on_drop, drop.skip_dtor); - self.schedule_clean(cleanup_scope, drop as CleanupObj); - } - - /// Schedules a (deep) drop and filling of `val`, which is a pointer to an instance of `ty` - fn schedule_drop_and_fill_mem(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>, - drop_hint: Option>) { - if !self.type_needs_drop(ty) { return; } - - let drop_hint = drop_hint.map(|datum|datum.to_value()); - let drop = box DropValue { - is_immediate: false, - val: val, - ty: ty, - fill_on_drop: true, - skip_dtor: false, - drop_hint: drop_hint, - }; - - debug!("schedule_drop_and_fill_mem({:?}, val={:?}, ty={:?}, - fill_on_drop={}, skip_dtor={}, has_drop_hint={})", - cleanup_scope, - Value(val), - ty, - drop.fill_on_drop, - drop.skip_dtor, - drop_hint.is_some()); - - self.schedule_clean(cleanup_scope, drop as CleanupObj); + self.schedule_clean(cleanup_scope, drop); } /// Issue #23611: Schedules a (deep) drop of the contents of @@ -472,110 +228,55 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { /// `ty`. The scheduled code handles extracting the discriminant /// and dropping the contents associated with that variant /// *without* executing any associated drop implementation. - fn schedule_drop_adt_contents(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>) { + pub fn schedule_drop_adt_contents(&self, + cleanup_scope: CustomScopeIndex, + val: ValueRef, + ty: Ty<'tcx>) { // `if` below could be "!contents_needs_drop"; skipping drop // is just an optimization, so sound to be conservative. if !self.type_needs_drop(ty) { return; } - let drop = box DropValue { + let drop = DropValue { is_immediate: false, val: val, ty: ty, - fill_on_drop: false, skip_dtor: true, - drop_hint: None, }; - debug!("schedule_drop_adt_contents({:?}, val={:?}, ty={:?}) fill_on_drop={} skip_dtor={}", + debug!("schedule_drop_adt_contents({:?}, val={:?}, ty={:?}) skip_dtor={}", cleanup_scope, Value(val), ty, - drop.fill_on_drop, drop.skip_dtor); - self.schedule_clean(cleanup_scope, drop as CleanupObj); + self.schedule_clean(cleanup_scope, drop); } /// Schedules a (deep) drop of `val`, which is an instance of `ty` - fn schedule_drop_immediate(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>) { + pub fn schedule_drop_immediate(&self, + cleanup_scope: CustomScopeIndex, + val: ValueRef, + ty: Ty<'tcx>) { if !self.type_needs_drop(ty) { return; } - let drop = Box::new(DropValue { + let drop = DropValue { is_immediate: true, val: val, ty: ty, - fill_on_drop: false, skip_dtor: false, - drop_hint: None, - }); + }; - debug!("schedule_drop_immediate({:?}, val={:?}, ty={:?}) fill_on_drop={} skip_dtor={}", + debug!("schedule_drop_immediate({:?}, val={:?}, ty={:?}) skip_dtor={}", cleanup_scope, Value(val), ty, - drop.fill_on_drop, drop.skip_dtor); - self.schedule_clean(cleanup_scope, drop as CleanupObj); - } - - /// Schedules a call to `free(val)`. Note that this is a shallow operation. - fn schedule_free_value(&self, - cleanup_scope: ScopeId, - val: ValueRef, - heap: Heap, - content_ty: Ty<'tcx>) { - let drop = box FreeValue { ptr: val, heap: heap, content_ty: content_ty }; - - debug!("schedule_free_value({:?}, val={:?}, heap={:?})", - cleanup_scope, Value(val), heap); - - self.schedule_clean(cleanup_scope, drop as CleanupObj); - } - - fn schedule_clean(&self, - cleanup_scope: ScopeId, - cleanup: CleanupObj<'tcx>) { - match cleanup_scope { - AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup), - CustomScope(id) => self.schedule_clean_in_custom_scope(id, cleanup), - } - } - - /// Schedules a cleanup to occur upon exit from `cleanup_scope`. If `cleanup_scope` is not - /// provided, then the cleanup is scheduled in the topmost scope, which must be a temporary - /// scope. - fn schedule_clean_in_ast_scope(&self, - cleanup_scope: ast::NodeId, - cleanup: CleanupObj<'tcx>) { - debug!("schedule_clean_in_ast_scope(cleanup_scope={})", - cleanup_scope); - - for scope in self.scopes.borrow_mut().iter_mut().rev() { - if scope.kind.is_ast_with_id(cleanup_scope) { - scope.cleanups.push(cleanup); - scope.cached_landing_pad = None; - return; - } else { - // will be adding a cleanup to some enclosing scope - scope.clear_cached_exits(); - } - } - - bug!("no cleanup scope {} found", - self.ccx.tcx().map.node_to_string(cleanup_scope)); + self.schedule_clean(cleanup_scope, drop); } /// Schedules a cleanup to occur in the top-most scope, which must be a temporary scope. - fn schedule_clean_in_custom_scope(&self, - custom_scope: CustomScopeIndex, - cleanup: CleanupObj<'tcx>) { + fn schedule_clean(&self, custom_scope: CustomScopeIndex, cleanup: DropValue<'tcx>) { debug!("schedule_clean_in_custom_scope(custom_scope={})", custom_scope.index); @@ -588,14 +289,14 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { } /// Returns true if there are pending cleanups that should execute on panic. - fn needs_invoke(&self) -> bool { + pub fn needs_invoke(&self) -> bool { self.scopes.borrow().iter().rev().any(|s| s.needs_invoke()) } /// Returns a basic block to branch to in the event of a panic. This block /// will run the panic cleanups and eventually resume the exception that /// caused the landing pad to be run. - fn get_landing_pad(&'blk self) -> BasicBlockRef { + pub fn get_landing_pad(&'blk self) -> BasicBlockRef { let _icx = base::push_ctxt("get_landing_pad"); debug!("get_landing_pad"); @@ -625,25 +326,6 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { return llbb; } -} - -impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { - /// Returns the id of the current top-most AST scope, if any. - fn top_ast_scope(&self) -> Option { - for scope in self.scopes.borrow().iter().rev() { - match scope.kind { - CustomScopeKind | LoopScopeKind(..) => {} - AstScopeKind(i) => { - return Some(i); - } - } - } - None - } - - fn top_nonempty_cleanup_scope(&self) -> Option { - self.scopes.borrow().iter().rev().position(|s| !s.cleanups.is_empty()) - } fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool { self.is_valid_custom_scope(custom_scope) && @@ -652,14 +334,13 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx fn is_valid_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool { let scopes = self.scopes.borrow(); - custom_scope.index < scopes.len() && - (*scopes)[custom_scope.index].kind.is_temp() + custom_scope.index < scopes.len() } /// Generates the cleanups for `scope` into `bcx` fn trans_scope_cleanups(&self, // cannot borrow self, will recurse bcx: Block<'blk, 'tcx>, - scope: &CleanupScope<'blk, 'tcx>) -> Block<'blk, 'tcx> { + scope: &CleanupScope<'tcx>) -> Block<'blk, 'tcx> { let mut bcx = bcx; if !bcx.unreachable.get() { @@ -674,11 +355,11 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx self.scopes.borrow().len() } - fn push_scope(&self, scope: CleanupScope<'blk, 'tcx>) { + fn push_scope(&self, scope: CleanupScope<'tcx>) { self.scopes.borrow_mut().push(scope) } - fn pop_scope(&self) -> CleanupScope<'blk, 'tcx> { + fn pop_scope(&self) -> CleanupScope<'tcx> { debug!("popping cleanup scope {}, {} scopes remaining", self.top_scope(|s| s.block_name("")), self.scopes_len() - 1); @@ -686,7 +367,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx self.scopes.borrow_mut().pop().unwrap() } - fn top_scope(&self, f: F) -> R where F: FnOnce(&CleanupScope<'blk, 'tcx>) -> R { + fn top_scope(&self, f: F) -> R where F: FnOnce(&CleanupScope<'tcx>) -> R { f(self.scopes.borrow().last().unwrap()) } @@ -738,7 +419,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx UnwindExit(val) => { // Generate a block that will resume unwinding to the // calling function - let bcx = self.new_block("resume", None); + let bcx = self.new_block("resume"); match val { UnwindKind::LandingPad => { let addr = self.landingpad_alloca.get() @@ -755,15 +436,6 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx prev_llbb = bcx.llbb; break; } - - ReturnExit => { - prev_llbb = self.get_llreturn(); - break - } - - LoopExit(id, _) => { - bug!("cannot exit from scope {}, not in scope", id); - } } } @@ -782,20 +454,6 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx skip = last_cleanup; break; } - - // If we are searching for a loop exit, - // and this scope is that loop, then stop popping and set - // `prev_llbb` to the appropriate exit block from the loop. - let scope = popped_scopes.last().unwrap(); - match label { - UnwindExit(..) | ReturnExit => { } - LoopExit(id, exit) => { - if let Some(exit) = scope.kind.early_exit_block(id, exit) { - prev_llbb = exit; - break - } - } - } } debug!("trans_cleanups_to_exit_scope: popped {} scopes", @@ -826,7 +484,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx let name = scope.block_name("clean"); debug!("generating cleanups for {}", name); - let bcx_in = self.new_block(&name[..], None); + let bcx_in = self.new_block(&name[..]); let exit_label = label.start(bcx_in); let mut bcx_out = bcx_in; let len = scope.cleanups.len(); @@ -869,7 +527,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx Some(llbb) => return llbb, None => { let name = last_scope.block_name("unwind"); - pad_bcx = self.new_block(&name[..], None); + pad_bcx = self.new_block(&name[..]); last_scope.cached_landing_pad = Some(pad_bcx.llbb); } } @@ -923,12 +581,9 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx } } -impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> { - fn new(kind: CleanupScopeKind<'blk, 'tcx>, - debug_loc: DebugLoc) - -> CleanupScope<'blk, 'tcx> { +impl<'tcx> CleanupScope<'tcx> { + fn new(debug_loc: DebugLoc) -> CleanupScope<'tcx> { CleanupScope { - kind: kind, debug_loc: debug_loc, cleanups: vec!(), cached_early_exits: vec!(), @@ -936,11 +591,6 @@ impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> { } } - fn clear_cached_exits(&mut self) { - self.cached_early_exits = vec!(); - self.cached_landing_pad = None; - } - fn cached_early_exit(&self, label: EarlyExitLabel) -> Option<(BasicBlockRef, usize)> { @@ -961,62 +611,13 @@ impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> { /// True if this scope has cleanups that need unwinding fn needs_invoke(&self) -> bool { - self.cached_landing_pad.is_some() || - self.cleanups.iter().any(|c| c.must_unwind()) + !self.cleanups.is_empty() } /// Returns a suitable name to use for the basic block that handles this cleanup scope fn block_name(&self, prefix: &str) -> String { - match self.kind { - CustomScopeKind => format!("{}_custom_", prefix), - AstScopeKind(id) => format!("{}_ast_{}_", prefix, id), - LoopScopeKind(id, _) => format!("{}_loop_{}_", prefix, id), - } - } - - /// Manipulate cleanup scope for call arguments. Conceptually, each - /// argument to a call is an lvalue, and performing the call moves each - /// of the arguments into a new rvalue (which gets cleaned up by the - /// callee). As an optimization, instead of actually performing all of - /// those moves, trans just manipulates the cleanup scope to obtain the - /// same effect. - pub fn drop_non_lifetime_clean(&mut self) { - self.cleanups.retain(|c| c.is_lifetime_end()); - self.clear_cached_exits(); - } -} - -impl<'blk, 'tcx> CleanupScopeKind<'blk, 'tcx> { - fn is_temp(&self) -> bool { - match *self { - CustomScopeKind => true, - LoopScopeKind(..) | AstScopeKind(..) => false, - } - } - - fn is_ast_with_id(&self, id: ast::NodeId) -> bool { - match *self { - CustomScopeKind | LoopScopeKind(..) => false, - AstScopeKind(i) => i == id - } - } - - fn is_loop_with_id(&self, id: ast::NodeId) -> bool { - match *self { - CustomScopeKind | AstScopeKind(..) => false, - LoopScopeKind(i, _) => i == id - } - } - - /// If this is a loop scope with id `id`, return the early exit block `exit`, else `None` - fn early_exit_block(&self, - id: ast::NodeId, - exit: usize) -> Option { - match *self { - LoopScopeKind(i, ref exits) if id == i => Some(exits[exit].llbb), - _ => None, - } + format!("{}_custom_", prefix) } } @@ -1057,7 +658,6 @@ impl EarlyExitLabel { bcx.lpad.set(Some(bcx.fcx.lpad_arena.alloc(LandingPad::gnu()))); *self } - label => label, } } } @@ -1080,20 +680,10 @@ pub struct DropValue<'tcx> { is_immediate: bool, val: ValueRef, ty: Ty<'tcx>, - fill_on_drop: bool, skip_dtor: bool, - drop_hint: Option, } -impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { - fn must_unwind(&self) -> bool { - true - } - - fn is_lifetime_end(&self) -> bool { - false - } - +impl<'tcx> DropValue<'tcx> { fn trans<'blk>(&self, bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc) @@ -1107,180 +697,8 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { let bcx = if self.is_immediate { glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc, self.skip_dtor) } else { - glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor, self.drop_hint) + glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor) }; - if self.fill_on_drop { - base::drop_done_fill_mem(bcx, self.val, self.ty); - } bcx } } - -#[derive(Copy, Clone, Debug)] -pub enum Heap { - HeapExchange -} - -#[derive(Copy, Clone)] -pub struct FreeValue<'tcx> { - ptr: ValueRef, - heap: Heap, - content_ty: Ty<'tcx> -} - -impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> { - fn must_unwind(&self) -> bool { - true - } - - fn is_lifetime_end(&self) -> bool { - false - } - - fn trans<'blk>(&self, - bcx: Block<'blk, 'tcx>, - debug_loc: DebugLoc) - -> Block<'blk, 'tcx> { - match self.heap { - HeapExchange => { - glue::trans_exchange_free_ty(bcx, - self.ptr, - self.content_ty, - debug_loc) - } - } - } -} - -#[derive(Copy, Clone)] -pub struct LifetimeEnd { - ptr: ValueRef, -} - -impl<'tcx> Cleanup<'tcx> for LifetimeEnd { - fn must_unwind(&self) -> bool { - false - } - - fn is_lifetime_end(&self) -> bool { - true - } - - fn trans<'blk>(&self, - bcx: Block<'blk, 'tcx>, - debug_loc: DebugLoc) - -> Block<'blk, 'tcx> { - debug_loc.apply(bcx.fcx); - base::call_lifetime_end(bcx, self.ptr); - bcx - } -} - -pub fn temporary_scope(tcx: TyCtxt, - id: ast::NodeId) - -> ScopeId { - match tcx.region_maps.temporary_scope(id) { - Some(scope) => { - let r = AstScope(scope.node_id(&tcx.region_maps)); - debug!("temporary_scope({}) = {:?}", id, r); - r - } - None => { - bug!("no temporary scope available for expr {}", id) - } - } -} - -pub fn var_scope(tcx: TyCtxt, - id: ast::NodeId) - -> ScopeId { - let r = AstScope(tcx.region_maps.var_scope(id).node_id(&tcx.region_maps)); - debug!("var_scope({}) = {:?}", id, r); - r -} - -/////////////////////////////////////////////////////////////////////////// -// These traits just exist to put the methods into this file. - -pub trait CleanupMethods<'blk, 'tcx> { - fn push_ast_cleanup_scope(&self, id: NodeIdAndSpan); - fn push_loop_cleanup_scope(&self, - id: ast::NodeId, - exits: [Block<'blk, 'tcx>; EXIT_MAX]); - fn push_custom_cleanup_scope(&self) -> CustomScopeIndex; - fn push_custom_cleanup_scope_with_debug_loc(&self, - debug_loc: NodeIdAndSpan) - -> CustomScopeIndex; - fn pop_and_trans_ast_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, - cleanup_scope: ast::NodeId) - -> Block<'blk, 'tcx>; - fn pop_loop_cleanup_scope(&self, - cleanup_scope: ast::NodeId); - fn pop_custom_cleanup_scope(&self, - custom_scope: CustomScopeIndex); - fn pop_and_trans_custom_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, - custom_scope: CustomScopeIndex) - -> Block<'blk, 'tcx>; - fn top_loop_scope(&self) -> ast::NodeId; - fn normal_exit_block(&'blk self, - cleanup_scope: ast::NodeId, - exit: usize) -> BasicBlockRef; - fn return_exit_block(&'blk self) -> BasicBlockRef; - fn schedule_lifetime_end(&self, - cleanup_scope: ScopeId, - val: ValueRef); - fn schedule_drop_mem(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>, - drop_hint: Option>); - fn schedule_drop_and_fill_mem(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>, - drop_hint: Option>); - fn schedule_drop_adt_contents(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>); - fn schedule_drop_immediate(&self, - cleanup_scope: ScopeId, - val: ValueRef, - ty: Ty<'tcx>); - fn schedule_free_value(&self, - cleanup_scope: ScopeId, - val: ValueRef, - heap: Heap, - content_ty: Ty<'tcx>); - fn schedule_clean(&self, - cleanup_scope: ScopeId, - cleanup: CleanupObj<'tcx>); - fn schedule_clean_in_ast_scope(&self, - cleanup_scope: ast::NodeId, - cleanup: CleanupObj<'tcx>); - fn schedule_clean_in_custom_scope(&self, - custom_scope: CustomScopeIndex, - cleanup: CleanupObj<'tcx>); - fn needs_invoke(&self) -> bool; - fn get_landing_pad(&'blk self) -> BasicBlockRef; -} - -trait CleanupHelperMethods<'blk, 'tcx> { - fn top_ast_scope(&self) -> Option; - fn top_nonempty_cleanup_scope(&self) -> Option; - fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool; - fn is_valid_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool; - fn trans_scope_cleanups(&self, - bcx: Block<'blk, 'tcx>, - scope: &CleanupScope<'blk, 'tcx>) -> Block<'blk, 'tcx>; - fn trans_cleanups_to_exit_scope(&'blk self, - label: EarlyExitLabel) - -> BasicBlockRef; - fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef; - fn scopes_len(&self) -> usize; - fn push_scope(&self, scope: CleanupScope<'blk, 'tcx>); - fn pop_scope(&self) -> CleanupScope<'blk, 'tcx>; - fn top_scope(&self, f: F) -> R where F: FnOnce(&CleanupScope<'blk, 'tcx>) -> R; -} diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index e0fa8df1100ac..842a8fddb83e1 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -10,113 +10,21 @@ use arena::TypedArena; use back::symbol_names; -use llvm::{self, ValueRef, get_param, get_params}; +use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use abi::{Abi, FnType}; -use adt; use attributes; use base::*; -use build::*; -use callee::{self, ArgVals, Callee}; -use cleanup::{CleanupMethods, CustomScope, ScopeId}; +use callee::{self, Callee}; use common::*; -use datum::{ByRef, Datum, lvalue_scratch_datum}; -use datum::{rvalue_scratch_datum, Rvalue}; -use debuginfo::{self, DebugLoc}; +use debuginfo::{DebugLoc}; use declare; -use expr; use monomorphize::{Instance}; use value::Value; -use Disr; use rustc::ty::{self, Ty, TyCtxt}; -use session::config::FullDebugInfo; - -use syntax::ast; use rustc::hir; -use libc::c_uint; - -fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - closure_def_id: DefId, - arg_scope_id: ScopeId, - id: ast::NodeId) { - let _icx = push_ctxt("closure::load_closure_environment"); - let kind = kind_for_closure(bcx.ccx(), closure_def_id); - - let env_arg = &bcx.fcx.fn_ty.args[0]; - let mut env_idx = bcx.fcx.fn_ty.ret.is_indirect() as usize; - - // Special case for small by-value selfs. - let llenv = if kind == ty::ClosureKind::FnOnce && !env_arg.is_indirect() { - let closure_ty = node_id_type(bcx, id); - let llenv = rvalue_scratch_datum(bcx, closure_ty, "closure_env").val; - env_arg.store_fn_arg(&bcx.build(), &mut env_idx, llenv); - llenv - } else { - get_param(bcx.fcx.llfn, env_idx as c_uint) - }; - - // Store the pointer to closure data in an alloca for debug info because that's what the - // llvm.dbg.declare intrinsic expects - let env_pointer_alloca = if bcx.sess().opts.debuginfo == FullDebugInfo { - let alloc = alloca(bcx, val_ty(llenv), "__debuginfo_env_ptr"); - Store(bcx, llenv, alloc); - Some(alloc) - } else { - None - }; - - bcx.tcx().with_freevars(id, |fv| { - for (i, freevar) in fv.iter().enumerate() { - let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(), - closure_expr_id: id }; - let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap(); - let mut upvar_ptr = StructGEP(bcx, llenv, i); - let captured_by_ref = match upvar_capture { - ty::UpvarCapture::ByValue => false, - ty::UpvarCapture::ByRef(..) => { - upvar_ptr = Load(bcx, upvar_ptr); - true - } - }; - let node_id = freevar.def.var_id(); - bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr); - - if kind == ty::ClosureKind::FnOnce && !captured_by_ref { - let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id); - bcx.fcx.schedule_drop_mem(arg_scope_id, - upvar_ptr, - node_id_type(bcx, node_id), - hint) - } - - if let Some(env_pointer_alloca) = env_pointer_alloca { - debuginfo::create_captured_var_metadata( - bcx, - node_id, - env_pointer_alloca, - i, - captured_by_ref, - freevar.span); - } - } - }) -} - -pub enum ClosureEnv { - NotClosure, - Closure(DefId, ast::NodeId), -} - -impl ClosureEnv { - pub fn load<'blk,'tcx>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId) { - if let ClosureEnv::Closure(def_id, id) = self { - load_closure_environment(bcx, def_id, arg_scope, id); - } - } -} - fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, closure_id: DefId, fn_ty: Ty<'tcx>) @@ -184,55 +92,12 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, closure_def_id: DefId, closure_substs: ty::ClosureSubsts<'tcx>) { - use syntax::ast::DUMMY_NODE_ID; - use syntax_pos::DUMMY_SP; - use syntax::ptr::P; - - trans_closure_expr(Dest::Ignore(ccx), - &hir::FnDecl { - inputs: P::new(), - output: hir::Return(P(hir::Ty { - id: DUMMY_NODE_ID, - span: DUMMY_SP, - node: hir::Ty_::TyNever, - })), - variadic: false - }, - &hir::Block { - stmts: P::new(), - expr: None, - id: DUMMY_NODE_ID, - rules: hir::DefaultBlock, - span: DUMMY_SP - }, - DUMMY_NODE_ID, - closure_def_id, - closure_substs); -} - -pub enum Dest<'a, 'tcx: 'a> { - SaveIn(Block<'a, 'tcx>, ValueRef), - Ignore(&'a CrateContext<'a, 'tcx>) -} - -pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, - decl: &hir::FnDecl, - body: &hir::Block, - id: ast::NodeId, - closure_def_id: DefId, // (*) - closure_substs: ty::ClosureSubsts<'tcx>) - -> Option> -{ // (*) Note that in the case of inlined functions, the `closure_def_id` will be the // defid of the closure in its original crate, whereas `id` will be the id of the local // inlined copy. - debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})", - id, closure_def_id, closure_substs); + debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})", + closure_def_id, closure_substs); - let ccx = match dest { - Dest::SaveIn(bcx, _) => bcx.ccx(), - Dest::Ignore(ccx) => ccx - }; let tcx = ccx.tcx(); let _icx = push_ctxt("closure::trans_closure_expr"); @@ -275,52 +140,13 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, }; trans_closure(ccx, - decl, - body, llfn, Instance::new(closure_def_id, param_substs), - id, &sig, - Abi::RustCall, - ClosureEnv::Closure(closure_def_id, id)); + Abi::RustCall); ccx.instances().borrow_mut().insert(instance, llfn); } - - // Don't hoist this to the top of the function. It's perfectly legitimate - // to have a zero-size closure (in which case dest will be `Ignore`) and - // we must still generate the closure body. - let (mut bcx, dest_addr) = match dest { - Dest::SaveIn(bcx, p) => (bcx, p), - Dest::Ignore(_) => { - debug!("trans_closure_expr() ignoring result"); - return None; - } - }; - - let repr = adt::represent_type(ccx, node_id_type(bcx, id)); - - // Create the closure. - tcx.with_freevars(id, |fv| { - for (i, freevar) in fv.iter().enumerate() { - let datum = expr::trans_var(bcx, freevar.def); - let upvar_slot_dest = adt::trans_field_ptr( - bcx, &repr, adt::MaybeSizedValue::sized(dest_addr), Disr(0), i); - let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(), - closure_expr_id: id }; - match tcx.upvar_capture(upvar_id).unwrap() { - ty::UpvarCapture::ByValue => { - bcx = datum.store_to(bcx, upvar_slot_dest); - } - ty::UpvarCapture::ByRef(..) => { - Store(bcx, datum.to_llref(), upvar_slot_dest); - } - } - } - }); - adt::trans_set_discr(bcx, &repr, dest_addr, Disr(0)); - - Some(bcx) } pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, @@ -337,23 +163,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, if !ccx.sess().target.target.options.allows_weak_linkage && !ccx.sess().opts.single_codegen_unit() { - if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) { - // If the closure is defined in the local crate, we can always just - // translate it. - let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node { - hir::ExprClosure(_, ref decl, ref body, _) => (decl, body), - _ => { unreachable!() } - }; - - trans_closure_expr(Dest::Ignore(ccx), - decl, - body, - node_id, - closure_def_id, - substs); - } else { - trans_closure_body_via_mir(ccx, closure_def_id, substs); - } + trans_closure_body_via_mir(ccx, closure_def_id, substs); } // If the closure is a Fn closure, but a FnOnce is needed (etc), @@ -453,28 +263,21 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); - let mut bcx = fcx.init(false, None); + let mut bcx = fcx.init(false); // the first argument (`self`) will be the (by value) closure env. - let self_scope = fcx.push_custom_cleanup_scope(); - let self_scope_id = CustomScope(self_scope); let mut llargs = get_params(fcx.llfn); let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; let env_arg = &fcx.fn_ty.args[0]; let llenv = if env_arg.is_indirect() { - Datum::new(llargs[self_idx], closure_ty, Rvalue::new(ByRef)) - .add_clean(&fcx, self_scope_id) + llargs[self_idx] } else { - unpack_datum!(bcx, lvalue_scratch_datum(bcx, closure_ty, "self", - InitAlloca::Dropped, - self_scope_id, |bcx, llval| { - let mut llarg_idx = self_idx; - env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, llval); - bcx.fcx.schedule_lifetime_end(self_scope_id, llval); - bcx - })).val + let scratch = alloc_ty(bcx, closure_ty, "self"); + let mut llarg_idx = self_idx; + env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); + scratch }; debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); @@ -491,15 +294,19 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( llargs[self_idx] = llenv; } - let dest = - fcx.llretslotptr.get().map( - |_| expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))); + let dest = fcx.llretslotptr.get(); let callee = Callee { data: callee::Fn(llreffn), ty: llref_fn_ty }; - bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx; + + // Call the by-ref closure body with `self` in a cleanup scope, + // to drop `self` when the body returns, or in case it unwinds. + let self_scope = fcx.push_custom_cleanup_scope(); + fcx.schedule_drop_mem(self_scope, llenv, closure_ty); + + bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index b1aaea7d984c9..0823f65a7a1e8 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -16,7 +16,6 @@ use session::Session; use llvm; use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind}; use llvm::{True, False, Bool, OperandBundleDef}; -use rustc::cfg; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; @@ -30,7 +29,6 @@ use builder::Builder; use callee::Callee; use cleanup; use consts; -use datum; use debuginfo::{self, DebugLoc}; use declare; use machine; @@ -43,7 +41,6 @@ use rustc::ty::layout::Layout; use rustc::traits::{self, SelectionContext, Reveal}; use rustc::ty::fold::TypeFoldable; use rustc::hir; -use util::nodemap::NodeMap; use arena::TypedArena; use libc::{c_uint, c_char}; @@ -208,10 +205,6 @@ pub struct NodeIdAndSpan { pub span: Span, } -pub fn expr_info(expr: &hir::Expr) -> NodeIdAndSpan { - NodeIdAndSpan { id: expr.id, span: expr.span } -} - /// The concrete version of ty::FieldDef. The name is the field index if /// the field is numeric. pub struct Field<'tcx>(pub ast::Name, pub Ty<'tcx>); @@ -257,17 +250,6 @@ impl<'a, 'tcx> VariantInfo<'tcx> { } } } - - /// Return the variant corresponding to a given node (e.g. expr) - pub fn of_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, id: ast::NodeId) -> Self { - Self::from_ty(tcx, ty, Some(tcx.expect_def(id))) - } - - pub fn field_index(&self, name: ast::Name) -> usize { - self.fields.iter().position(|&Field(n,_)| n == name).unwrap_or_else(|| { - bug!("unknown field `{}`", name) - }) - } } pub struct BuilderRef_res { @@ -292,37 +274,6 @@ pub fn validate_substs(substs: &Substs) { assert!(!substs.types.needs_infer()); } -// work around bizarre resolve errors -type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; -pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>; - -#[derive(Clone, Debug)] -struct HintEntry<'tcx> { - // The datum for the dropflag-hint itself; note that many - // source-level Lvalues will be associated with the same - // dropflag-hint datum. - datum: cleanup::DropHintDatum<'tcx>, -} - -pub struct DropFlagHintsMap<'tcx> { - // Maps NodeId for expressions that read/write unfragmented state - // to that state's drop-flag "hint." (A stack-local hint - // indicates either that (1.) it is certain that no-drop is - // needed, or (2.) inline drop-flag must be consulted.) - node_map: NodeMap>, -} - -impl<'tcx> DropFlagHintsMap<'tcx> { - pub fn new() -> DropFlagHintsMap<'tcx> { DropFlagHintsMap { node_map: NodeMap() } } - pub fn has_hint(&self, id: ast::NodeId) -> bool { self.node_map.contains_key(&id) } - pub fn insert(&mut self, id: ast::NodeId, datum: cleanup::DropHintDatum<'tcx>) { - self.node_map.insert(id, HintEntry { datum: datum }); - } - pub fn hint_datum(&self, id: ast::NodeId) -> Option> { - self.node_map.get(&id).map(|t|t.datum) - } -} - // Function context. Every LLVM function we create will have one of // these. pub struct FunctionContext<'a, 'tcx: 'a> { @@ -352,12 +303,6 @@ pub struct FunctionContext<'a, 'tcx: 'a> { // A marker for the place where we want to insert the function's static // allocas, so that LLVM will coalesce them into a single alloca call. pub alloca_insert_pt: Cell>, - pub llreturn: Cell>, - - // If the function has any nested return's, including something like: - // fn foo() -> Option { Some(Foo { x: return None }) }, then - // we use a separate alloca for each return - pub needs_ret_allocas: bool, // When working with landingpad-based exceptions this value is alloca'd and // later loaded when using the resume instruction. This ends up being @@ -367,17 +312,6 @@ pub struct FunctionContext<'a, 'tcx: 'a> { // Note that for cleanuppad-based exceptions this is not used. pub landingpad_alloca: Cell>, - // Maps the DefId's for local variables to the allocas created for - // them in llallocas. - pub lllocals: RefCell>>, - - // Same as above, but for closure upvars - pub llupvars: RefCell>, - - // Carries info about drop-flags for local bindings (longer term, - // paths) for the code being compiled. - pub lldropflag_hints: RefCell>, - // Describes the return/argument LLVM types and their ABI handling. pub fn_ty: FnType, @@ -402,9 +336,7 @@ pub struct FunctionContext<'a, 'tcx: 'a> { pub debug_context: debuginfo::FunctionDebugContext, // Cleanup scopes. - pub scopes: RefCell>>, - - pub cfg: Option, + pub scopes: RefCell>>, } impl<'a, 'tcx> FunctionContext<'a, 'tcx> { @@ -420,68 +352,16 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { } } - pub fn get_llreturn(&self) -> BasicBlockRef { - if self.llreturn.get().is_none() { - - self.llreturn.set(Some(unsafe { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, - "return\0".as_ptr() as *const _) - })) - } - - self.llreturn.get().unwrap() - } - - pub fn get_ret_slot(&self, bcx: Block<'a, 'tcx>, name: &str) -> ValueRef { - if self.needs_ret_allocas { - base::alloca(bcx, self.fn_ty.ret.memory_ty(self.ccx), name) - } else { - self.llretslotptr.get().unwrap() - } - } - pub fn new_block(&'a self, - name: &str, - opt_node_id: Option) + name: &str) -> Block<'a, 'tcx> { unsafe { let name = CString::new(name).unwrap(); let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, name.as_ptr()); - BlockS::new(llbb, opt_node_id, self) - } - } - - pub fn new_id_block(&'a self, - name: &str, - node_id: ast::NodeId) - -> Block<'a, 'tcx> { - self.new_block(name, Some(node_id)) - } - - pub fn new_temp_block(&'a self, - name: &str) - -> Block<'a, 'tcx> { - self.new_block(name, None) - } - - pub fn join_blocks(&'a self, - id: ast::NodeId, - in_cxs: &[Block<'a, 'tcx>]) - -> Block<'a, 'tcx> { - let out = self.new_id_block("join", id); - let mut reachable = false; - for bcx in in_cxs { - if !bcx.unreachable.get() { - build::Br(*bcx, out.llbb, DebugLoc::None); - reachable = true; - } - } - if !reachable { - build::Unreachable(out); + BlockS::new(llbb, self) } - return out; } pub fn monomorphize(&self, value: &T) -> T @@ -523,7 +403,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let tcx = ccx.tcx(); match tcx.lang_items.eh_personality() { Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => { - Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx).val + Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx) } _ => { if let Some(llpersonality) = ccx.eh_personality().get() { @@ -565,12 +445,12 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let unwresume = ccx.eh_unwind_resume(); if let Some(llfn) = unwresume.get() { - return Callee::ptr(datum::immediate_rvalue(llfn, ty)); + return Callee::ptr(llfn, ty); } let llfn = declare::declare_fn(ccx, "rust_eh_unwind_resume", ty); attributes::unwind(llfn, true); unwresume.set(Some(llfn)); - Callee::ptr(datum::immediate_rvalue(llfn, ty)) + Callee::ptr(llfn, ty) } } @@ -593,10 +473,6 @@ pub struct BlockS<'blk, 'tcx: 'blk> { // kind of landing pad its in, otherwise this is none. pub lpad: Cell>, - // AST node-id associated with this block, if any. Used for - // debugging purposes only. - pub opt_node_id: Option, - // The function context for the function to which this block is // attached. pub fcx: &'blk FunctionContext<'blk, 'tcx>, @@ -606,7 +482,6 @@ pub type Block<'blk, 'tcx> = &'blk BlockS<'blk, 'tcx>; impl<'blk, 'tcx> BlockS<'blk, 'tcx> { pub fn new(llbb: BasicBlockRef, - opt_node_id: Option, fcx: &'blk FunctionContext<'blk, 'tcx>) -> Block<'blk, 'tcx> { fcx.block_arena.alloc(BlockS { @@ -614,7 +489,6 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { terminated: Cell::new(false), unreachable: Cell::new(false), lpad: Cell::new(None), - opt_node_id: opt_node_id, fcx: fcx }) } @@ -883,13 +757,6 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { } } -pub fn C_floating(s: &str, t: Type) -> ValueRef { - unsafe { - let s = CString::new(s).unwrap(); - llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr()) - } -} - pub fn C_floating_f64(f: f64, t: Type) -> ValueRef { unsafe { llvm::LLVMConstReal(t.to_ref(), f) @@ -1099,24 +966,6 @@ pub fn is_null(val: ValueRef) -> bool { } } -pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { - bcx.fcx.monomorphize(&t) -} - -pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> { - let tcx = bcx.tcx(); - let t = tcx.node_id_to_type(id); - monomorphize_type(bcx, t) -} - -pub fn expr_ty<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) -> Ty<'tcx> { - node_id_type(bcx, ex.id) -} - -pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) -> Ty<'tcx> { - monomorphize_type(bcx, bcx.tcx().expr_ty_adjusted(ex)) -} - /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should /// guarantee to us that all nested obligations *could be* resolved if we wanted to. diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 7382d5f0130cd..c1d855649123a 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -11,98 +11,26 @@ use llvm; use llvm::{SetUnnamedAddr}; -use llvm::{InternalLinkage, ValueRef, Bool, True}; -use middle::const_qualif::ConstQualif; -use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}; -use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err}; -use rustc::hir::def::Def; +use llvm::{InternalLinkage, ValueRef, True}; +use rustc_const_eval::ConstEvalErr; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; -use {abi, adt, closure, debuginfo, expr, machine}; +use {debuginfo, machine}; use base::{self, push_ctxt}; -use callee::Callee; use trans_item::TransItem; -use common::{type_is_sized, C_nil, const_get_elt}; -use common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; -use common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}; -use common::{type_is_fat_ptr, Field, C_vector, C_array, C_null}; -use datum::{Datum, Lvalue}; +use common::{CrateContext, val_ty}; use declare; -use monomorphize::{self, Instance}; +use monomorphize::{Instance}; use type_::Type; use type_of; -use value::Value; -use Disr; -use rustc::ty::subst::Substs; -use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer}; -use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::cast::{CastTy,IntTy}; -use util::nodemap::NodeMap; -use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; +use rustc::ty; use rustc::hir; use std::ffi::{CStr, CString}; -use libc::c_uint; -use syntax::ast::{self, LitKind}; +use syntax::ast; use syntax::attr::{self, AttrMetaMethods}; use syntax::parse::token; -use syntax::ptr::P; -use syntax_pos::Span; - -pub type FnArgMap<'a> = Option<&'a NodeMap>; - -pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit) - -> ValueRef { - let _icx = push_ctxt("trans_lit"); - debug!("const_lit: {:?}", lit); - match lit.node { - LitKind::Byte(b) => C_integral(Type::uint_from_ty(cx, ast::UintTy::U8), b as u64, false), - LitKind::Char(i) => C_integral(Type::char(cx), i as u64, false), - LitKind::Int(i, ast::LitIntType::Signed(t)) => { - C_integral(Type::int_from_ty(cx, t), i, true) - } - LitKind::Int(u, ast::LitIntType::Unsigned(t)) => { - C_integral(Type::uint_from_ty(cx, t), u, false) - } - LitKind::Int(i, ast::LitIntType::Unsuffixed) => { - let lit_int_ty = cx.tcx().node_id_to_type(e.id); - match lit_int_ty.sty { - ty::TyInt(t) => { - C_integral(Type::int_from_ty(cx, t), i as u64, true) - } - ty::TyUint(t) => { - C_integral(Type::uint_from_ty(cx, t), i as u64, false) - } - _ => span_bug!(lit.span, - "integer literal has type {:?} (expected int \ - or usize)", - lit_int_ty) - } - } - LitKind::Float(ref fs, t) => { - C_floating(&fs, Type::float_from_ty(cx, t)) - } - LitKind::FloatUnsuffixed(ref fs) => { - let lit_float_ty = cx.tcx().node_id_to_type(e.id); - match lit_float_ty.sty { - ty::TyFloat(t) => { - C_floating(&fs, Type::float_from_ty(cx, t)) - } - _ => { - span_bug!(lit.span, - "floating point literal doesn't have the right type"); - } - } - } - LitKind::Bool(b) => C_bool(cx, b), - LitKind::Str(ref s, _) => C_str_slice(cx, (*s).clone()), - LitKind::ByteStr(ref data) => { - addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str") - } - } -} pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { unsafe { @@ -154,868 +82,13 @@ pub fn addr_of(ccx: &CrateContext, gv } -/// Deref a constant pointer -pub fn load_const(cx: &CrateContext, v: ValueRef, t: Ty) -> ValueRef { - let v = match cx.const_unsized().borrow().get(&v) { - Some(&v) => v, - None => v - }; - let d = unsafe { llvm::LLVMGetInitializer(v) }; - if !d.is_null() && t.is_bool() { - unsafe { llvm::LLVMConstTrunc(d, Type::i1(cx).to_ref()) } - } else { - d - } -} - -fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - v: ValueRef, - ty: Ty<'tcx>) - -> (ValueRef, Ty<'tcx>) { - match ty.builtin_deref(true, ty::NoPreference) { - Some(mt) => { - if type_is_sized(cx.tcx(), mt.ty) { - (load_const(cx, v, mt.ty), mt.ty) - } else { - // Derefing a fat pointer does not change the representation, - // just the type to the unsized contents. - (v, mt.ty) - } - } - None => { - bug!("unexpected dereferenceable type {:?}", ty) - } - } -} - -fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - arg_vals: &[ValueRef], - param_substs: &'tcx Substs<'tcx>, - trueconst: TrueConst) -> Result { - let fn_like = lookup_const_fn_by_id(ccx.tcx(), def_id); - let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call"); - - let body = match fn_like.body().expr { - Some(ref expr) => expr, - None => return Ok(C_nil(ccx)) - }; - - let args = &fn_like.decl().inputs; - assert_eq!(args.len(), arg_vals.len()); - - let arg_ids = args.iter().map(|arg| arg.pat.id); - let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect(); - - let substs = ccx.tcx().erase_regions(&substs); - let substs = monomorphize::apply_param_substs(ccx.tcx(), - param_substs, - &substs); - - const_expr(ccx, body, substs, Some(&fn_args), trueconst).map(|(res, _)| res) -} - -pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId, - ref_expr: &hir::Expr, - param_substs: &'tcx Substs<'tcx>) - -> &'tcx hir::Expr { - let substs = ccx.tcx().node_id_item_substs(ref_expr.id).substs; - let substs = ccx.tcx().erase_regions(&substs); - let substs = monomorphize::apply_param_substs(ccx.tcx(), - param_substs, - &substs); - match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) { - Some((ref expr, _ty)) => expr, - None => { - span_bug!(ref_expr.span, "constant item not found") - } - } -} - -pub enum ConstEvalFailure { - /// in case the const evaluator failed on something that panic at runtime - /// as defined in RFC 1229 - Runtime(ConstEvalErr), - // in case we found a true constant - Compiletime(ConstEvalErr), -} - -impl ConstEvalFailure { - fn into_inner(self) -> ConstEvalErr { - match self { - Runtime(e) => e, - Compiletime(e) => e, - } - } - - pub fn as_inner(&self) -> &ConstEvalErr { - match self { - &Runtime(ref e) => e, - &Compiletime(ref e) => e, - } - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum TrueConst { - Yes, No -} - -use self::ConstEvalFailure::*; - -fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId, - ref_expr: &hir::Expr, - param_substs: &'tcx Substs<'tcx>) - -> Result { - let expr = get_const_expr(ccx, def_id, ref_expr, param_substs); - let empty_substs = Substs::empty(ccx.tcx()); - match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) { - Err(Runtime(err)) => { - report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit(); - Err(Compiletime(err)) - }, - other => other, - } -} - -pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - expr: &hir::Expr, - qualif: ConstQualif, - param_substs: &'tcx Substs<'tcx>, - trueconst: TrueConst) - -> Result { - debug!("get_const_expr_as_global: {:?}", expr.id); - // Special-case constants to cache a common global for all uses. - if let hir::ExprPath(..) = expr.node { - // `def` must be its own statement and cannot be in the `match` - // otherwise the `def_map` will be borrowed for the entire match instead - // of just to get the `def` value - match ccx.tcx().expect_def(expr.id) { - Def::Const(def_id) | Def::AssociatedConst(def_id) => { - if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { - debug!("get_const_expr_as_global ({:?}): found const {:?}", - expr.id, def_id); - return get_const_val(ccx, def_id, expr, param_substs); - } - }, - _ => {}, - } - } - - let key = (expr.id, param_substs); - if let Some(&val) = ccx.const_values().borrow().get(&key) { - return Ok(val); - } - let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, - &ccx.tcx().expr_ty(expr)); - let val = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) { - // Avoid autorefs as they would create global instead of stack - // references, even when only the latter are correct. - const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst)? - } else { - const_expr(ccx, expr, param_substs, None, trueconst)?.0 - }; - - // boolean SSA values are i1, but they have to be stored in i8 slots, - // otherwise some LLVM optimization passes don't work as expected - let val = unsafe { - if llvm::LLVMTypeOf(val) == Type::i1(ccx).to_ref() { - llvm::LLVMConstZExt(val, Type::i8(ccx).to_ref()) - } else { - val - } - }; - - let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const"); - ccx.const_values().borrow_mut().insert(key, lvalue); - Ok(lvalue) -} - -pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - e: &hir::Expr, - param_substs: &'tcx Substs<'tcx>, - fn_args: FnArgMap, - trueconst: TrueConst) - -> Result<(ValueRef, Ty<'tcx>), ConstEvalFailure> { - let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs, - &cx.tcx().expr_ty(e)); - let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args, trueconst)?; - let mut llconst = llconst; - let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs, - &cx.tcx().expr_ty_adjusted(e)); - let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); - match opt_adj { - Some(AdjustNeverToAny(..)) => span_bug!(e.span, "const expression of type ! encountered"), - Some(AdjustReifyFnPointer) => { - match ety.sty { - ty::TyFnDef(def_id, substs, _) => { - llconst = Callee::def(cx, def_id, substs).reify(cx).val; - } - _ => { - bug!("{} cannot be reified to a fn ptr", ety) - } - } - } - Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => { - // purely a type-level thing - } - Some(AdjustDerefRef(adj)) => { - let mut ty = ety; - // Save the last autoderef in case we can avoid it. - if adj.autoderefs > 0 { - for _ in 0..adj.autoderefs-1 { - let (dv, dt) = const_deref(cx, llconst, ty); - llconst = dv; - ty = dt; - } - } - - if adj.autoref.is_some() { - if adj.autoderefs == 0 { - // Don't copy data to do a deref+ref - // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref"); - ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReErased), ty); - } - } else if adj.autoderefs > 0 { - let (dv, dt) = const_deref(cx, llconst, ty); - llconst = dv; - - // If we derefed a fat pointer then we will have an - // open type here. So we need to update the type with - // the one returned from const_deref. - ety_adjusted = dt; - } - - if let Some(target) = adj.unsize { - let target = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &target); - - let pointee_ty = ty.builtin_deref(true, ty::NoPreference) - .expect("consts: unsizing got non-pointer type").ty; - let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) { - // Normally, the source is a thin pointer and we are - // adding extra info to make a fat pointer. The exception - // is when we are upcasting an existing object fat pointer - // to use a different vtable. In that case, we want to - // load out the original data pointer so we can repackage - // it. - (const_get_elt(llconst, &[abi::FAT_PTR_ADDR as u32]), - Some(const_get_elt(llconst, &[abi::FAT_PTR_EXTRA as u32]))) - } else { - (llconst, None) - }; - - let unsized_ty = target.builtin_deref(true, ty::NoPreference) - .expect("consts: unsizing got non-pointer target type").ty; - let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); - let base = ptrcast(base, ptr_ty); - let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info); - - if old_info.is_none() { - let prev_const = cx.const_unsized().borrow_mut() - .insert(base, llconst); - assert!(prev_const.is_none() || prev_const == Some(llconst)); - } - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - llconst = C_struct(cx, &[base, info], false); - } - } - None => {} - }; - - let llty = type_of::sizing_type_of(cx, ety_adjusted); - let csize = machine::llsize_of_alloc(cx, val_ty(llconst)); - let tsize = machine::llsize_of_alloc(cx, llty); - if csize != tsize { - cx.sess().abort_if_errors(); - unsafe { - // FIXME these values could use some context - llvm::LLVMDumpValue(llconst); - llvm::LLVMDumpValue(C_undef(llty)); - } - bug!("const {:?} of type {:?} has size {} instead of {}", - e, ety_adjusted, - csize, tsize); - } - Ok((llconst, ety_adjusted)) -} - -fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, - te: ValueRef, trueconst: TrueConst) -> Result<(), ConstEvalFailure> { - // The only kind of unary expression that we check for validity - // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`). - if let hir::ExprUnary(hir::UnNeg, ref inner_e) = e.node { - - // An unfortunate special case: we parse e.g. -128 as a - // negation of the literal 128, which means if we're expecting - // a i8 (or if it was already suffixed, e.g. `-128_i8`), then - // 128 will have already overflowed to -128, and so then the - // constant evaluator thinks we're trying to negate -128. - // - // Catch this up front by looking for ExprLit directly, - // and just accepting it. - if let hir::ExprLit(_) = inner_e.node { return Ok(()); } - let cval = match to_const_int(te, t, cx.tcx()) { - Some(v) => v, - None => return Ok(()), - }; - const_err(cx, e.span, (-cval).map_err(ErrKind::Math), trueconst)?; - } - Ok(()) -} - -pub fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { - match t.sty { - ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type { - ast::IntTy::I8 => { - assert_eq!(input as i8 as i64, input); - Some(ConstInt::I8(input as i8)) - }, - ast::IntTy::I16 => { - assert_eq!(input as i16 as i64, input); - Some(ConstInt::I16(input as i16)) - }, - ast::IntTy::I32 => { - assert_eq!(input as i32 as i64, input); - Some(ConstInt::I32(input as i32)) - }, - ast::IntTy::I64 => { - Some(ConstInt::I64(input)) - }, - ast::IntTy::Is => { - ConstIsize::new(input, tcx.sess.target.int_type) - .ok().map(ConstInt::Isize) - }, - }), - ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type { - ast::UintTy::U8 => { - assert_eq!(input as u8 as u64, input); - Some(ConstInt::U8(input as u8)) - }, - ast::UintTy::U16 => { - assert_eq!(input as u16 as u64, input); - Some(ConstInt::U16(input as u16)) - }, - ast::UintTy::U32 => { - assert_eq!(input as u32 as u64, input); - Some(ConstInt::U32(input as u32)) - }, - ast::UintTy::U64 => { - Some(ConstInt::U64(input)) - }, - ast::UintTy::Us => { - ConstUsize::new(input, tcx.sess.target.uint_type) - .ok().map(ConstInt::Usize) - }, - }), - _ => None, - } -} - -pub fn const_err(cx: &CrateContext, - span: Span, - result: Result, - trueconst: TrueConst) - -> Result { - match (result, trueconst) { - (Ok(x), _) => Ok(x), - (Err(err), TrueConst::Yes) => { - let err = ConstEvalErr{ span: span, kind: err }; - report_const_eval_err(cx.tcx(), &err, span, "expression").emit(); - Err(Compiletime(err)) - }, - (Err(err), TrueConst::No) => { - let err = ConstEvalErr{ span: span, kind: err }; - let mut diag = cx.tcx().sess.struct_span_warn( - span, "this expression will panic at run-time"); - note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag); - diag.emit(); - Err(Runtime(err)) - }, - } -} - -fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, - te1: ValueRef, te2: ValueRef, - trueconst: TrueConst) -> Result<(), ConstEvalFailure> { - let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { bug!() }; - let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) { - (Some(v1), Some(v2)) => (v1, v2), - _ => return Ok(()), - }; - let result = match b.node { - hir::BiAdd => lhs + rhs, - hir::BiSub => lhs - rhs, - hir::BiMul => lhs * rhs, - hir::BiDiv => lhs / rhs, - hir::BiRem => lhs % rhs, - hir::BiShl => lhs << rhs, - hir::BiShr => lhs >> rhs, - _ => return Ok(()), - }; - const_err(cx, e.span, result.map_err(ErrKind::Math), trueconst)?; - Ok(()) -} - -fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - e: &hir::Expr, - ety: Ty<'tcx>, - param_substs: &'tcx Substs<'tcx>, - fn_args: FnArgMap, - trueconst: TrueConst) - -> Result -{ - debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})", - e, - ety, - param_substs); - - let map_list = |exprs: &[P]| -> Result, ConstEvalFailure> { - exprs.iter() - .map(|e| const_expr(cx, &e, param_substs, fn_args, trueconst).map(|(l, _)| l)) - .collect::>>() - .into_iter() - .collect() - // this dance is necessary to eagerly run const_expr so all errors are reported - }; - let _icx = push_ctxt("const_expr"); - Ok(match e.node { - hir::ExprLit(ref lit) => const_lit(cx, e, &lit), - hir::ExprBinary(b, ref e1, ref e2) => { - /* Neither type is bottom, and we expect them to be unified - * already, so the following is safe. */ - let (te1, ty) = const_expr(cx, &e1, param_substs, fn_args, trueconst)?; - debug!("const_expr_unadjusted: te1={:?}, ty={:?}", - Value(te1), ty); - assert!(!ty.is_simd()); - let is_float = ty.is_fp(); - let signed = ty.is_signed(); - - let (te2, ty2) = const_expr(cx, &e2, param_substs, fn_args, trueconst)?; - debug!("const_expr_unadjusted: te2={:?}, ty={:?}", - Value(te2), ty2); - - check_binary_expr_validity(cx, e, ty, te1, te2, trueconst)?; - - unsafe { match b.node { - hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2), - hir::BiAdd => llvm::LLVMConstAdd(te1, te2), - - hir::BiSub if is_float => llvm::LLVMConstFSub(te1, te2), - hir::BiSub => llvm::LLVMConstSub(te1, te2), - - hir::BiMul if is_float => llvm::LLVMConstFMul(te1, te2), - hir::BiMul => llvm::LLVMConstMul(te1, te2), - - hir::BiDiv if is_float => llvm::LLVMConstFDiv(te1, te2), - hir::BiDiv if signed => llvm::LLVMConstSDiv(te1, te2), - hir::BiDiv => llvm::LLVMConstUDiv(te1, te2), - - hir::BiRem if is_float => llvm::LLVMConstFRem(te1, te2), - hir::BiRem if signed => llvm::LLVMConstSRem(te1, te2), - hir::BiRem => llvm::LLVMConstURem(te1, te2), - - hir::BiAnd => llvm::LLVMConstAnd(te1, te2), - hir::BiOr => llvm::LLVMConstOr(te1, te2), - hir::BiBitXor => llvm::LLVMConstXor(te1, te2), - hir::BiBitAnd => llvm::LLVMConstAnd(te1, te2), - hir::BiBitOr => llvm::LLVMConstOr(te1, te2), - hir::BiShl => { - let te2 = base::cast_shift_const_rhs(b.node, te1, te2); - llvm::LLVMConstShl(te1, te2) - }, - hir::BiShr => { - let te2 = base::cast_shift_const_rhs(b.node, te1, te2); - if signed { llvm::LLVMConstAShr(te1, te2) } - else { llvm::LLVMConstLShr(te1, te2) } - }, - hir::BiEq | hir::BiNe | hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => { - if is_float { - let cmp = base::bin_op_to_fcmp_predicate(b.node); - llvm::LLVMConstFCmp(cmp, te1, te2) - } else { - let cmp = base::bin_op_to_icmp_predicate(b.node, signed); - llvm::LLVMConstICmp(cmp, te1, te2) - } - }, - } } // unsafe { match b.node { - }, - hir::ExprUnary(u, ref inner_e) => { - let (te, ty) = const_expr(cx, &inner_e, param_substs, fn_args, trueconst)?; - - check_unary_expr_validity(cx, e, ty, te, trueconst)?; - - let is_float = ty.is_fp(); - unsafe { match u { - hir::UnDeref => const_deref(cx, te, ty).0, - hir::UnNot => llvm::LLVMConstNot(te), - hir::UnNeg if is_float => llvm::LLVMConstFNeg(te), - hir::UnNeg => llvm::LLVMConstNeg(te), - } } - }, - hir::ExprField(ref base, field) => { - let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; - let brepr = adt::represent_type(cx, bt); - let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); - let ix = vinfo.field_index(field.node); - adt::const_get_field(&brepr, bv, vinfo.discr, ix) - }, - hir::ExprTupField(ref base, idx) => { - let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; - let brepr = adt::represent_type(cx, bt); - let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); - adt::const_get_field(&brepr, bv, vinfo.discr, idx.node) - }, - hir::ExprIndex(ref base, ref index) => { - let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; - let iv = const_expr(cx, &index, param_substs, fn_args, TrueConst::Yes)?.0; - let iv = if let Some(iv) = const_to_opt_uint(iv) { - iv - } else { - span_bug!(index.span, "index is not an integer-constant expression"); - }; - let (arr, len) = match bt.sty { - ty::TyArray(_, u) => (bv, C_uint(cx, u)), - ty::TySlice(..) | ty::TyStr => { - let e1 = const_get_elt(bv, &[0]); - (load_const(cx, e1, bt), const_get_elt(bv, &[1])) - }, - ty::TyRef(_, mt) => match mt.ty.sty { - ty::TyArray(_, u) => { - (load_const(cx, bv, mt.ty), C_uint(cx, u)) - }, - _ => span_bug!(base.span, - "index-expr base must be a vector \ - or string type, found {:?}", - bt), - }, - _ => span_bug!(base.span, - "index-expr base must be a vector \ - or string type, found {:?}", - bt), - }; - - let len = unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 }; - let len = match bt.sty { - ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => match ty.sty { - ty::TyStr => { - assert!(len > 0); - len - 1 - }, - _ => len, - }, - _ => len, - }; - if iv >= len { - // FIXME #3170: report this earlier on in the const-eval - // pass. Reporting here is a bit late. - const_err(cx, e.span, Err(ErrKind::IndexOutOfBounds { - len: len, - index: iv - }), trueconst)?; - C_undef(val_ty(arr).element_type()) - } else { - const_get_elt(arr, &[iv as c_uint]) - } - }, - hir::ExprCast(ref base, _) => { - let t_cast = ety; - let llty = type_of::type_of(cx, t_cast); - let (v, t_expr) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; - debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast); - if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) { - return Ok(v); - } - if type_is_fat_ptr(cx.tcx(), t_expr) { - // Fat pointer casts. - let t_cast_inner = - t_cast.builtin_deref(true, ty::NoPreference).expect("cast to non-pointer").ty; - let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to(); - let addr = ptrcast(const_get_elt(v, &[abi::FAT_PTR_ADDR as u32]), - ptr_ty); - if type_is_fat_ptr(cx.tcx(), t_cast) { - let info = const_get_elt(v, &[abi::FAT_PTR_EXTRA as u32]); - return Ok(C_struct(cx, &[addr, info], false)) - } else { - return Ok(addr); - } - } - unsafe { match ( - CastTy::from_ty(t_expr).expect("bad input type for cast"), - CastTy::from_ty(t_cast).expect("bad output type for cast"), - ) { - (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => { - let repr = adt::represent_type(cx, t_expr); - let discr = adt::const_get_discrim(&repr, v); - let iv = C_integral(cx.int_type(), discr.0, false); - let s = adt::is_discr_signed(&repr) as Bool; - llvm::LLVMConstIntCast(iv, llty.to_ref(), s) - }, - (CastTy::Int(_), CastTy::Int(_)) => { - let s = t_expr.is_signed() as Bool; - llvm::LLVMConstIntCast(v, llty.to_ref(), s) - }, - (CastTy::Int(_), CastTy::Float) => { - if t_expr.is_signed() { - llvm::LLVMConstSIToFP(v, llty.to_ref()) - } else { - llvm::LLVMConstUIToFP(v, llty.to_ref()) - } - }, - (CastTy::Float, CastTy::Float) => llvm::LLVMConstFPCast(v, llty.to_ref()), - (CastTy::Float, CastTy::Int(IntTy::I)) => llvm::LLVMConstFPToSI(v, llty.to_ref()), - (CastTy::Float, CastTy::Int(_)) => llvm::LLVMConstFPToUI(v, llty.to_ref()), - (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) - | (CastTy::RPtr(_), CastTy::Ptr(_)) => { - ptrcast(v, llty) - }, - (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion? - (CastTy::Int(_), CastTy::Ptr(_)) => llvm::LLVMConstIntToPtr(v, llty.to_ref()), - (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => { - llvm::LLVMConstPtrToInt(v, llty.to_ref()) - }, - _ => { - span_bug!(e.span, "bad combination of types for cast") - }, - } } // unsafe { match ( ... ) { - }, - hir::ExprAddrOf(hir::MutImmutable, ref sub) => { - // If this is the address of some static, then we need to return - // the actual address of the static itself (short circuit the rest - // of const eval). - let mut cur = sub; - loop { - match cur.node { - hir::ExprBlock(ref blk) => { - if let Some(ref sub) = blk.expr { - cur = sub; - } else { - break; - } - }, - _ => break, - } - } - if let Some(Def::Static(def_id, _)) = cx.tcx().expect_def_or_none(cur.id) { - get_static(cx, def_id).val - } else { - // If this isn't the address of a static, then keep going through - // normal constant evaluation. - let (v, ty) = const_expr(cx, &sub, param_substs, fn_args, trueconst)?; - addr_of(cx, v, type_of::align_of(cx, ty), "ref") - } - }, - hir::ExprAddrOf(hir::MutMutable, ref sub) => { - let (v, ty) = const_expr(cx, &sub, param_substs, fn_args, trueconst)?; - addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice") - }, - hir::ExprTup(ref es) => { - let repr = adt::represent_type(cx, ety); - let vals = map_list(&es[..])?; - adt::trans_const(cx, &repr, Disr(0), &vals[..]) - }, - hir::ExprStruct(_, ref fs, ref base_opt) => { - let repr = adt::represent_type(cx, ety); - - let base_val = match *base_opt { - Some(ref base) => Some(const_expr( - cx, - &base, - param_substs, - fn_args, - trueconst, - )?), - None => None - }; - - let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id); - let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| { - match (fs.iter().find(|f| f_name == f.name.node), base_val) { - (Some(ref f), _) => { - const_expr(cx, &f.expr, param_substs, fn_args, trueconst).map(|(l, _)| l) - }, - (_, Some((bv, _))) => Ok(adt::const_get_field(&repr, bv, discr, ix)), - (_, None) => span_bug!(e.span, "missing struct field"), - } - }) - .collect::>>() - .into_iter() - .collect::,ConstEvalFailure>>(); - let cs = cs?; - if ety.is_simd() { - C_vector(&cs[..]) - } else { - adt::trans_const(cx, &repr, discr, &cs[..]) - } - }, - hir::ExprVec(ref es) => { - let unit_ty = ety.sequence_element_type(cx.tcx()); - let llunitty = type_of::type_of(cx, unit_ty); - let vs = es.iter() - .map(|e| const_expr( - cx, - &e, - param_substs, - fn_args, - trueconst, - ).map(|(l, _)| l)) - .collect::>>() - .into_iter() - .collect::, ConstEvalFailure>>(); - let vs = vs?; - // If the vector contains enums, an LLVM array won't work. - if vs.iter().any(|vi| val_ty(*vi) != llunitty) { - C_struct(cx, &vs[..], false) - } else { - C_array(llunitty, &vs[..]) - } - }, - hir::ExprRepeat(ref elem, ref count) => { - let unit_ty = ety.sequence_element_type(cx.tcx()); - let llunitty = type_of::type_of(cx, unit_ty); - let n = eval_length(cx.tcx(), count, "repeat count").unwrap(); - let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0; - let vs = vec![unit_val; n]; - if val_ty(unit_val) != llunitty { - C_struct(cx, &vs[..], false) - } else { - C_array(llunitty, &vs[..]) - } - }, - hir::ExprPath(..) => { - match cx.tcx().expect_def(e.id) { - Def::Local(_, id) => { - if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) { - val - } else { - span_bug!(e.span, "const fn argument not found") - } - } - Def::Fn(..) | Def::Method(..) => C_nil(cx), - Def::Const(def_id) | Def::AssociatedConst(def_id) => { - load_const(cx, get_const_val(cx, def_id, e, param_substs)?, - ety) - } - Def::Variant(enum_did, variant_did) => { - let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); - match vinfo.kind { - ty::VariantKind::Unit => { - let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[]) - } - ty::VariantKind::Tuple => C_nil(cx), - ty::VariantKind::Struct => { - span_bug!(e.span, "path-expr refers to a dict variant!") - } - } - } - // Unit struct or ctor. - Def::Struct(..) => C_null(type_of::type_of(cx, ety)), - _ => { - span_bug!(e.span, "expected a const, fn, struct, \ - or variant def") - } - } - }, - hir::ExprCall(ref callee, ref args) => { - let mut callee = &**callee; - loop { - callee = match callee.node { - hir::ExprBlock(ref block) => match block.expr { - Some(ref tail) => &tail, - None => break, - }, - _ => break, - }; - } - let arg_vals = map_list(args)?; - match cx.tcx().expect_def(callee.id) { - Def::Fn(did) | Def::Method(did) => { - const_fn_call( - cx, - did, - cx.tcx().node_id_item_substs(callee.id).substs, - &arg_vals, - param_substs, - trueconst, - )? - } - Def::Struct(..) => { - if ety.is_simd() { - C_vector(&arg_vals[..]) - } else { - let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &repr, Disr(0), &arg_vals[..]) - } - } - Def::Variant(enum_did, variant_did) => { - let repr = adt::represent_type(cx, ety); - let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); - adt::trans_const(cx, - &repr, - Disr::from(vinfo.disr_val), - &arg_vals[..]) - } - _ => span_bug!(e.span, "expected a struct, variant, or const fn def"), - } - }, - hir::ExprMethodCall(_, _, ref args) => { - let arg_vals = map_list(args)?; - let method_call = ty::MethodCall::expr(e.id); - let method = cx.tcx().tables.borrow().method_map[&method_call]; - const_fn_call(cx, method.def_id, method.substs, - &arg_vals, param_substs, trueconst)? - }, - hir::ExprType(ref e, _) => const_expr(cx, &e, param_substs, fn_args, trueconst)?.0, - hir::ExprBlock(ref block) => { - match block.expr { - Some(ref expr) => const_expr( - cx, - &expr, - param_substs, - fn_args, - trueconst, - )?.0, - None => C_nil(cx), - } - }, - hir::ExprClosure(_, ref decl, ref body, _) => { - match ety.sty { - ty::TyClosure(def_id, substs) => { - closure::trans_closure_expr(closure::Dest::Ignore(cx), - decl, - body, - e.id, - def_id, - substs); - } - _ => - span_bug!( - e.span, - "bad type for closure expr: {:?}", ety) - } - C_null(type_of::type_of(cx, ety)) - }, - _ => span_bug!(e.span, - "bad constant expression type in consts::const_expr"), - }) -} - -pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) - -> Datum<'tcx, Lvalue> { - let ty = ccx.tcx().lookup_item_type(def_id).ty; - +pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { let instance = Instance::mono(ccx.shared(), def_id); if let Some(&g) = ccx.instances().borrow().get(&instance) { - return Datum::new(g, ty, Lvalue::new("static")); + return g; } + let ty = ccx.tcx().lookup_item_type(def_id).ty; let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); @@ -1136,29 +209,20 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) ccx.instances().borrow_mut().insert(instance, g); ccx.statics().borrow_mut().insert(g, def_id); - Datum::new(g, ty, Lvalue::new("static")) + g } pub fn trans_static(ccx: &CrateContext, m: hir::Mutability, - expr: &hir::Expr, id: ast::NodeId, attrs: &[ast::Attribute]) -> Result { unsafe { let _icx = push_ctxt("trans_static"); let def_id = ccx.tcx().map.local_def_id(id); - let datum = get_static(ccx, def_id); + let g = get_static(ccx, def_id); - let use_mir = true; - - let v = if use_mir { - ::mir::trans_static_initializer(ccx, def_id) - } else { - let empty_substs = Substs::empty(ccx.tcx()); - const_expr(ccx, expr, empty_substs, None, TrueConst::Yes) - .map(|(v, _)| v) - }.map_err(|e| e.into_inner())?; + let v = ::mir::trans_static_initializer(ccx, def_id)?; // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected @@ -1170,31 +234,32 @@ pub fn trans_static(ccx: &CrateContext, v }; - let llty = type_of::type_of(ccx, datum.ty); + let ty = ccx.tcx().lookup_item_type(def_id).ty; + let llty = type_of::type_of(ccx, ty); let g = if val_llty == llty { - datum.val + g } else { // If we created the global with the wrong type, // correct the type. let empty_string = CString::new("").unwrap(); - let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(datum.val)); + let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g)); let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); - llvm::LLVMSetValueName(datum.val, empty_string.as_ptr()); + llvm::LLVMSetValueName(g, empty_string.as_ptr()); let new_g = llvm::LLVMRustGetOrInsertGlobal( ccx.llmod(), name_string.as_ptr(), val_llty.to_ref()); // To avoid breaking any invariants, we leave around the old // global for the moment; we'll replace all references to it // with the new global later. (See base::trans_crate.) - ccx.statics_to_rauw().borrow_mut().push((datum.val, new_g)); + ccx.statics_to_rauw().borrow_mut().push((g, new_g)); new_g }; - llvm::LLVMSetAlignment(g, type_of::align_of(ccx, datum.ty)); + llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty)); llvm::LLVMSetInitializer(g, v); // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. if m != hir::MutMutable { - let tcontents = datum.ty.type_contents(ccx.tcx()); + let tcontents = ty.type_contents(ccx.tcx()); if !tcontents.interior_unsafe() { llvm::LLVMSetGlobalConstant(g, llvm::True); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c31dbf8943e08..8a836c692e1a8 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -79,7 +79,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, stats: Stats, check_overflow: bool, - check_drop_flag_for_sanity: bool, mir_map: &'a MirMap<'tcx>, mir_cache: RefCell>>, @@ -424,8 +423,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { symbol_hasher: Sha256, link_meta: LinkMeta, reachable: NodeSet, - check_overflow: bool, - check_drop_flag_for_sanity: bool) + check_overflow: bool) -> SharedCrateContext<'b, 'tcx> { let (metadata_llcx, metadata_llmod) = unsafe { create_context_and_module(&tcx.sess, "metadata") @@ -500,7 +498,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { fn_stats: RefCell::new(Vec::new()), }, check_overflow: check_overflow, - check_drop_flag_for_sanity: check_drop_flag_for_sanity, use_dll_storage_attrs: use_dll_storage_attrs, translation_items: RefCell::new(FnvHashSet()), trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), @@ -964,13 +961,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared.check_overflow } - pub fn check_drop_flag_for_sanity(&self) -> bool { - // This controls whether we emit a conditional llvm.debugtrap - // guarded on whether the dropflag is one of its (two) valid - // values. - self.shared.check_drop_flag_for_sanity - } - pub fn use_dll_storage_attrs(&self) -> bool { self.shared.use_dll_storage_attrs() } diff --git a/src/librustc_trans/controlflow.rs b/src/librustc_trans/controlflow.rs deleted file mode 100644 index 8b3a8a2bfccfb..0000000000000 --- a/src/librustc_trans/controlflow.rs +++ /dev/null @@ -1,434 +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. - -use llvm::ValueRef; -use rustc::hir::def::Def; -use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem}; -use rustc::ty::subst::Substs; -use base::*; -use basic_block::BasicBlock; -use build::*; -use callee::{Callee, ArgVals}; -use cleanup::CleanupMethods; -use cleanup; -use common::*; -use consts; -use debuginfo; -use debuginfo::{DebugLoc, ToDebugLoc}; -use expr; -use machine; - -use rustc::hir; - -use syntax::ast; -use syntax::parse::token::InternedString; -use syntax::parse::token; - -pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, - s: &hir::Stmt) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_stmt"); - let fcx = cx.fcx; - debug!("trans_stmt({:?})", s); - - if cx.unreachable.get() { - return cx; - } - - if cx.sess().asm_comments() { - add_span_comment(cx, s.span, &format!("{:?}", s)); - } - - let mut bcx = cx; - - let id = s.node.id(); - let cleanup_debug_loc = - debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), id, s.span, false); - fcx.push_ast_cleanup_scope(cleanup_debug_loc); - - match s.node { - hir::StmtExpr(ref e, _) | hir::StmtSemi(ref e, _) => { - bcx = trans_stmt_semi(bcx, &e); - } - hir::StmtDecl(ref d, _) => { - match d.node { - hir::DeclLocal(ref local) => { - bcx = init_local(bcx, &local); - debuginfo::create_local_var_metadata(bcx, &local); - } - // Inner items are visited by `trans_item`/`trans_meth`. - hir::DeclItem(_) => {}, - } - } - } - - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, s.node.id()); - - return bcx; -} - -pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &hir::Expr) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_stmt_semi"); - - if cx.unreachable.get() { - return cx; - } - - let ty = expr_ty(cx, e); - if cx.fcx.type_needs_drop(ty) { - expr::trans_to_lvalue(cx, e, "stmt").bcx - } else { - expr::trans_into(cx, e, expr::Ignore) - } -} - -pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - b: &hir::Block, - mut dest: expr::Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_block"); - - if bcx.unreachable.get() { - return bcx; - } - - let fcx = bcx.fcx; - let mut bcx = bcx; - - let cleanup_debug_loc = - debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), b.id, b.span, true); - fcx.push_ast_cleanup_scope(cleanup_debug_loc); - - for s in &b.stmts { - bcx = trans_stmt(bcx, s); - } - - if dest != expr::Ignore { - let block_ty = node_id_type(bcx, b.id); - - if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) { - dest = expr::Ignore; - } else if b.expr.is_some() { - // If the block has an expression, but that expression isn't reachable, - // don't save into the destination given, ignore it. - if let Some(ref cfg) = bcx.fcx.cfg { - if !cfg.node_is_reachable(b.expr.as_ref().unwrap().id) { - dest = expr::Ignore; - } - } - } - } - - match b.expr { - Some(ref e) => { - if !bcx.unreachable.get() { - bcx = expr::trans_into(bcx, &e, dest); - } - } - None => { - assert!(dest == expr::Ignore || bcx.unreachable.get()); - } - } - - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, b.id); - - return bcx; -} - -pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - if_id: ast::NodeId, - cond: &hir::Expr, - thn: &hir::Block, - els: Option<&hir::Expr>, - dest: expr::Dest) - -> Block<'blk, 'tcx> { - debug!("trans_if(bcx={}, if_id={}, cond={:?}, thn={}, dest={:?})", - bcx.to_str(), if_id, cond, thn.id, dest); - let _icx = push_ctxt("trans_if"); - - if bcx.unreachable.get() { - return bcx; - } - - let mut bcx = bcx; - - let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool()); - - // Drop branches that are known to be impossible - if let Some(cv) = const_to_opt_uint(cond_val) { - if cv == 1 { - // if true { .. } [else { .. }] - bcx = trans_block(bcx, &thn, dest); - DebugLoc::None.apply(bcx.fcx); - } else { - if let Some(elexpr) = els { - bcx = expr::trans_into(bcx, &elexpr, dest); - DebugLoc::None.apply(bcx.fcx); - } - } - - return bcx; - } - - let name = format!("then-block-{}-", thn.id); - let then_bcx_in = bcx.fcx.new_id_block(&name[..], thn.id); - let then_bcx_out = trans_block(then_bcx_in, &thn, dest); - DebugLoc::None.apply(bcx.fcx); - - let cond_source_loc = cond.debug_loc(); - - let next_bcx; - match els { - Some(elexpr) => { - let else_bcx_in = bcx.fcx.new_id_block("else-block", elexpr.id); - let else_bcx_out = expr::trans_into(else_bcx_in, &elexpr, dest); - next_bcx = bcx.fcx.join_blocks(if_id, - &[then_bcx_out, else_bcx_out]); - CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb, cond_source_loc); - } - - None => { - next_bcx = bcx.fcx.new_id_block("next-block", if_id); - Br(then_bcx_out, next_bcx.llbb, DebugLoc::None); - CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb, cond_source_loc); - } - } - - // Clear the source location because it is still set to whatever has been translated - // right before. - DebugLoc::None.apply(next_bcx.fcx); - - next_bcx -} - -pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - loop_expr: &hir::Expr, - cond: &hir::Expr, - body: &hir::Block) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_while"); - - if bcx.unreachable.get() { - return bcx; - } - - let fcx = bcx.fcx; - - // bcx - // | - // cond_bcx_in <--------+ - // | | - // cond_bcx_out | - // | | | - // | body_bcx_in | - // cleanup_blk | | - // | body_bcx_out --+ - // next_bcx_in - - let next_bcx_in = fcx.new_id_block("while_exit", loop_expr.id); - let cond_bcx_in = fcx.new_id_block("while_cond", cond.id); - let body_bcx_in = fcx.new_id_block("while_body", body.id); - - fcx.push_loop_cleanup_scope(loop_expr.id, [next_bcx_in, cond_bcx_in]); - - Br(bcx, cond_bcx_in.llbb, loop_expr.debug_loc()); - - // compile the block where we will handle loop cleanups - let cleanup_llbb = fcx.normal_exit_block(loop_expr.id, cleanup::EXIT_BREAK); - - // compile the condition - let Result {bcx: cond_bcx_out, val: cond_val} = - expr::trans(cond_bcx_in, cond).to_llbool(); - - CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb, cond.debug_loc()); - - // loop body: - let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore); - Br(body_bcx_out, cond_bcx_in.llbb, DebugLoc::None); - - fcx.pop_loop_cleanup_scope(loop_expr.id); - return next_bcx_in; -} - -pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - loop_expr: &hir::Expr, - body: &hir::Block) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_loop"); - - if bcx.unreachable.get() { - return bcx; - } - - let fcx = bcx.fcx; - - // bcx - // | - // body_bcx_in - // | - // body_bcx_out - // - // next_bcx - // - // Links between body_bcx_in and next_bcx are created by - // break statements. - - let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_expr.id); - let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id); - - fcx.push_loop_cleanup_scope(loop_expr.id, [next_bcx_in, body_bcx_in]); - - Br(bcx, body_bcx_in.llbb, loop_expr.debug_loc()); - let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore); - Br(body_bcx_out, body_bcx_in.llbb, DebugLoc::None); - - fcx.pop_loop_cleanup_scope(loop_expr.id); - - // If there are no predecessors for the next block, we just translated an endless loop and the - // next block is unreachable - if BasicBlock(next_bcx_in.llbb).pred_iter().next().is_none() { - Unreachable(next_bcx_in); - } - - return next_bcx_in; -} - -pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - opt_label: Option, - exit: usize) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_break_cont"); - - if bcx.unreachable.get() { - return bcx; - } - - let fcx = bcx.fcx; - - // Locate loop that we will break to - let loop_id = match opt_label { - None => fcx.top_loop_scope(), - Some(_) => { - match bcx.tcx().expect_def(expr.id) { - Def::Label(loop_id) => loop_id, - r => { - bug!("{:?} in def-map for label", r) - } - } - } - }; - - // Generate appropriate cleanup code and branch - let cleanup_llbb = fcx.normal_exit_block(loop_id, exit); - Br(bcx, cleanup_llbb, expr.debug_loc()); - Unreachable(bcx); // anything afterwards should be ignored - return bcx; -} - -pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - label_opt: Option) - -> Block<'blk, 'tcx> { - return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_BREAK); -} - -pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - label_opt: Option) - -> Block<'blk, 'tcx> { - return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_LOOP); -} - -pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - return_expr: &hir::Expr, - retval_expr: Option<&hir::Expr>) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_ret"); - - if bcx.unreachable.get() { - return bcx; - } - - let fcx = bcx.fcx; - let mut bcx = bcx; - if let Some(x) = retval_expr { - let dest = if fcx.llretslotptr.get().is_some() { - expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot")) - } else { - expr::Ignore - }; - bcx = expr::trans_into(bcx, &x, dest); - match dest { - expr::SaveIn(slot) if fcx.needs_ret_allocas => { - Store(bcx, slot, fcx.llretslotptr.get().unwrap()); - } - _ => {} - } - } - let cleanup_llbb = fcx.return_exit_block(); - Br(bcx, cleanup_llbb, return_expr.debug_loc()); - Unreachable(bcx); - return bcx; -} - -pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - call_info: NodeIdAndSpan, - fail_str: InternedString) - -> Block<'blk, 'tcx> { - let ccx = bcx.ccx(); - let _icx = push_ctxt("trans_fail_value"); - - if bcx.unreachable.get() { - return bcx; - } - - let v_str = C_str_slice(ccx, fail_str); - let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo); - let filename = token::intern_and_get_ident(&loc.file.name); - let filename = C_str_slice(ccx, filename); - let line = C_u32(ccx, loc.line as u32); - let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false); - let align = machine::llalign_of_min(ccx, val_ty(expr_file_line_const)); - let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc"); - let args = vec!(expr_file_line); - let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicFnLangItem); - Callee::def(ccx, did, Substs::empty(ccx.tcx())) - .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx -} - -pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - call_info: NodeIdAndSpan, - index: ValueRef, - len: ValueRef) - -> Block<'blk, 'tcx> { - let ccx = bcx.ccx(); - let _icx = push_ctxt("trans_fail_bounds_check"); - - if bcx.unreachable.get() { - return bcx; - } - - // Extract the file/line from the span - let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo); - let filename = token::intern_and_get_ident(&loc.file.name); - - // Invoke the lang item - let filename = C_str_slice(ccx, filename); - let line = C_u32(ccx, loc.line as u32); - let file_line_const = C_struct(ccx, &[filename, line], false); - let align = machine::llalign_of_min(ccx, val_ty(file_line_const)); - let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc"); - let args = vec!(file_line, index, len); - let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicBoundsCheckFnLangItem); - Callee::def(ccx, did, Substs::empty(ccx.tcx())) - .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx -} diff --git a/src/librustc_trans/datum.rs b/src/librustc_trans/datum.rs deleted file mode 100644 index 875f88e37c916..0000000000000 --- a/src/librustc_trans/datum.rs +++ /dev/null @@ -1,828 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! ## The Datum module -//! -//! A `Datum` encapsulates the result of evaluating a Rust expression. It -//! contains a `ValueRef` indicating the result, a `Ty` describing -//! the Rust type, but also a *kind*. The kind indicates whether the datum -//! has cleanup scheduled (lvalue) or not (rvalue) and -- in the case of -//! rvalues -- whether or not the value is "by ref" or "by value". -//! -//! The datum API is designed to try and help you avoid memory errors like -//! forgetting to arrange cleanup or duplicating a value. The type of the -//! datum incorporates the kind, and thus reflects whether it has cleanup -//! scheduled: -//! -//! - `Datum` -- by ref, cleanup scheduled -//! - `Datum` -- by value or by ref, no cleanup scheduled -//! - `Datum` -- either `Datum` or `Datum` -//! -//! Rvalue and expr datums are noncopyable, and most of the methods on -//! datums consume the datum itself (with some notable exceptions). This -//! reflects the fact that datums may represent affine values which ought -//! to be consumed exactly once, and if you were to try to (for example) -//! store an affine value multiple times, you would be duplicating it, -//! which would certainly be a bug. -//! -//! Some of the datum methods, however, are designed to work only on -//! copyable values such as ints or pointers. Those methods may borrow the -//! datum (`&self`) rather than consume it, but they always include -//! assertions on the type of the value represented to check that this -//! makes sense. An example is `shallow_copy()`, which duplicates -//! a datum value. -//! -//! Translating an expression always yields a `Datum` result, but -//! the methods `to_[lr]value_datum()` can be used to coerce a -//! `Datum` into a `Datum` or `Datum` as -//! needed. Coercing to an lvalue is fairly common, and generally occurs -//! whenever it is necessary to inspect a value and pull out its -//! subcomponents (for example, a match, or indexing expression). Coercing -//! to an rvalue is more unusual; it occurs when moving values from place -//! to place, such as in an assignment expression or parameter passing. -//! -//! ### Lvalues in detail -//! -//! An lvalue datum is one for which cleanup has been scheduled. Lvalue -//! datums are always located in memory, and thus the `ValueRef` for an -//! LLVM value is always a pointer to the actual Rust value. This means -//! that if the Datum has a Rust type of `int`, then the LLVM type of the -//! `ValueRef` will be `int*` (pointer to int). -//! -//! Because lvalues already have cleanups scheduled, the memory must be -//! zeroed to prevent the cleanup from taking place (presuming that the -//! Rust type needs drop in the first place, otherwise it doesn't -//! matter). The Datum code automatically performs this zeroing when the -//! value is stored to a new location, for example. -//! -//! Lvalues usually result from evaluating lvalue expressions. For -//! example, evaluating a local variable `x` yields an lvalue, as does a -//! reference to a field like `x.f` or an index `x[i]`. -//! -//! Lvalue datums can also arise by *converting* an rvalue into an lvalue. -//! This is done with the `to_lvalue_datum` method defined on -//! `Datum`. Basically this method just schedules cleanup if the -//! datum is an rvalue, possibly storing the value into a stack slot first -//! if needed. Converting rvalues into lvalues occurs in constructs like -//! `&foo()` or `match foo() { ref x => ... }`, where the user is -//! implicitly requesting a temporary. -//! -//! ### Rvalues in detail -//! -//! Rvalues datums are values with no cleanup scheduled. One must be -//! careful with rvalue datums to ensure that cleanup is properly -//! arranged, usually by converting to an lvalue datum or by invoking the -//! `add_clean` method. -//! -//! ### Scratch datums -//! -//! Sometimes you need some temporary scratch space. The functions -//! `[lr]value_scratch_datum()` can be used to get temporary stack -//! space. As their name suggests, they yield lvalues and rvalues -//! respectively. That is, the slot from `lvalue_scratch_datum` will have -//! cleanup arranged, and the slot from `rvalue_scratch_datum` does not. - -pub use self::Expr::*; -pub use self::RvalueMode::*; - -use llvm::ValueRef; -use adt; -use base::*; -use build::{Load, Store}; -use common::*; -use cleanup; -use cleanup::{CleanupMethods, DropHintDatum, DropHintMethods}; -use expr; -use tvec; -use value::Value; -use rustc::ty::Ty; - -use std::fmt; -use syntax::ast; -use syntax_pos::DUMMY_SP; - -/// A `Datum` encapsulates the result of evaluating an expression. It -/// describes where the value is stored, what Rust type the value has, -/// whether it is addressed by reference, and so forth. Please refer -/// the section on datums in `README.md` for more details. -#[derive(Clone, Copy)] -pub struct Datum<'tcx, K> { - /// The llvm value. This is either a pointer to the Rust value or - /// the value itself, depending on `kind` below. - pub val: ValueRef, - - /// The rust type of the value. - pub ty: Ty<'tcx>, - - /// Indicates whether this is by-ref or by-value. - pub kind: K, -} - -impl<'tcx, K: fmt::Debug> fmt::Debug for Datum<'tcx, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Datum({:?}, {:?}, {:?})", - Value(self.val), self.ty, self.kind) - } -} - -pub struct DatumBlock<'blk, 'tcx: 'blk, K> { - pub bcx: Block<'blk, 'tcx>, - pub datum: Datum<'tcx, K>, -} - -#[derive(Debug)] -pub enum Expr { - /// a fresh value that was produced and which has no cleanup yet - /// because it has not yet "landed" into its permanent home - RvalueExpr(Rvalue), - - /// `val` is a pointer into memory for which a cleanup is scheduled - /// (and thus has type *T). If you move out of an Lvalue, you must - /// zero out the memory (FIXME #5016). - LvalueExpr(Lvalue), -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum DropFlagInfo { - DontZeroJustUse(ast::NodeId), - ZeroAndMaintain(ast::NodeId), - None, -} - -impl DropFlagInfo { - pub fn must_zero(&self) -> bool { - match *self { - DropFlagInfo::DontZeroJustUse(..) => false, - DropFlagInfo::ZeroAndMaintain(..) => true, - DropFlagInfo::None => true, - } - } - - pub fn hint_datum<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) - -> Option> { - let id = match *self { - DropFlagInfo::None => return None, - DropFlagInfo::DontZeroJustUse(id) | - DropFlagInfo::ZeroAndMaintain(id) => id, - }; - - let hints = bcx.fcx.lldropflag_hints.borrow(); - let retval = hints.hint_datum(id); - assert!(retval.is_some(), "An id (={}) means must have a hint", id); - retval - } -} - -// FIXME: having Lvalue be `Copy` is a bit of a footgun, since clients -// may not realize that subparts of an Lvalue can have a subset of -// drop-flags associated with them, while this as written will just -// memcpy the drop_flag_info. But, it is an easier way to get `_match` -// off the ground to just let this be `Copy` for now. -#[derive(Copy, Clone, Debug)] -pub struct Lvalue { - pub source: &'static str, - pub drop_flag_info: DropFlagInfo -} - -#[derive(Debug)] -pub struct Rvalue { - pub mode: RvalueMode -} - -/// Classifies what action we should take when a value is moved away -/// with respect to its drop-flag. -/// -/// Long term there will be no need for this classification: all flags -/// (which will be stored on the stack frame) will have the same -/// interpretation and maintenance code associated with them. -#[derive(Copy, Clone, Debug)] -pub enum HintKind { - /// When the value is moved, set the drop-flag to "dropped" - /// (i.e. "zero the flag", even when the specific representation - /// is not literally 0) and when it is reinitialized, set the - /// drop-flag back to "initialized". - ZeroAndMaintain, - - /// When the value is moved, do not set the drop-flag to "dropped" - /// However, continue to read the drop-flag in deciding whether to - /// drop. (In essence, the path/fragment in question will never - /// need to be dropped at the points where it is moved away by - /// this code, but we are defending against the scenario where - /// some *other* code could move away (or drop) the value and thus - /// zero-the-flag, which is why we will still read from it. - DontZeroJustUse, -} - -impl Lvalue { // Constructors for various Lvalues. - pub fn new<'blk, 'tcx>(source: &'static str) -> Lvalue { - debug!("Lvalue at {} no drop flag info", source); - Lvalue { source: source, drop_flag_info: DropFlagInfo::None } - } - - pub fn new_dropflag_hint(source: &'static str) -> Lvalue { - debug!("Lvalue at {} is drop flag hint", source); - Lvalue { source: source, drop_flag_info: DropFlagInfo::None } - } - - pub fn new_with_hint<'blk, 'tcx>(source: &'static str, - bcx: Block<'blk, 'tcx>, - id: ast::NodeId, - k: HintKind) -> Lvalue { - let (opt_id, info) = { - let hint_available = Lvalue::has_dropflag_hint(bcx, id) && - bcx.tcx().sess.nonzeroing_move_hints(); - let info = match k { - HintKind::ZeroAndMaintain if hint_available => - DropFlagInfo::ZeroAndMaintain(id), - HintKind::DontZeroJustUse if hint_available => - DropFlagInfo::DontZeroJustUse(id), - _ => - DropFlagInfo::None, - }; - (Some(id), info) - }; - debug!("Lvalue at {}, id: {:?} info: {:?}", source, opt_id, info); - Lvalue { source: source, drop_flag_info: info } - } -} // end Lvalue constructor methods. - -impl Lvalue { - fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - id: ast::NodeId) -> bool { - let hints = bcx.fcx.lldropflag_hints.borrow(); - hints.has_hint(id) - } - pub fn dropflag_hint<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) - -> Option> { - self.drop_flag_info.hint_datum(bcx) - } -} - -impl Rvalue { - pub fn new(m: RvalueMode) -> Rvalue { - Rvalue { mode: m } - } -} - -// Make Datum linear for more type safety. -impl Drop for Rvalue { - fn drop(&mut self) { } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum RvalueMode { - /// `val` is a pointer to the actual value (and thus has type *T) - ByRef, - - /// `val` is the actual value (*only used for immediates* like ints, ptrs) - ByValue, -} - -pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> { - return Datum::new(val, ty, Rvalue::new(ByValue)); -} - -pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - val: ValueRef, - ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Rvalue> { - return DatumBlock::new(bcx, immediate_rvalue(val, ty)) -} - -/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to -/// it. The memory will be dropped upon exit from `scope`. The callback `populate` should -/// initialize the memory. -/// -/// The flag `zero` indicates how the temporary space itself should be -/// initialized at the outset of the function; the only time that -/// `InitAlloca::Uninit` is a valid value for `zero` is when the -/// caller can prove that either (1.) the code injected by `populate` -/// onto `bcx` always dominates the end of `scope`, or (2.) the data -/// being allocated has no associated destructor. -pub fn lvalue_scratch_datum<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - ty: Ty<'tcx>, - name: &str, - zero: InitAlloca, - scope: cleanup::ScopeId, - populate: F) - -> DatumBlock<'blk, 'tcx, Lvalue> where - F: FnOnce(Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>, -{ - // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed. - // (See discussion at Issue 30530.) - let scratch = alloc_ty_init(bcx, ty, zero, name); - debug!("lvalue_scratch_datum scope={:?} scratch={:?} ty={:?}", - scope, Value(scratch), ty); - - // Subtle. Populate the scratch memory *before* scheduling cleanup. - let bcx = populate(bcx, scratch); - bcx.fcx.schedule_drop_mem(scope, scratch, ty, None); - - DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum"))) -} - -/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to -/// it. If `zero` is true, the space will be zeroed when it is allocated; this is normally not -/// necessary, but in the case of automatic rooting in match statements it is possible to have -/// temporaries that may not get initialized if a certain arm is not taken, so we must zero them. -/// You must arrange any cleanups etc yourself! -pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - ty: Ty<'tcx>, - name: &str) - -> Datum<'tcx, Rvalue> { - let scratch = alloc_ty(bcx, ty, name); - call_lifetime_start(bcx, scratch); - Datum::new(scratch, ty, Rvalue::new(ByRef)) -} - -/// Indicates the "appropriate" mode for this value, which is either by ref or by value, depending -/// on whether type is immediate or not. -pub fn appropriate_rvalue_mode<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - ty: Ty<'tcx>) -> RvalueMode { - if type_is_immediate(ccx, ty) { - ByValue - } else { - ByRef - } -} - -fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode, - fcx: &FunctionContext<'a, 'tcx>, - scope: cleanup::ScopeId, - val: ValueRef, - ty: Ty<'tcx>) { - debug!("add_rvalue_clean scope={:?} val={:?} ty={:?}", - scope, Value(val), ty); - match mode { - ByValue => { fcx.schedule_drop_immediate(scope, val, ty); } - ByRef => { - fcx.schedule_lifetime_end(scope, val); - fcx.schedule_drop_mem(scope, val, ty, None); - } - } -} - -pub trait KindOps { - - /// Take appropriate action after the value in `datum` has been - /// stored to a new location. - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, - val: ValueRef, - ty: Ty<'tcx>) - -> Block<'blk, 'tcx>; - - /// True if this mode is a reference mode, meaning that the datum's - /// val field is a pointer to the actual value - fn is_by_ref(&self) -> bool; - - /// Converts to an Expr kind - fn to_expr_kind(self) -> Expr; - -} - -impl KindOps for Rvalue { - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, - _val: ValueRef, - _ty: Ty<'tcx>) - -> Block<'blk, 'tcx> { - // No cleanup is scheduled for an rvalue, so we don't have - // to do anything after a move to cancel or duplicate it. - if self.is_by_ref() { - call_lifetime_end(bcx, _val); - } - bcx - } - - fn is_by_ref(&self) -> bool { - self.mode == ByRef - } - - fn to_expr_kind(self) -> Expr { - RvalueExpr(self) - } -} - -impl KindOps for Lvalue { - /// If an lvalue is moved, we must zero out the memory in which it resides so as to cancel - /// cleanup. If an @T lvalue is copied, we must increment the reference count. - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, - val: ValueRef, - ty: Ty<'tcx>) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("::post_store"); - if bcx.fcx.type_needs_drop(ty) { - // cancel cleanup of affine values: - // 1. if it has drop-hint, mark as moved; then code - // aware of drop-hint won't bother calling the - // drop-glue itself. - if let Some(hint_datum) = self.drop_flag_info.hint_datum(bcx) { - let moved_hint_byte = adt::DTOR_MOVED_HINT; - let hint_llval = hint_datum.to_value().value(); - Store(bcx, C_u8(bcx.fcx.ccx, moved_hint_byte), hint_llval); - } - // 2. if the drop info says its necessary, drop-fill the memory. - if self.drop_flag_info.must_zero() { - let () = drop_done_fill_mem(bcx, val, ty); - } - bcx - } else { - // FIXME (#5016) would be nice to assert this, but we have - // to allow for e.g. DontZeroJustUse flags, for now. - // - // (The dropflag hint construction should be taking - // !type_needs_drop into account; earlier analysis phases - // may not have all the info they need to include such - // information properly, I think; in particular the - // fragments analysis works on a non-monomorphized view of - // the code.) - // - // assert_eq!(self.drop_flag_info, DropFlagInfo::None); - bcx - } - } - - fn is_by_ref(&self) -> bool { - true - } - - fn to_expr_kind(self) -> Expr { - LvalueExpr(self) - } -} - -impl KindOps for Expr { - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, - val: ValueRef, - ty: Ty<'tcx>) - -> Block<'blk, 'tcx> { - match *self { - LvalueExpr(ref l) => l.post_store(bcx, val, ty), - RvalueExpr(ref r) => r.post_store(bcx, val, ty), - } - } - - fn is_by_ref(&self) -> bool { - match *self { - LvalueExpr(ref l) => l.is_by_ref(), - RvalueExpr(ref r) => r.is_by_ref() - } - } - - fn to_expr_kind(self) -> Expr { - self - } -} - -impl<'tcx> Datum<'tcx, Rvalue> { - /// Schedules a cleanup for this datum in the given scope. That means that this datum is no - /// longer an rvalue datum; hence, this function consumes the datum and returns the contained - /// ValueRef. - pub fn add_clean<'a>(self, - fcx: &FunctionContext<'a, 'tcx>, - scope: cleanup::ScopeId) - -> ValueRef { - add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty); - self.val - } - - /// Returns an lvalue datum (that is, a by ref datum with cleanup scheduled). If `self` is not - /// already an lvalue, cleanup will be scheduled in the temporary scope for `expr_id`. - pub fn to_lvalue_datum_in_scope<'blk>(self, - bcx: Block<'blk, 'tcx>, - name: &str, - scope: cleanup::ScopeId) - -> DatumBlock<'blk, 'tcx, Lvalue> { - let fcx = bcx.fcx; - - match self.kind.mode { - ByRef => { - add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty); - DatumBlock::new(bcx, Datum::new( - self.val, - self.ty, - Lvalue::new("datum::to_lvalue_datum_in_scope"))) - } - - ByValue => { - lvalue_scratch_datum( - bcx, self.ty, name, InitAlloca::Dropped, scope, - |bcx, llval| { - debug!("populate call for Datum::to_lvalue_datum_in_scope \ - self.ty={:?}", self.ty); - // do not call_lifetime_start here; the - // `InitAlloc::Dropped` will start scratch - // value's lifetime at open of function body. - let bcx = self.store_to(bcx, llval); - bcx.fcx.schedule_lifetime_end(scope, llval); - bcx - }) - } - } - } - - pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>) - -> DatumBlock<'blk, 'tcx, Rvalue> { - let mut bcx = bcx; - match self.kind.mode { - ByRef => DatumBlock::new(bcx, self), - ByValue => { - let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref"); - bcx = self.store_to(bcx, scratch.val); - DatumBlock::new(bcx, scratch) - } - } - } - - pub fn to_appropriate_datum<'blk>(self, bcx: Block<'blk, 'tcx>) - -> DatumBlock<'blk, 'tcx, Rvalue> { - match self.appropriate_rvalue_mode(bcx.ccx()) { - ByRef => { - self.to_ref_datum(bcx) - } - ByValue => { - match self.kind.mode { - ByValue => DatumBlock::new(bcx, self), - ByRef => { - let llval = load_ty(bcx, self.val, self.ty); - call_lifetime_end(bcx, self.val); - DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue))) - } - } - } - } - } -} - -/// Methods suitable for "expr" datums that could be either lvalues or -/// rvalues. These include coercions into lvalues/rvalues but also a number -/// of more general operations. (Some of those operations could be moved to -/// the more general `impl Datum`, but it's convenient to have them -/// here since we can `match self.kind` rather than having to implement -/// generic methods in `KindOps`.) -impl<'tcx> Datum<'tcx, Expr> { - fn match_kind(self, if_lvalue: F, if_rvalue: G) -> R where - F: FnOnce(Datum<'tcx, Lvalue>) -> R, - G: FnOnce(Datum<'tcx, Rvalue>) -> R, - { - let Datum { val, ty, kind } = self; - match kind { - LvalueExpr(l) => if_lvalue(Datum::new(val, ty, l)), - RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)), - } - } - - /// Asserts that this datum *is* an lvalue and returns it. - #[allow(dead_code)] // potentially useful - pub fn assert_lvalue(self) -> Datum<'tcx, Lvalue> { - self.match_kind( - |d| d, - |_| bug!("assert_lvalue given rvalue")) - } - - pub fn store_to_dest<'blk>(self, - bcx: Block<'blk, 'tcx>, - dest: expr::Dest, - expr_id: ast::NodeId) - -> Block<'blk, 'tcx> { - match dest { - expr::Ignore => { - self.add_clean_if_rvalue(bcx, expr_id); - bcx - } - expr::SaveIn(addr) => { - self.store_to(bcx, addr) - } - } - } - - /// Arranges cleanup for `self` if it is an rvalue. Use when you are done working with a value - /// that may need drop. - pub fn add_clean_if_rvalue<'blk>(self, - bcx: Block<'blk, 'tcx>, - expr_id: ast::NodeId) { - self.match_kind( - |_| { /* Nothing to do, cleanup already arranged */ }, - |r| { - let scope = cleanup::temporary_scope(bcx.tcx(), expr_id); - r.add_clean(bcx.fcx, scope); - }) - } - - pub fn to_lvalue_datum<'blk>(self, - bcx: Block<'blk, 'tcx>, - name: &str, - expr_id: ast::NodeId) - -> DatumBlock<'blk, 'tcx, Lvalue> { - debug!("to_lvalue_datum self: {:?}", self); - - self.match_kind( - |l| DatumBlock::new(bcx, l), - |r| { - let scope = cleanup::temporary_scope(bcx.tcx(), expr_id); - r.to_lvalue_datum_in_scope(bcx, name, scope) - }) - } - - /// Ensures that we have an rvalue datum (that is, a datum with no cleanup scheduled). - pub fn to_rvalue_datum<'blk>(self, - bcx: Block<'blk, 'tcx>, - name: &'static str) - -> DatumBlock<'blk, 'tcx, Rvalue> { - self.match_kind( - |l| { - let mut bcx = bcx; - match l.appropriate_rvalue_mode(bcx.ccx()) { - ByRef => { - let scratch = rvalue_scratch_datum(bcx, l.ty, name); - bcx = l.store_to(bcx, scratch.val); - DatumBlock::new(bcx, scratch) - } - ByValue => { - let v = load_ty(bcx, l.val, l.ty); - bcx = l.kind.post_store(bcx, l.val, l.ty); - DatumBlock::new(bcx, Datum::new(v, l.ty, Rvalue::new(ByValue))) - } - } - }, - |r| DatumBlock::new(bcx, r)) - } - -} - -/// Methods suitable only for lvalues. These include the various -/// operations to extract components out of compound data structures, -/// such as extracting the field from a struct or a particular element -/// from an array. -impl<'tcx> Datum<'tcx, Lvalue> { - /// Converts a datum into a by-ref value. The datum type must be one which is always passed by - /// reference. - pub fn to_llref(self) -> ValueRef { - self.val - } - - // Extracts a component of a compound data structure (e.g., a field from a - // struct). Note that if self is an opened, unsized type then the returned - // datum may also be unsized _without the size information_. It is the - // callers responsibility to package the result in some way to make a valid - // datum in that case (e.g., by making a fat pointer or opened pair). - pub fn get_element<'blk, F>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>, - gep: F) - -> Datum<'tcx, Lvalue> where - F: FnOnce(adt::MaybeSizedValue) -> ValueRef, - { - let val = if type_is_sized(bcx.tcx(), self.ty) { - let val = adt::MaybeSizedValue::sized(self.val); - gep(val) - } else { - let val = adt::MaybeSizedValue::unsized_( - Load(bcx, expr::get_dataptr(bcx, self.val)), - Load(bcx, expr::get_meta(bcx, self.val))); - gep(val) - }; - Datum { - val: val, - kind: Lvalue::new("Datum::get_element"), - ty: ty, - } - } - - pub fn get_vec_base_and_len<'blk>(&self, bcx: Block<'blk, 'tcx>) - -> (ValueRef, ValueRef) { - //! Converts a vector into the slice pair. - - tvec::get_base_and_len(bcx, self.val, self.ty) - } -} - -/// Generic methods applicable to any sort of datum. -impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> { - pub fn new(val: ValueRef, ty: Ty<'tcx>, kind: K) -> Datum<'tcx, K> { - Datum { val: val, ty: ty, kind: kind } - } - - pub fn to_expr_datum(self) -> Datum<'tcx, Expr> { - let Datum { val, ty, kind } = self; - Datum { val: val, ty: ty, kind: kind.to_expr_kind() } - } - - /// Moves or copies this value into a new home, as appropriate depending on the type of the - /// datum. This method consumes the datum, since it would be incorrect to go on using the datum - /// if the value represented is affine (and hence the value is moved). - pub fn store_to<'blk>(self, - bcx: Block<'blk, 'tcx>, - dst: ValueRef) - -> Block<'blk, 'tcx> { - self.shallow_copy_raw(bcx, dst); - - self.kind.post_store(bcx, self.val, self.ty) - } - - /// Helper function that performs a shallow copy of this value into `dst`, which should be a - /// pointer to a memory location suitable for `self.ty`. `dst` should contain uninitialized - /// memory (either newly allocated, zeroed, or dropped). - /// - /// This function is private to datums because it leaves memory in an unstable state, where the - /// source value has been copied but not zeroed. Public methods are `store_to` (if you no - /// longer need the source value) or `shallow_copy` (if you wish the source value to remain - /// valid). - fn shallow_copy_raw<'blk>(&self, - bcx: Block<'blk, 'tcx>, - dst: ValueRef) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("copy_to_no_check"); - - if type_is_zero_size(bcx.ccx(), self.ty) { - return bcx; - } - - if self.kind.is_by_ref() { - memcpy_ty(bcx, dst, self.val, self.ty); - } else { - store_ty(bcx, self.val, dst, self.ty); - } - - return bcx; - } - - /// Copies the value into a new location. This function always preserves the existing datum as - /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine - /// values (since they must never be duplicated). - pub fn shallow_copy<'blk>(&self, - bcx: Block<'blk, 'tcx>, - dst: ValueRef) - -> Block<'blk, 'tcx> { - /*! - * Copies the value into a new location. This function always - * preserves the existing datum as a valid value. Therefore, - * it does not consume `self` and, also, cannot be applied to - * affine values (since they must never be duplicated). - */ - - assert!(!self.ty.moves_by_default(bcx.tcx(), - &bcx.tcx().empty_parameter_environment(), DUMMY_SP)); - self.shallow_copy_raw(bcx, dst) - } - - /// See the `appropriate_rvalue_mode()` function - pub fn appropriate_rvalue_mode<'a>(&self, ccx: &CrateContext<'a, 'tcx>) - -> RvalueMode { - appropriate_rvalue_mode(ccx, self.ty) - } - - /// Converts `self` into a by-value `ValueRef`. Consumes this datum (i.e., absolves you of - /// responsibility to cleanup the value). For this to work, the value must be something - /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is - /// naturally passed around by value, and not by reference. - pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { - assert!(!bcx.fcx.type_needs_drop(self.ty)); - assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue); - if self.kind.is_by_ref() { - load_ty(bcx, self.val, self.ty) - } else { - self.val - } - } - - pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { - assert!(self.ty.is_bool()); - self.to_llscalarish(bcx) - } -} - -impl<'blk, 'tcx, K> DatumBlock<'blk, 'tcx, K> { - pub fn new(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, K>) - -> DatumBlock<'blk, 'tcx, K> { - DatumBlock { bcx: bcx, datum: datum } - } -} - -impl<'blk, 'tcx, K: KindOps + fmt::Debug> DatumBlock<'blk, 'tcx, K> { - pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> { - DatumBlock::new(self.bcx, self.datum.to_expr_datum()) - } -} - -impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> { - pub fn store_to_dest(self, - dest: expr::Dest, - expr_id: ast::NodeId) -> Block<'blk, 'tcx> { - let DatumBlock { bcx, datum } = self; - datum.store_to_dest(bcx, dest, expr_id) - } - - pub fn to_llbool(self) -> Result<'blk, 'tcx> { - let DatumBlock { datum, bcx } = self; - Result::new(bcx, datum.to_llbool(bcx)) - } -} diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index fe6a48d4c559d..58cf85747374a 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -15,58 +15,15 @@ use super::utils::{DIB, span_start}; use llvm; use llvm::debuginfo::{DIScope, DISubprogram}; use common::{CrateContext, FunctionContext}; -use rustc::hir::pat_util; use rustc::mir::repr::{Mir, VisibilityScope}; -use rustc::util::nodemap::NodeMap; use libc::c_uint; use std::ptr; -use syntax_pos::{Span, Pos}; -use syntax::{ast, codemap}; +use syntax_pos::Pos; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc::hir::{self, PatKind}; - -// This procedure builds the *scope map* for a given function, which maps any -// given ast::NodeId in the function's AST to the correct DIScope metadata instance. -// -// This builder procedure walks the AST in execution order and keeps track of -// what belongs to which scope, creating DIScope DIEs along the way, and -// introducing *artificial* lexical scope descriptors where necessary. These -// artificial scopes allow GDB to correctly handle name shadowing. -pub fn create_scope_map(cx: &CrateContext, - args: &[hir::Arg], - fn_entry_block: &hir::Block, - fn_metadata: DISubprogram, - fn_ast_id: ast::NodeId) - -> NodeMap { - let mut scope_map = NodeMap(); - let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None }); - scope_map.insert(fn_ast_id, fn_metadata); - - // Push argument identifiers onto the stack so arguments integrate nicely - // with variable shadowing. - for arg in args { - pat_util::pat_bindings(&arg.pat, |_, node_id, _, path1| { - scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata, - name: Some(path1.node) }); - scope_map.insert(node_id, fn_metadata); - }) - } - - // Clang creates a separate scope for function bodies, so let's do this too. - with_new_scope(cx, - fn_entry_block.span, - &mut scope_stack, - &mut scope_map, - |cx, scope_stack, scope_map| { - walk_block(cx, fn_entry_block, scope_stack, scope_map); - }); - - return scope_map; -} /// Produce DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. @@ -141,405 +98,3 @@ fn make_mir_scope(ccx: &CrateContext, loc.col.to_usize() as c_uint) }; } - -// local helper functions for walking the AST. -fn with_new_scope(cx: &CrateContext, - scope_span: Span, - scope_stack: &mut Vec , - scope_map: &mut NodeMap, - inner_walk: F) where - F: FnOnce(&CrateContext, &mut Vec, &mut NodeMap), -{ - // Create a new lexical scope and push it onto the stack - let loc = span_start(cx, scope_span); - let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path); - let parent_scope = scope_stack.last().unwrap().scope_metadata; - - let scope_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope, - file_metadata, - loc.line as c_uint, - loc.col.to_usize() as c_uint) - }; - - scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None }); - - inner_walk(cx, scope_stack, scope_map); - - // pop artificial scopes - while scope_stack.last().unwrap().name.is_some() { - scope_stack.pop(); - } - - if scope_stack.last().unwrap().scope_metadata != scope_metadata { - span_bug!(scope_span, "debuginfo: Inconsistency in scope management."); - } - - scope_stack.pop(); -} - -struct ScopeStackEntry { - scope_metadata: DIScope, - name: Option -} - -fn walk_block(cx: &CrateContext, - block: &hir::Block, - scope_stack: &mut Vec , - scope_map: &mut NodeMap) { - scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata); - - // The interesting things here are statements and the concluding expression. - for statement in &block.stmts { - scope_map.insert(statement.node.id(), - scope_stack.last().unwrap().scope_metadata); - - match statement.node { - hir::StmtDecl(ref decl, _) => - walk_decl(cx, &decl, scope_stack, scope_map), - hir::StmtExpr(ref exp, _) | - hir::StmtSemi(ref exp, _) => - walk_expr(cx, &exp, scope_stack, scope_map), - } - } - - if let Some(ref exp) = block.expr { - walk_expr(cx, &exp, scope_stack, scope_map); - } -} - -fn walk_decl(cx: &CrateContext, - decl: &hir::Decl, - scope_stack: &mut Vec , - scope_map: &mut NodeMap) { - match *decl { - codemap::Spanned { node: hir::DeclLocal(ref local), .. } => { - scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata); - - walk_pattern(cx, &local.pat, scope_stack, scope_map); - - if let Some(ref exp) = local.init { - walk_expr(cx, &exp, scope_stack, scope_map); - } - } - _ => () - } -} - -fn walk_pattern(cx: &CrateContext, - pat: &hir::Pat, - scope_stack: &mut Vec , - scope_map: &mut NodeMap) { - // Unfortunately, we cannot just use pat_util::pat_bindings() or - // ast_util::walk_pat() here because we have to visit *all* nodes in - // order to put them into the scope map. The above functions don't do that. - match pat.node { - PatKind::Binding(_, ref path1, ref sub_pat_opt) => { - // LLVM does not properly generate 'DW_AT_start_scope' fields - // for variable DIEs. For this reason we have to introduce - // an artificial scope at bindings whenever a variable with - // the same name is declared in *any* parent scope. - // - // Otherwise the following error occurs: - // - // let x = 10; - // - // do_something(); // 'gdb print x' correctly prints 10 - // - // { - // do_something(); // 'gdb print x' prints 0, because it - // // already reads the uninitialized 'x' - // // from the next line... - // let x = 100; - // do_something(); // 'gdb print x' correctly prints 100 - // } - - // Is there already a binding with that name? - // N.B.: this comparison must be UNhygienic... because - // gdb knows nothing about the context, so any two - // variables with the same name will cause the problem. - let name = path1.node; - let need_new_scope = scope_stack - .iter() - .any(|entry| entry.name == Some(name)); - - if need_new_scope { - // Create a new lexical scope and push it onto the stack - let loc = span_start(cx, pat.span); - let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path); - let parent_scope = scope_stack.last().unwrap().scope_metadata; - - let scope_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope, - file_metadata, - loc.line as c_uint, - loc.col.to_usize() as c_uint) - }; - - scope_stack.push(ScopeStackEntry { - scope_metadata: scope_metadata, - name: Some(name) - }); - - } else { - // Push a new entry anyway so the name can be found - let prev_metadata = scope_stack.last().unwrap().scope_metadata; - scope_stack.push(ScopeStackEntry { - scope_metadata: prev_metadata, - name: Some(name) - }); - } - - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - - if let Some(ref sub_pat) = *sub_pat_opt { - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - } - - PatKind::Wild => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - } - - PatKind::TupleStruct(_, ref sub_pats, _) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - - for p in sub_pats { - walk_pattern(cx, &p, scope_stack, scope_map); - } - } - - PatKind::Path(..) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - } - - PatKind::Struct(_, ref field_pats, _) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - - for &codemap::Spanned { - node: hir::FieldPat { pat: ref sub_pat, .. }, - .. - } in field_pats { - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - } - - PatKind::Tuple(ref sub_pats, _) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - - for sub_pat in sub_pats { - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - } - - PatKind::Box(ref sub_pat) | PatKind::Ref(ref sub_pat, _) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - - PatKind::Lit(ref exp) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - walk_expr(cx, &exp, scope_stack, scope_map); - } - - PatKind::Range(ref exp1, ref exp2) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - walk_expr(cx, &exp1, scope_stack, scope_map); - walk_expr(cx, &exp2, scope_stack, scope_map); - } - - PatKind::Vec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => { - scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - - for sub_pat in front_sub_pats { - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - - if let Some(ref sub_pat) = *middle_sub_pats { - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - - for sub_pat in back_sub_pats { - walk_pattern(cx, &sub_pat, scope_stack, scope_map); - } - } - } -} - -fn walk_expr(cx: &CrateContext, - exp: &hir::Expr, - scope_stack: &mut Vec , - scope_map: &mut NodeMap) { - - scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata); - - match exp.node { - hir::ExprLit(_) | - hir::ExprBreak(_) | - hir::ExprAgain(_) | - hir::ExprPath(..) => {} - - hir::ExprCast(ref sub_exp, _) | - hir::ExprType(ref sub_exp, _) | - hir::ExprAddrOf(_, ref sub_exp) | - hir::ExprField(ref sub_exp, _) | - hir::ExprTupField(ref sub_exp, _) => - walk_expr(cx, &sub_exp, scope_stack, scope_map), - - hir::ExprBox(ref sub_expr) => { - walk_expr(cx, &sub_expr, scope_stack, scope_map); - } - - hir::ExprRet(ref exp_opt) => match *exp_opt { - Some(ref sub_exp) => walk_expr(cx, &sub_exp, scope_stack, scope_map), - None => () - }, - - hir::ExprUnary(_, ref sub_exp) => { - walk_expr(cx, &sub_exp, scope_stack, scope_map); - } - - hir::ExprAssignOp(_, ref lhs, ref rhs) | - hir::ExprIndex(ref lhs, ref rhs) | - hir::ExprBinary(_, ref lhs, ref rhs) => { - walk_expr(cx, &lhs, scope_stack, scope_map); - walk_expr(cx, &rhs, scope_stack, scope_map); - } - - hir::ExprVec(ref init_expressions) | - hir::ExprTup(ref init_expressions) => { - for ie in init_expressions { - walk_expr(cx, &ie, scope_stack, scope_map); - } - } - - hir::ExprAssign(ref sub_exp1, ref sub_exp2) | - hir::ExprRepeat(ref sub_exp1, ref sub_exp2) => { - walk_expr(cx, &sub_exp1, scope_stack, scope_map); - walk_expr(cx, &sub_exp2, scope_stack, scope_map); - } - - hir::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => { - walk_expr(cx, &cond_exp, scope_stack, scope_map); - - with_new_scope(cx, - then_block.span, - scope_stack, - scope_map, - |cx, scope_stack, scope_map| { - walk_block(cx, &then_block, scope_stack, scope_map); - }); - - match *opt_else_exp { - Some(ref else_exp) => - walk_expr(cx, &else_exp, scope_stack, scope_map), - _ => () - } - } - - hir::ExprWhile(ref cond_exp, ref loop_body, _) => { - walk_expr(cx, &cond_exp, scope_stack, scope_map); - - with_new_scope(cx, - loop_body.span, - scope_stack, - scope_map, - |cx, scope_stack, scope_map| { - walk_block(cx, &loop_body, scope_stack, scope_map); - }) - } - - hir::ExprLoop(ref block, _) | - hir::ExprBlock(ref block) => { - with_new_scope(cx, - block.span, - scope_stack, - scope_map, - |cx, scope_stack, scope_map| { - walk_block(cx, &block, scope_stack, scope_map); - }) - } - - hir::ExprClosure(_, ref decl, ref block, _) => { - with_new_scope(cx, - block.span, - scope_stack, - scope_map, - |cx, scope_stack, scope_map| { - for &hir::Arg { pat: ref pattern, .. } in &decl.inputs { - walk_pattern(cx, &pattern, scope_stack, scope_map); - } - - walk_block(cx, &block, scope_stack, scope_map); - }) - } - - hir::ExprCall(ref fn_exp, ref args) => { - walk_expr(cx, &fn_exp, scope_stack, scope_map); - - for arg_exp in args { - walk_expr(cx, &arg_exp, scope_stack, scope_map); - } - } - - hir::ExprMethodCall(_, _, ref args) => { - for arg_exp in args { - walk_expr(cx, &arg_exp, scope_stack, scope_map); - } - } - - hir::ExprMatch(ref discriminant_exp, ref arms, _) => { - walk_expr(cx, &discriminant_exp, scope_stack, scope_map); - - // For each arm we have to first walk the pattern as these might - // introduce new artificial scopes. It should be sufficient to - // walk only one pattern per arm, as they all must contain the - // same binding names. - - for arm_ref in arms { - let arm_span = arm_ref.pats[0].span; - - with_new_scope(cx, - arm_span, - scope_stack, - scope_map, - |cx, scope_stack, scope_map| { - for pat in &arm_ref.pats { - walk_pattern(cx, &pat, scope_stack, scope_map); - } - - if let Some(ref guard_exp) = arm_ref.guard { - walk_expr(cx, &guard_exp, scope_stack, scope_map) - } - - walk_expr(cx, &arm_ref.body, scope_stack, scope_map); - }) - } - } - - hir::ExprStruct(_, ref fields, ref base_exp) => { - for &hir::Field { expr: ref exp, .. } in fields { - walk_expr(cx, &exp, scope_stack, scope_map); - } - - match *base_exp { - Some(ref exp) => walk_expr(cx, &exp, scope_stack, scope_map), - None => () - } - } - - hir::ExprInlineAsm(_, ref outputs, ref inputs) => { - for output in outputs { - walk_expr(cx, output, scope_stack, scope_map); - } - - for input in inputs { - walk_expr(cx, input, scope_stack, scope_map); - } - } - } -} diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index f505efb1ab2f9..fb1a5f7eb04f9 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -14,11 +14,10 @@ use self::MemberDescriptionFactory::*; use self::EnumDiscriminantInfo::*; use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align_of, - get_namespace_and_span_for_item, create_DIArray, - fn_should_be_ignored, is_node_local_to_unit}; + get_namespace_and_span_for_item, create_DIArray, is_node_local_to_unit}; use super::namespace::mangled_name_of_item; use super::type_names::{compute_debuginfo_type_name, push_debuginfo_type_name}; -use super::{declare_local, VariableKind, VariableAccess, CrateDebugContext}; +use super::{CrateDebugContext}; use context::SharedCrateContext; use session::Session; @@ -26,16 +25,13 @@ use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; use rustc::hir::def_id::DefId; -use rustc::hir::pat_util; use rustc::ty::subst::Substs; -use rustc::hir::map as hir_map; -use rustc::hir::{self, PatKind}; +use rustc::hir; use {type_of, adt, machine, monomorphize}; -use common::{self, CrateContext, FunctionContext, Block}; -use _match::{BindingInfo, TransBindingMode}; +use common::{CrateContext, FunctionContext}; use type_::Type; use rustc::ty::{self, Ty}; -use session::config::{self, FullDebugInfo}; +use session::config; use util::nodemap::FnvHashMap; use util::common::path2cstr; @@ -1863,226 +1859,3 @@ pub fn create_global_var_metadata(cx: &CrateContext, ptr::null_mut()); } } - -/// Creates debug information for the given local variable. -/// -/// This function assumes that there's a datum for each pattern component of the -/// local in `bcx.fcx.lllocals`. -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_local_var_metadata(bcx: Block, local: &hir::Local) { - if bcx.unreachable.get() || - fn_should_be_ignored(bcx.fcx) || - bcx.sess().opts.debuginfo != FullDebugInfo { - return; - } - - let locals = bcx.fcx.lllocals.borrow(); - pat_util::pat_bindings(&local.pat, |_, node_id, span, var_name| { - let datum = match locals.get(&node_id) { - Some(datum) => datum, - None => { - span_bug!(span, - "no entry in lllocals table for {}", - node_id); - } - }; - - if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() { - span_bug!(span, "debuginfo::create_local_var_metadata() - \ - Referenced variable location is not an alloca!"); - } - - let scope_metadata = scope_metadata(bcx.fcx, node_id, span); - - declare_local(bcx, - var_name.node, - datum.ty, - scope_metadata, - VariableAccess::DirectVariable { alloca: datum.val }, - VariableKind::LocalVariable, - span); - }) -} - -/// Creates debug information for a variable captured in a closure. -/// -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - node_id: ast::NodeId, - env_pointer: ValueRef, - env_index: usize, - captured_by_ref: bool, - span: Span) { - if bcx.unreachable.get() || - fn_should_be_ignored(bcx.fcx) || - bcx.sess().opts.debuginfo != FullDebugInfo { - return; - } - - let cx = bcx.ccx(); - - let ast_item = cx.tcx().map.find(node_id); - - let variable_name = match ast_item { - None => { - span_bug!(span, "debuginfo::create_captured_var_metadata: node not found"); - } - Some(hir_map::NodeLocal(pat)) => { - match pat.node { - PatKind::Binding(_, ref path1, _) => { - path1.node - } - _ => { - span_bug!(span, - "debuginfo::create_captured_var_metadata() - \ - Captured var-id refers to unexpected \ - hir_map variant: {:?}", - ast_item); - } - } - } - _ => { - span_bug!(span, - "debuginfo::create_captured_var_metadata() - \ - Captured var-id refers to unexpected \ - hir_map variant: {:?}", - ast_item); - } - }; - - let variable_type = common::node_id_type(bcx, node_id); - let scope_metadata = bcx.fcx.debug_context.get_ref(span).fn_metadata; - - // env_pointer is the alloca containing the pointer to the environment, - // so it's type is **EnvironmentType. In order to find out the type of - // the environment we have to "dereference" two times. - let llvm_env_data_type = common::val_ty(env_pointer).element_type() - .element_type(); - let byte_offset_of_var_in_env = machine::llelement_offset(cx, - llvm_env_data_type, - env_index); - - let address_operations = unsafe { - [llvm::LLVMRustDIBuilderCreateOpDeref(), - llvm::LLVMRustDIBuilderCreateOpPlus(), - byte_offset_of_var_in_env as i64, - llvm::LLVMRustDIBuilderCreateOpDeref()] - }; - - let address_op_count = if captured_by_ref { - address_operations.len() - } else { - address_operations.len() - 1 - }; - - let variable_access = VariableAccess::IndirectVariable { - alloca: env_pointer, - address_operations: &address_operations[..address_op_count] - }; - - declare_local(bcx, - variable_name, - variable_type, - scope_metadata, - variable_access, - VariableKind::CapturedVariable, - span); -} - -/// Creates debug information for a local variable introduced in the head of a -/// match-statement arm. -/// -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - variable_name: ast::Name, - binding: BindingInfo<'tcx>) { - if bcx.unreachable.get() || - fn_should_be_ignored(bcx.fcx) || - bcx.sess().opts.debuginfo != FullDebugInfo { - return; - } - - let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span); - let aops = unsafe { - [llvm::LLVMRustDIBuilderCreateOpDeref()] - }; - // Regardless of the actual type (`T`) we're always passed the stack slot - // (alloca) for the binding. For ByRef bindings that's a `T*` but for ByMove - // bindings we actually have `T**`. So to get the actual variable we need to - // dereference once more. For ByCopy we just use the stack slot we created - // for the binding. - let var_access = match binding.trmode { - TransBindingMode::TrByCopy(llbinding) | - TransBindingMode::TrByMoveIntoCopy(llbinding) => VariableAccess::DirectVariable { - alloca: llbinding - }, - TransBindingMode::TrByMoveRef => VariableAccess::IndirectVariable { - alloca: binding.llmatch, - address_operations: &aops - }, - TransBindingMode::TrByRef => VariableAccess::DirectVariable { - alloca: binding.llmatch - } - }; - - declare_local(bcx, - variable_name, - binding.ty, - scope_metadata, - var_access, - VariableKind::LocalVariable, - binding.span); -} - -/// Creates debug information for the given function argument. -/// -/// This function assumes that there's a datum for each pattern component of the -/// argument in `bcx.fcx.lllocals`. -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) { - if bcx.unreachable.get() || - fn_should_be_ignored(bcx.fcx) || - bcx.sess().opts.debuginfo != FullDebugInfo { - return; - } - - let scope_metadata = bcx - .fcx - .debug_context - .get_ref(arg.pat.span) - .fn_metadata; - let locals = bcx.fcx.lllocals.borrow(); - - pat_util::pat_bindings(&arg.pat, |_, node_id, span, var_name| { - let datum = match locals.get(&node_id) { - Some(v) => v, - None => { - span_bug!(span, "no entry in lllocals table for {}", node_id); - } - }; - - if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() { - span_bug!(span, "debuginfo::create_argument_metadata() - \ - Referenced variable location is not an alloca!"); - } - - let argument_index = { - let counter = &bcx - .fcx - .debug_context - .get_ref(span) - .argument_counter; - let argument_index = counter.get(); - counter.set(argument_index + 1); - argument_index - }; - - declare_local(bcx, - var_name.node, - datum.ty, - scope_metadata, - VariableAccess::DirectVariable { alloca: datum.val }, - VariableKind::ArgumentVariable(argument_index), - span); - }) -} diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 1ee000992b9c5..a864f974c96fc 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -56,13 +56,7 @@ mod source_loc; pub use self::create_scope_map::create_mir_scopes; pub use self::source_loc::start_emitting_source_locations; -pub use self::source_loc::get_cleanup_debug_loc_for_ast_node; -pub use self::source_loc::with_source_location_override; -pub use self::metadata::create_match_binding_metadata; -pub use self::metadata::create_argument_metadata; -pub use self::metadata::create_captured_var_metadata; pub use self::metadata::create_global_var_metadata; -pub use self::metadata::create_local_var_metadata; #[allow(non_upper_case_globals)] const DW_TAG_auto_variable: c_uint = 0x100; @@ -142,7 +136,6 @@ impl FunctionDebugContext { pub struct FunctionDebugContextData { scope_map: RefCell>, fn_metadata: DISubprogram, - argument_counter: Cell, source_locations_enabled: Cell, source_location_override: Cell, } @@ -307,7 +300,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fn_debug_context = box FunctionDebugContextData { scope_map: RefCell::new(NodeMap()), fn_metadata: fn_metadata, - argument_counter: Cell::new(1), source_locations_enabled: Cell::new(false), source_location_override: Cell::new(false), }; @@ -455,25 +447,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } -/// Computes the scope map for a function given its declaration and body. -pub fn fill_scope_map_for_function<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, - fn_decl: &hir::FnDecl, - top_level_block: &hir::Block, - fn_ast_id: ast::NodeId) { - match fcx.debug_context { - FunctionDebugContext::RegularContext(box ref data) => { - let scope_map = create_scope_map::create_scope_map(fcx.ccx, - &fn_decl.inputs, - top_level_block, - data.fn_metadata, - fn_ast_id); - *data.scope_map.borrow_mut() = scope_map; - } - FunctionDebugContext::DebugInfoDisabled | - FunctionDebugContext::FunctionWithoutDebugInfo => {} - } -} - pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, variable_name: ast::Name, variable_type: Ty<'tcx>, diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_trans/debuginfo/source_loc.rs index d288b9dcef70b..32b414d279628 100644 --- a/src/librustc_trans/debuginfo/source_loc.rs +++ b/src/librustc_trans/debuginfo/source_loc.rs @@ -17,73 +17,11 @@ use super::{FunctionDebugContext, DebugLoc}; use llvm; use llvm::debuginfo::DIScope; use builder::Builder; -use common::{NodeIdAndSpan, CrateContext, FunctionContext}; +use common::{CrateContext, FunctionContext}; use libc::c_uint; use std::ptr; -use syntax_pos::{self, Span, Pos}; -use syntax::ast; - -pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - node_id: ast::NodeId, - node_span: Span, - is_block: bool) - -> NodeIdAndSpan { - // A debug location needs two things: - // (1) A span (of which only the beginning will actually be used) - // (2) An AST node-id which will be used to look up the lexical scope - // for the location in the functions scope-map - // - // This function will calculate the debug location for compiler-generated - // cleanup calls that are executed when control-flow leaves the - // scope identified by `node_id`. - // - // For everything but block-like things we can simply take id and span of - // the given expression, meaning that from a debugger's view cleanup code is - // executed at the same source location as the statement/expr itself. - // - // Blocks are a special case. Here we want the cleanup to be linked to the - // closing curly brace of the block. The *scope* the cleanup is executed in - // is up to debate: It could either still be *within* the block being - // cleaned up, meaning that locals from the block are still visible in the - // debugger. - // Or it could be in the scope that the block is contained in, so any locals - // from within the block are already considered out-of-scope and thus not - // accessible in the debugger anymore. - // - // The current implementation opts for the second option: cleanup of a block - // already happens in the parent scope of the block. The main reason for - // this decision is that scoping becomes controlflow dependent when variable - // shadowing is involved and it's impossible to decide statically which - // scope is actually left when the cleanup code is executed. - // In practice it shouldn't make much of a difference. - - let mut cleanup_span = node_span; - - if is_block { - // Not all blocks actually have curly braces (e.g. simple closure - // bodies), in which case we also just want to return the span of the - // whole expression. - let code_snippet = cx.sess().codemap().span_to_snippet(node_span); - if let Ok(code_snippet) = code_snippet { - let bytes = code_snippet.as_bytes(); - - if !bytes.is_empty() && &bytes[bytes.len()-1..] == b"}" { - cleanup_span = Span { - lo: node_span.hi - syntax_pos::BytePos(1), - hi: node_span.hi, - expn_id: node_span.expn_id - }; - } - } - } - - NodeIdAndSpan { - id: node_id, - span: cleanup_span - } -} - +use syntax_pos::Pos; /// Sets the current debug location at the beginning of the span. /// @@ -129,35 +67,6 @@ pub fn set_source_location(fcx: &FunctionContext, set_debug_location(fcx.ccx, builder, dbg_loc); } -/// This function makes sure that all debug locations emitted while executing -/// `wrapped_function` are set to the given `debug_loc`. -pub fn with_source_location_override(fcx: &FunctionContext, - debug_loc: DebugLoc, - wrapped_function: F) -> R - where F: FnOnce() -> R -{ - match fcx.debug_context { - FunctionDebugContext::DebugInfoDisabled => { - wrapped_function() - } - FunctionDebugContext::FunctionWithoutDebugInfo => { - set_debug_location(fcx.ccx, None, UnknownLocation); - wrapped_function() - } - FunctionDebugContext::RegularContext(box ref function_debug_context) => { - if function_debug_context.source_location_override.get() { - wrapped_function() - } else { - debug_loc.apply(fcx); - function_debug_context.source_location_override.set(true); - let result = wrapped_function(); - function_debug_context.source_location_override.set(false); - result - } - } - } -} - /// Enables emitting source locations for the given functions. /// /// Since we don't want source locations to be emitted for the function prelude, diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 5734a12394113..3cdac485fecc9 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -10,7 +10,7 @@ // Utility Functions. -use super::{FunctionDebugContext, CrateDebugContext}; +use super::{CrateDebugContext}; use super::namespace::item_namespace; use rustc::hir::def_id::DefId; @@ -18,7 +18,7 @@ use rustc::hir::def_id::DefId; use llvm; use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray}; use machine; -use common::{CrateContext, FunctionContext}; +use common::{CrateContext}; use type_::Type; use syntax_pos::{self, Span}; @@ -70,13 +70,6 @@ pub fn DIB(cx: &CrateContext) -> DIBuilderRef { cx.dbg_cx().as_ref().unwrap().builder } -pub fn fn_should_be_ignored(fcx: &FunctionContext) -> bool { - match fcx.debug_context { - FunctionDebugContext::RegularContext(_) => false, - _ => true - } -} - pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId) -> (DIScope, Span) { let containing_scope = item_namespace(cx, DefId { diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs deleted file mode 100644 index beb589c80bfc5..0000000000000 --- a/src/librustc_trans/expr.rs +++ /dev/null @@ -1,2473 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Translation of Expressions -//! -//! The expr module handles translation of expressions. The most general -//! translation routine is `trans()`, which will translate an expression -//! into a datum. `trans_into()` is also available, which will translate -//! an expression and write the result directly into memory, sometimes -//! avoiding the need for a temporary stack slot. Finally, -//! `trans_to_lvalue()` is available if you'd like to ensure that the -//! result has cleanup scheduled. -//! -//! Internally, each of these functions dispatches to various other -//! expression functions depending on the kind of expression. We divide -//! up expressions into: -//! -//! - **Datum expressions:** Those that most naturally yield values. -//! Examples would be `22`, `box x`, or `a + b` (when not overloaded). -//! - **DPS expressions:** Those that most naturally write into a location -//! in memory. Examples would be `foo()` or `Point { x: 3, y: 4 }`. -//! - **Statement expressions:** That that do not generate a meaningful -//! result. Examples would be `while { ... }` or `return 44`. -//! -//! Public entry points: -//! -//! - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression, -//! storing the result into `dest`. This is the preferred form, if you -//! can manage it. -//! -//! - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding -//! `Datum` with the result. You can then store the datum, inspect -//! the value, etc. This may introduce temporaries if the datum is a -//! structural type. -//! -//! - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an -//! expression and ensures that the result has a cleanup associated with it, -//! creating a temporary stack slot if necessary. -//! -//! - `trans_var -> Datum`: looks up a local variable, upvar or static. - -#![allow(non_camel_case_types)] - -pub use self::Dest::*; -use self::lazy_binop_ty::*; - -use llvm::{self, ValueRef, TypeKind}; -use middle::const_qualif::ConstQualif; -use rustc::hir::def::Def; -use rustc::ty::subst::Substs; -use {_match, abi, adt, asm, base, closure, consts, controlflow}; -use base::*; -use build::*; -use callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp}; -use cleanup::{self, CleanupMethods, DropHintMethods}; -use common::*; -use datum::*; -use debuginfo::{self, DebugLoc, ToDebugLoc}; -use glue; -use machine; -use tvec; -use type_of; -use value::Value; -use Disr; -use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer}; -use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::MethodCall; -use rustc::ty::cast::{CastKind, CastTy}; -use util::common::indenter; -use machine::{llsize_of, llsize_of_alloc}; -use type_::Type; - -use rustc::hir; - -use syntax::ast; -use syntax::parse::token::InternedString; -use syntax_pos; -use std::fmt; -use std::mem; - -// Destinations - -// These are passed around by the code generating functions to track the -// destination of a computation's value. - -#[derive(Copy, Clone, PartialEq)] -pub enum Dest { - SaveIn(ValueRef), - Ignore, -} - -impl fmt::Debug for Dest { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - SaveIn(v) => write!(f, "SaveIn({:?})", Value(v)), - Ignore => f.write_str("Ignore") - } - } -} - -/// This function is equivalent to `trans(bcx, expr).store_to_dest(dest)` but it may generate -/// better optimized LLVM code. -pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - dest: Dest) - -> Block<'blk, 'tcx> { - let mut bcx = bcx; - - expr.debug_loc().apply(bcx.fcx); - - if adjustment_required(bcx, expr) { - // use trans, which may be less efficient but - // which will perform the adjustments: - let datum = unpack_datum!(bcx, trans(bcx, expr)); - return datum.store_to_dest(bcx, dest, expr.id); - } - - let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap(); - if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) { - if !qualif.intersects(ConstQualif::PREFER_IN_PLACE) { - if let SaveIn(lldest) = dest { - match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, - bcx.fcx.param_substs, - consts::TrueConst::No) { - Ok(global) => { - // Cast pointer to destination, because constants - // have different types. - let lldest = PointerCast(bcx, lldest, val_ty(global)); - memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr)); - return bcx; - }, - Err(consts::ConstEvalFailure::Runtime(_)) => { - // in case const evaluation errors, translate normally - // debug assertions catch the same errors - // see RFC 1229 - }, - Err(consts::ConstEvalFailure::Compiletime(_)) => { - return bcx; - }, - } - } - - // If we see a const here, that's because it evaluates to a type with zero size. We - // should be able to just discard it, since const expressions are guaranteed not to - // have side effects. This seems to be reached through tuple struct constructors being - // passed zero-size constants. - if let hir::ExprPath(..) = expr.node { - match bcx.tcx().expect_def(expr.id) { - Def::Const(_) | Def::AssociatedConst(_) => { - assert!(type_is_zero_size(bcx.ccx(), bcx.tcx().node_id_to_type(expr.id))); - return bcx; - } - _ => {} - } - } - - // Even if we don't have a value to emit, and the expression - // doesn't have any side-effects, we still have to translate the - // body of any closures. - // FIXME: Find a better way of handling this case. - } else { - // The only way we're going to see a `const` at this point is if - // it prefers in-place instantiation, likely because it contains - // `[x; N]` somewhere within. - match expr.node { - hir::ExprPath(..) => { - match bcx.tcx().expect_def(expr.id) { - Def::Const(did) | Def::AssociatedConst(did) => { - let empty_substs = Substs::empty(bcx.tcx()); - let const_expr = consts::get_const_expr(bcx.ccx(), did, expr, - empty_substs); - // Temporarily get cleanup scopes out of the way, - // as they require sub-expressions to be contained - // inside the current AST scope. - // These should record no cleanups anyways, `const` - // can't have destructors. - let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(), - vec![]); - // Lock emitted debug locations to the location of - // the constant reference expression. - debuginfo::with_source_location_override(bcx.fcx, - expr.debug_loc(), - || { - bcx = trans_into(bcx, const_expr, dest) - }); - let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(), - scopes); - assert!(scopes.is_empty()); - return bcx; - } - _ => {} - } - } - _ => {} - } - } - } - - debug!("trans_into() expr={:?}", expr); - - let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), - expr.id, - expr.span, - false); - bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc); - - let kind = expr_kind(bcx.tcx(), expr); - bcx = match kind { - ExprKind::Lvalue | ExprKind::RvalueDatum => { - trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id) - } - ExprKind::RvalueDps => { - trans_rvalue_dps_unadjusted(bcx, expr, dest) - } - ExprKind::RvalueStmt => { - trans_rvalue_stmt_unadjusted(bcx, expr) - } - }; - - bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id) -} - -/// Translates an expression, returning a datum (and new block) encapsulating the result. When -/// possible, it is preferred to use `trans_into`, as that may avoid creating a temporary on the -/// stack. -pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - debug!("trans(expr={:?})", expr); - - let mut bcx = bcx; - let fcx = bcx.fcx; - let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap(); - let adjusted_global = !qualif.intersects(ConstQualif::NON_STATIC_BORROWS); - let global = if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) { - match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, - bcx.fcx.param_substs, - consts::TrueConst::No) { - Ok(global) => { - if qualif.intersects(ConstQualif::HAS_STATIC_BORROWS) { - // Is borrowed as 'static, must return lvalue. - - // Cast pointer to global, because constants have different types. - let const_ty = expr_ty_adjusted(bcx, expr); - let llty = type_of::type_of(bcx.ccx(), const_ty); - let global = PointerCast(bcx, global, llty.ptr_to()); - let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans")); - return DatumBlock::new(bcx, datum.to_expr_datum()); - } - - // Otherwise, keep around and perform adjustments, if needed. - let const_ty = if adjusted_global { - expr_ty_adjusted(bcx, expr) - } else { - expr_ty(bcx, expr) - }; - - // This could use a better heuristic. - Some(if type_is_immediate(bcx.ccx(), const_ty) { - // Cast pointer to global, because constants have different types. - let llty = type_of::type_of(bcx.ccx(), const_ty); - let global = PointerCast(bcx, global, llty.ptr_to()); - // Maybe just get the value directly, instead of loading it? - immediate_rvalue(load_ty(bcx, global, const_ty), const_ty) - } else { - let scratch = alloc_ty(bcx, const_ty, "const"); - call_lifetime_start(bcx, scratch); - let lldest = if !const_ty.is_structural() { - // Cast pointer to slot, because constants have different types. - PointerCast(bcx, scratch, val_ty(global)) - } else { - // In this case, memcpy_ty calls llvm.memcpy after casting both - // source and destination to i8*, so we don't need any casts. - scratch - }; - memcpy_ty(bcx, lldest, global, const_ty); - Datum::new(scratch, const_ty, Rvalue::new(ByRef)) - }) - }, - Err(consts::ConstEvalFailure::Runtime(_)) => { - // in case const evaluation errors, translate normally - // debug assertions catch the same errors - // see RFC 1229 - None - }, - Err(consts::ConstEvalFailure::Compiletime(_)) => { - // generate a dummy llvm value - let const_ty = expr_ty(bcx, expr); - let llty = type_of::type_of(bcx.ccx(), const_ty); - let dummy = C_undef(llty.ptr_to()); - Some(Datum::new(dummy, const_ty, Rvalue::new(ByRef))) - }, - } - } else { - None - }; - - let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), - expr.id, - expr.span, - false); - fcx.push_ast_cleanup_scope(cleanup_debug_loc); - let datum = match global { - Some(rvalue) => rvalue.to_expr_datum(), - None => unpack_datum!(bcx, trans_unadjusted(bcx, expr)) - }; - let datum = if adjusted_global { - datum // trans::consts already performed adjustments. - } else { - unpack_datum!(bcx, apply_adjustments(bcx, expr, datum)) - }; - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id); - return DatumBlock::new(bcx, datum); -} - -pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef { - StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA) -} - -pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { - StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR) -} - -pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { - Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr)); - Store(bcx, Load(bcx, get_meta(bcx, src_ptr)), get_meta(bcx, dst_ptr)); -} - -fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr) -> bool { - let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() { - None => { return false; } - Some(adj) => adj - }; - - // Don't skip a conversion from Box to &T, etc. - if bcx.tcx().is_overloaded_autoderef(expr.id, 0) { - return true; - } - - match adjustment { - AdjustNeverToAny(..) => true, - AdjustReifyFnPointer => true, - AdjustUnsafeFnPointer | AdjustMutToConstPointer => { - // purely a type-level thing - false - } - AdjustDerefRef(ref adj) => { - // We are a bit paranoid about adjustments and thus might have a re- - // borrow here which merely derefs and then refs again (it might have - // a different region or mutability, but we don't care here). - !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none()) - } - } -} - -/// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted -/// translation of `expr`. -fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> -{ - let mut bcx = bcx; - let mut datum = datum; - let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() { - None => { - return DatumBlock::new(bcx, datum); - } - Some(adj) => { adj } - }; - debug!("unadjusted datum for expr {:?}: {:?} adjustment={:?}", - expr, datum, adjustment); - match adjustment { - AdjustNeverToAny(ref target) => { - let mono_target = bcx.monomorphize(target); - let llty = type_of::type_of(bcx.ccx(), mono_target); - let dummy = C_undef(llty.ptr_to()); - datum = Datum::new(dummy, mono_target, Lvalue::new("never")).to_expr_datum(); - } - AdjustReifyFnPointer => { - match datum.ty.sty { - ty::TyFnDef(def_id, substs, _) => { - datum = Callee::def(bcx.ccx(), def_id, substs) - .reify(bcx.ccx()).to_expr_datum(); - } - _ => { - bug!("{} cannot be reified to a fn ptr", datum.ty) - } - } - } - AdjustUnsafeFnPointer | AdjustMutToConstPointer => { - // purely a type-level thing - } - AdjustDerefRef(ref adj) => { - let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() { - // We are a bit paranoid about adjustments and thus might have a re- - // borrow here which merely derefs and then refs again (it might have - // a different region or mutability, but we don't care here). - match datum.ty.sty { - // Don't skip a conversion from Box to &T, etc. - ty::TyRef(..) => { - if bcx.tcx().is_overloaded_autoderef(expr.id, 0) { - // Don't skip an overloaded deref. - 0 - } else { - 1 - } - } - _ => 0 - } - } else { - 0 - }; - - if adj.autoderefs > skip_reborrows { - // Schedule cleanup. - let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); - datum = unpack_datum!(bcx, deref_multiple(bcx, expr, - lval.to_expr_datum(), - adj.autoderefs - skip_reborrows)); - } - - // (You might think there is a more elegant way to do this than a - // skip_reborrows bool, but then you remember that the borrow checker exists). - if skip_reborrows == 0 && adj.autoref.is_some() { - datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr)); - } - - if let Some(target) = adj.unsize { - // We do not arrange cleanup ourselves; if we already are an - // L-value, then cleanup will have already been scheduled (and - // the `datum.to_rvalue_datum` call below will emit code to zero - // the drop flag when moving out of the L-value). If we are an - // R-value, then we do not need to schedule cleanup. - let source_datum = unpack_datum!(bcx, - datum.to_rvalue_datum(bcx, "__coerce_source")); - - let target = bcx.monomorphize(&target); - - let scratch = alloc_ty(bcx, target, "__coerce_target"); - call_lifetime_start(bcx, scratch); - let target_datum = Datum::new(scratch, target, - Rvalue::new(ByRef)); - bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum); - datum = Datum::new(scratch, target, - RvalueExpr(Rvalue::new(ByRef))); - } - } - } - debug!("after adjustments, datum={:?}", datum); - DatumBlock::new(bcx, datum) -} - -fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - span: syntax_pos::Span, - source: Datum<'tcx, Rvalue>, - target: Datum<'tcx, Rvalue>) - -> Block<'blk, 'tcx> { - let mut bcx = bcx; - debug!("coerce_unsized({:?} -> {:?})", source, target); - - match (&source.ty.sty, &target.ty.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) | - (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), - &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | - (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), - &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | - (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), - &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { - let (inner_source, inner_target) = (a, b); - - let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) { - // Normally, the source is a thin pointer and we are - // adding extra info to make a fat pointer. The exception - // is when we are upcasting an existing object fat pointer - // to use a different vtable. In that case, we want to - // load out the original data pointer so we can repackage - // it. - (Load(bcx, get_dataptr(bcx, source.val)), - Some(Load(bcx, get_meta(bcx, source.val)))) - } else { - let val = if source.kind.is_by_ref() { - load_ty(bcx, source.val, source.ty) - } else { - source.val - }; - (val, None) - }; - - let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info); - - // Compute the base pointer. This doesn't change the pointer value, - // but merely its type. - let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to(); - let base = PointerCast(bcx, base, ptr_ty); - - Store(bcx, base, get_dataptr(bcx, target.val)); - Store(bcx, info, get_meta(bcx, target.val)); - } - - // This can be extended to enums and tuples in the future. - // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) | - (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => { - assert_eq!(def_id_a, def_id_b); - - // The target is already by-ref because it's to be written to. - let source = unpack_datum!(bcx, source.to_ref_datum(bcx)); - assert!(target.kind.is_by_ref()); - - let kind = custom_coerce_unsize_info(bcx.ccx().shared(), - source.ty, - target.ty); - - let repr_source = adt::represent_type(bcx.ccx(), source.ty); - let src_fields = match &*repr_source { - &adt::Repr::Univariant(ref s, _) => &s.fields, - _ => span_bug!(span, - "Non univariant struct? (repr_source: {:?})", - repr_source), - }; - let repr_target = adt::represent_type(bcx.ccx(), target.ty); - let target_fields = match &*repr_target { - &adt::Repr::Univariant(ref s, _) => &s.fields, - _ => span_bug!(span, - "Non univariant struct? (repr_target: {:?})", - repr_target), - }; - - let coerce_index = match kind { - CustomCoerceUnsized::Struct(i) => i - }; - assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len()); - - let source_val = adt::MaybeSizedValue::sized(source.val); - let target_val = adt::MaybeSizedValue::sized(target.val); - - let iter = src_fields.iter().zip(target_fields).enumerate(); - for (i, (src_ty, target_ty)) in iter { - let ll_source = adt::trans_field_ptr(bcx, &repr_source, source_val, Disr(0), i); - let ll_target = adt::trans_field_ptr(bcx, &repr_target, target_val, Disr(0), i); - - // If this is the field we need to coerce, recurse on it. - if i == coerce_index { - coerce_unsized(bcx, span, - Datum::new(ll_source, src_ty, - Rvalue::new(ByRef)), - Datum::new(ll_target, target_ty, - Rvalue::new(ByRef))); - } else { - // Otherwise, simply copy the data from the source. - assert!(src_ty.is_phantom_data() || src_ty == target_ty); - memcpy_ty(bcx, ll_target, ll_source, src_ty); - } - } - } - _ => bug!("coerce_unsized: invalid coercion {:?} -> {:?}", - source.ty, - target.ty) - } - bcx -} - -/// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory -/// that the expr represents. -/// -/// If this expression is an rvalue, this implies introducing a temporary. In other words, -/// something like `x().f` is translated into roughly the equivalent of -/// -/// { tmp = x(); tmp.f } -pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - name: &str) - -> DatumBlock<'blk, 'tcx, Lvalue> { - let mut bcx = bcx; - let datum = unpack_datum!(bcx, trans(bcx, expr)); - return datum.to_lvalue_datum(bcx, name, expr.id); -} - -/// A version of `trans` that ignores adjustments. You almost certainly do not want to call this -/// directly. -fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - - debug!("trans_unadjusted(expr={:?})", expr); - let _indenter = indenter(); - - expr.debug_loc().apply(bcx.fcx); - - return match expr_kind(bcx.tcx(), expr) { - ExprKind::Lvalue | ExprKind::RvalueDatum => { - let datum = unpack_datum!(bcx, { - trans_datum_unadjusted(bcx, expr) - }); - - DatumBlock {bcx: bcx, datum: datum} - } - - ExprKind::RvalueStmt => { - bcx = trans_rvalue_stmt_unadjusted(bcx, expr); - nil(bcx, expr_ty(bcx, expr)) - } - - ExprKind::RvalueDps => { - let ty = expr_ty(bcx, expr); - if type_is_zero_size(bcx.ccx(), ty) { - bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore); - nil(bcx, ty) - } else { - let scratch = rvalue_scratch_datum(bcx, ty, ""); - bcx = trans_rvalue_dps_unadjusted( - bcx, expr, SaveIn(scratch.val)); - - // Note: this is not obviously a good idea. It causes - // immediate values to be loaded immediately after a - // return from a call or other similar expression, - // which in turn leads to alloca's having shorter - // lifetimes and hence larger stack frames. However, - // in turn it can lead to more register pressure. - // Still, in practice it seems to increase - // performance, since we have fewer problems with - // morestack churn. - let scratch = unpack_datum!( - bcx, scratch.to_appropriate_datum(bcx)); - - DatumBlock::new(bcx, scratch.to_expr_datum()) - } - } - }; - - fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let llval = C_undef(type_of::type_of(bcx.ccx(), ty)); - let datum = immediate_rvalue(llval, ty); - DatumBlock::new(bcx, datum.to_expr_datum()) - } -} - -fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let fcx = bcx.fcx; - let _icx = push_ctxt("trans_datum_unadjusted"); - - match expr.node { - hir::ExprType(ref e, _) => { - trans(bcx, &e) - } - hir::ExprPath(..) => { - let var = trans_var(bcx, bcx.tcx().expect_def(expr.id)); - DatumBlock::new(bcx, var.to_expr_datum()) - } - hir::ExprField(ref base, name) => { - trans_rec_field(bcx, &base, name.node) - } - hir::ExprTupField(ref base, idx) => { - trans_rec_tup_field(bcx, &base, idx.node) - } - hir::ExprIndex(ref base, ref idx) => { - trans_index(bcx, expr, &base, &idx, MethodCall::expr(expr.id)) - } - hir::ExprBox(ref contents) => { - // Special case for `Box` - let box_ty = expr_ty(bcx, expr); - let contents_ty = expr_ty(bcx, &contents); - match box_ty.sty { - ty::TyBox(..) => { - trans_uniq_expr(bcx, expr, box_ty, &contents, contents_ty) - } - _ => span_bug!(expr.span, - "expected unique box") - } - - } - hir::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, &lit), - hir::ExprBinary(op, ref lhs, ref rhs) => { - trans_binary(bcx, expr, op, &lhs, &rhs) - } - hir::ExprUnary(op, ref x) => { - trans_unary(bcx, expr, op, &x) - } - hir::ExprAddrOf(_, ref x) => { - match x.node { - hir::ExprRepeat(..) | hir::ExprVec(..) => { - // Special case for slices. - let cleanup_debug_loc = - debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), - x.id, - x.span, - false); - fcx.push_ast_cleanup_scope(cleanup_debug_loc); - let datum = unpack_datum!( - bcx, tvec::trans_slice_vec(bcx, expr, &x)); - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id); - DatumBlock::new(bcx, datum) - } - _ => { - trans_addr_of(bcx, expr, &x) - } - } - } - hir::ExprCast(ref val, _) => { - // Datum output mode means this is a scalar cast: - trans_imm_cast(bcx, &val, expr.id) - } - _ => { - span_bug!( - expr.span, - "trans_rvalue_datum_unadjusted reached \ - fall-through case: {:?}", - expr.node); - } - } -} - -fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - base: &hir::Expr, - get_idx: F) - -> DatumBlock<'blk, 'tcx, Expr> where - F: FnOnce(TyCtxt<'blk, 'tcx, 'tcx>, &VariantInfo<'tcx>) -> usize, -{ - let mut bcx = bcx; - let _icx = push_ctxt("trans_rec_field"); - - let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field")); - let bare_ty = base_datum.ty; - let repr = adt::represent_type(bcx.ccx(), bare_ty); - let vinfo = VariantInfo::from_ty(bcx.tcx(), bare_ty, None); - - let ix = get_idx(bcx.tcx(), &vinfo); - let d = base_datum.get_element( - bcx, - vinfo.fields[ix].1, - |srcval| { - adt::trans_field_ptr(bcx, &repr, srcval, vinfo.discr, ix) - }); - - if type_is_sized(bcx.tcx(), d.ty) { - DatumBlock { datum: d.to_expr_datum(), bcx: bcx } - } else { - let scratch = rvalue_scratch_datum(bcx, d.ty, ""); - Store(bcx, d.val, get_dataptr(bcx, scratch.val)); - let info = Load(bcx, get_meta(bcx, base_datum.val)); - Store(bcx, info, get_meta(bcx, scratch.val)); - - // Always generate an lvalue datum, because this pointer doesn't own - // the data and cleanup is scheduled elsewhere. - DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind))) - } -} - -/// Translates `base.field`. -fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - base: &hir::Expr, - field: ast::Name) - -> DatumBlock<'blk, 'tcx, Expr> { - trans_field(bcx, base, |_, vinfo| vinfo.field_index(field)) -} - -/// Translates `base.`. -fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - base: &hir::Expr, - idx: usize) - -> DatumBlock<'blk, 'tcx, Expr> { - trans_field(bcx, base, |_, _| idx) -} - -fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - index_expr: &hir::Expr, - base: &hir::Expr, - idx: &hir::Expr, - method_call: MethodCall) - -> DatumBlock<'blk, 'tcx, Expr> { - //! Translates `base[idx]`. - - let _icx = push_ctxt("trans_index"); - let ccx = bcx.ccx(); - let mut bcx = bcx; - - let index_expr_debug_loc = index_expr.debug_loc(); - - // Check for overloaded index. - let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned(); - let elt_datum = match method { - Some(method) => { - let method_ty = monomorphize_type(bcx, method.ty); - - let base_datum = unpack_datum!(bcx, trans(bcx, base)); - - // Translate index expression. - let ix_datum = unpack_datum!(bcx, trans(bcx, idx)); - - let ref_ty = // invoked methods have LB regions instantiated: - bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) { - None => { - span_bug!(index_expr.span, - "index method didn't return a \ - dereferenceable type?!") - } - Some(elt_tm) => elt_tm.ty, - }; - - // Overloaded. Invoke the index() method, which basically - // yields a `&T` pointer. We can then proceed down the - // normal path (below) to dereference that `&T`. - let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt"); - - bcx = Callee::method(bcx, method) - .call(bcx, index_expr_debug_loc, - ArgOverloadedOp(base_datum, Some(ix_datum)), - Some(SaveIn(scratch.val))).bcx; - - let datum = scratch.to_expr_datum(); - let lval = Lvalue::new("expr::trans_index overload"); - if type_is_sized(bcx.tcx(), elt_ty) { - Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr(lval)) - } else { - Datum::new(datum.val, elt_ty, LvalueExpr(lval)) - } - } - None => { - let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, - base, - "index")); - - // Translate index expression and cast to a suitable LLVM integer. - // Rust is less strict than LLVM in this regard. - let ix_datum = unpack_datum!(bcx, trans(bcx, idx)); - let ix_val = ix_datum.to_llscalarish(bcx); - let ix_size = machine::llbitsize_of_real(bcx.ccx(), - val_ty(ix_val)); - let int_size = machine::llbitsize_of_real(bcx.ccx(), - ccx.int_type()); - let ix_val = { - if ix_size < int_size { - if expr_ty(bcx, idx).is_signed() { - SExt(bcx, ix_val, ccx.int_type()) - } else { ZExt(bcx, ix_val, ccx.int_type()) } - } else if ix_size > int_size { - Trunc(bcx, ix_val, ccx.int_type()) - } else { - ix_val - } - }; - - let unit_ty = base_datum.ty.sequence_element_type(bcx.tcx()); - - let (base, len) = base_datum.get_vec_base_and_len(bcx); - - debug!("trans_index: base {:?}", Value(base)); - debug!("trans_index: len {:?}", Value(len)); - - let bounds_check = ICmp(bcx, - llvm::IntUGE, - ix_val, - len, - index_expr_debug_loc); - let expect = ccx.get_intrinsic(&("llvm.expect.i1")); - let expected = Call(bcx, - expect, - &[bounds_check, C_bool(ccx, false)], - index_expr_debug_loc); - bcx = with_cond(bcx, expected, |bcx| { - controlflow::trans_fail_bounds_check(bcx, - expr_info(index_expr), - ix_val, - len) - }); - let elt = InBoundsGEP(bcx, base, &[ix_val]); - let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to()); - let lval = Lvalue::new("expr::trans_index fallback"); - Datum::new(elt, unit_ty, LvalueExpr(lval)) - } - }; - - DatumBlock::new(bcx, elt_datum) -} - -/// Translates a reference to a variable. -pub fn trans_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: Def) - -> Datum<'tcx, Lvalue> { - - match def { - Def::Static(did, _) => consts::get_static(bcx.ccx(), did), - Def::Upvar(_, nid, _, _) => { - // Can't move upvars, so this is never a ZeroMemLastUse. - let local_ty = node_id_type(bcx, nid); - let lval = Lvalue::new_with_hint("expr::trans_var (upvar)", - bcx, nid, HintKind::ZeroAndMaintain); - match bcx.fcx.llupvars.borrow().get(&nid) { - Some(&val) => Datum::new(val, local_ty, lval), - None => { - bug!("trans_var: no llval for upvar {} found", nid); - } - } - } - Def::Local(_, nid) => { - let datum = match bcx.fcx.lllocals.borrow().get(&nid) { - Some(&v) => v, - None => { - bug!("trans_var: no datum for local/arg {} found", nid); - } - }; - debug!("take_local(nid={}, v={:?}, ty={})", - nid, Value(datum.val), datum.ty); - datum - } - _ => bug!("{:?} should not reach expr::trans_var", def) - } -} - -fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr) - -> Block<'blk, 'tcx> { - let mut bcx = bcx; - let _icx = push_ctxt("trans_rvalue_stmt"); - - if bcx.unreachable.get() { - return bcx; - } - - expr.debug_loc().apply(bcx.fcx); - - match expr.node { - hir::ExprBreak(label_opt) => { - controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node)) - } - hir::ExprType(ref e, _) => { - trans_into(bcx, &e, Ignore) - } - hir::ExprAgain(label_opt) => { - controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node)) - } - hir::ExprRet(ref ex) => { - // Check to see if the return expression itself is reachable. - // This can occur when the inner expression contains a return - let reachable = if let Some(ref cfg) = bcx.fcx.cfg { - cfg.node_is_reachable(expr.id) - } else { - true - }; - - if reachable { - controlflow::trans_ret(bcx, expr, ex.as_ref().map(|e| &**e)) - } else { - // If it's not reachable, just translate the inner expression - // directly. This avoids having to manage a return slot when - // it won't actually be used anyway. - if let &Some(ref x) = ex { - bcx = trans_into(bcx, &x, Ignore); - } - // Mark the end of the block as unreachable. Once we get to - // a return expression, there's no more we should be doing - // after this. - Unreachable(bcx); - bcx - } - } - hir::ExprWhile(ref cond, ref body, _) => { - controlflow::trans_while(bcx, expr, &cond, &body) - } - hir::ExprLoop(ref body, _) => { - controlflow::trans_loop(bcx, expr, &body) - } - hir::ExprAssign(ref dst, ref src) => { - let src_datum = unpack_datum!(bcx, trans(bcx, &src)); - let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &dst, "assign")); - - if bcx.fcx.type_needs_drop(dst_datum.ty) { - // If there are destructors involved, make sure we - // are copying from an rvalue, since that cannot possible - // alias an lvalue. We are concerned about code like: - // - // a = a - // - // but also - // - // a = a.b - // - // where e.g. a : Option and a.b : - // Option. In that case, freeing `a` before the - // assignment may also free `a.b`! - // - // We could avoid this intermediary with some analysis - // to determine whether `dst` may possibly own `src`. - expr.debug_loc().apply(bcx.fcx); - let src_datum = unpack_datum!( - bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign")); - let opt_hint_datum = dst_datum.kind.drop_flag_info.hint_datum(bcx); - let opt_hint_val = opt_hint_datum.map(|d|d.to_value()); - - // 1. Drop the data at the destination, passing the - // drop-hint in case the lvalue has already been - // dropped or moved. - bcx = glue::drop_ty_core(bcx, - dst_datum.val, - dst_datum.ty, - expr.debug_loc(), - false, - opt_hint_val); - - // 2. We are overwriting the destination; ensure that - // its drop-hint (if any) says "initialized." - if let Some(hint_val) = opt_hint_val { - let hint_llval = hint_val.value(); - let drop_needed = C_u8(bcx.fcx.ccx, adt::DTOR_NEEDED_HINT); - Store(bcx, drop_needed, hint_llval); - } - src_datum.store_to(bcx, dst_datum.val) - } else { - src_datum.store_to(bcx, dst_datum.val) - } - } - hir::ExprAssignOp(op, ref dst, ref src) => { - let method = bcx.tcx().tables - .borrow() - .method_map - .get(&MethodCall::expr(expr.id)).cloned(); - - if let Some(method) = method { - let dst = unpack_datum!(bcx, trans(bcx, &dst)); - let src_datum = unpack_datum!(bcx, trans(bcx, &src)); - - Callee::method(bcx, method) - .call(bcx, expr.debug_loc(), - ArgOverloadedOp(dst, Some(src_datum)), None).bcx - } else { - trans_assign_op(bcx, expr, op, &dst, &src) - } - } - hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => { - let outputs = outputs.iter().map(|output| { - let out_datum = unpack_datum!(bcx, trans(bcx, output)); - unpack_datum!(bcx, out_datum.to_lvalue_datum(bcx, "out", expr.id)) - }).collect(); - let inputs = inputs.iter().map(|input| { - let input = unpack_datum!(bcx, trans(bcx, input)); - let input = unpack_datum!(bcx, input.to_rvalue_datum(bcx, "in")); - input.to_llscalarish(bcx) - }).collect(); - asm::trans_inline_asm(bcx, a, outputs, inputs); - bcx - } - _ => { - span_bug!( - expr.span, - "trans_rvalue_stmt_unadjusted reached \ - fall-through case: {:?}", - expr.node); - } - } -} - -fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - dest: Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_rvalue_dps_unadjusted"); - let mut bcx = bcx; - - expr.debug_loc().apply(bcx.fcx); - - // Entry into the method table if this is an overloaded call/op. - let method_call = MethodCall::expr(expr.id); - - match expr.node { - hir::ExprType(ref e, _) => { - trans_into(bcx, &e, dest) - } - hir::ExprPath(..) => { - trans_def_dps_unadjusted(bcx, expr, bcx.tcx().expect_def(expr.id), dest) - } - hir::ExprIf(ref cond, ref thn, ref els) => { - controlflow::trans_if(bcx, expr.id, &cond, &thn, els.as_ref().map(|e| &**e), dest) - } - hir::ExprMatch(ref discr, ref arms, _) => { - _match::trans_match(bcx, expr, &discr, &arms[..], dest) - } - hir::ExprBlock(ref blk) => { - controlflow::trans_block(bcx, &blk, dest) - } - hir::ExprStruct(_, ref fields, ref base) => { - trans_struct(bcx, - &fields[..], - base.as_ref().map(|e| &**e), - expr.span, - expr.id, - node_id_type(bcx, expr.id), - dest) - } - hir::ExprTup(ref args) => { - let numbered_fields: Vec<(usize, &hir::Expr)> = - args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect(); - trans_adt(bcx, - expr_ty(bcx, expr), - Disr(0), - &numbered_fields[..], - None, - dest, - expr.debug_loc()) - } - hir::ExprLit(ref lit) => { - match lit.node { - ast::LitKind::Str(ref s, _) => { - tvec::trans_lit_str(bcx, expr, (*s).clone(), dest) - } - _ => { - span_bug!(expr.span, - "trans_rvalue_dps_unadjusted shouldn't be \ - translating this type of literal") - } - } - } - hir::ExprVec(..) | hir::ExprRepeat(..) => { - tvec::trans_fixed_vstore(bcx, expr, dest) - } - hir::ExprClosure(_, ref decl, ref body, _) => { - let dest = match dest { - SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest), - Ignore => closure::Dest::Ignore(bcx.ccx()) - }; - - // NB. To get the id of the closure, we don't use - // `local_def_id(id)`, but rather we extract the closure - // def-id from the expr's type. This is because this may - // be an inlined expression from another crate, and we - // want to get the ORIGINAL closure def-id, since that is - // the key we need to find the closure-kind and - // closure-type etc. - let (def_id, substs) = match expr_ty(bcx, expr).sty { - ty::TyClosure(def_id, substs) => (def_id, substs), - ref t => - span_bug!( - expr.span, - "closure expr without closure type: {:?}", t), - }; - - closure::trans_closure_expr(dest, - decl, - body, - expr.id, - def_id, - substs).unwrap_or(bcx) - } - hir::ExprCall(ref f, ref args) => { - let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned(); - let (callee, args) = if let Some(method) = method { - let mut all_args = vec![&**f]; - all_args.extend(args.iter().map(|e| &**e)); - - (Callee::method(bcx, method), ArgOverloadedCall(all_args)) - } else { - let f = unpack_datum!(bcx, trans(bcx, f)); - (match f.ty.sty { - ty::TyFnDef(def_id, substs, _) => { - Callee::def(bcx.ccx(), def_id, substs) - } - ty::TyFnPtr(_) => { - let f = unpack_datum!(bcx, - f.to_rvalue_datum(bcx, "callee")); - Callee::ptr(f) - } - _ => { - span_bug!(expr.span, - "type of callee is not a fn: {}", f.ty); - } - }, ArgExprs(&args)) - }; - callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx - } - hir::ExprMethodCall(_, _, ref args) => { - Callee::method_call(bcx, method_call) - .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx - } - hir::ExprBinary(op, ref lhs, ref rhs_expr) => { - // if not overloaded, would be RvalueDatumExpr - let lhs = unpack_datum!(bcx, trans(bcx, &lhs)); - let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr)); - if !op.node.is_by_value() { - rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr)); - } - - Callee::method_call(bcx, method_call) - .call(bcx, expr.debug_loc(), - ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx - } - hir::ExprUnary(_, ref subexpr) => { - // if not overloaded, would be RvalueDatumExpr - let arg = unpack_datum!(bcx, trans(bcx, &subexpr)); - - Callee::method_call(bcx, method_call) - .call(bcx, expr.debug_loc(), - ArgOverloadedOp(arg, None), Some(dest)).bcx - } - hir::ExprCast(..) => { - // Trait casts used to come this way, now they should be coercions. - span_bug!(expr.span, "DPS expr_cast (residual trait cast?)") - } - hir::ExprAssignOp(op, _, _) => { - span_bug!( - expr.span, - "augmented assignment `{}=` should always be a rvalue_stmt", - op.node.as_str()) - } - _ => { - span_bug!( - expr.span, - "trans_rvalue_dps_unadjusted reached fall-through \ - case: {:?}", - expr.node); - } - } -} - -fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - ref_expr: &hir::Expr, - def: Def, - dest: Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_def_dps_unadjusted"); - - let lldest = match dest { - SaveIn(lldest) => lldest, - Ignore => { return bcx; } - }; - - let ty = expr_ty(bcx, ref_expr); - if let ty::TyFnDef(..) = ty.sty { - // Zero-sized function or ctor. - return bcx; - } - - match def { - Def::Variant(tid, vid) => { - let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); - // Nullary variant. - let ty = expr_ty(bcx, ref_expr); - let repr = adt::represent_type(bcx.ccx(), ty); - adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val)); - bcx - } - Def::Struct(..) => { - match ty.sty { - ty::TyStruct(def, _) if def.has_dtor() => { - let repr = adt::represent_type(bcx.ccx(), ty); - adt::trans_set_discr(bcx, &repr, lldest, Disr(0)); - } - _ => {} - } - bcx - } - _ => { - span_bug!(ref_expr.span, - "Non-DPS def {:?} referened by {}", - def, bcx.node_id_to_string(ref_expr.id)); - } - } -} - -fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - fields: &[hir::Field], - base: Option<&hir::Expr>, - expr_span: syntax_pos::Span, - expr_id: ast::NodeId, - ty: Ty<'tcx>, - dest: Dest) -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_rec"); - - let tcx = bcx.tcx(); - let vinfo = VariantInfo::of_node(tcx, ty, expr_id); - - let mut need_base = vec![true; vinfo.fields.len()]; - - let numbered_fields = fields.iter().map(|field| { - let pos = vinfo.field_index(field.name.node); - need_base[pos] = false; - (pos, &*field.expr) - }).collect::>(); - - let optbase = match base { - Some(base_expr) => { - let mut leftovers = Vec::new(); - for (i, b) in need_base.iter().enumerate() { - if *b { - leftovers.push((i, vinfo.fields[i].1)); - } - } - Some(StructBaseInfo {expr: base_expr, - fields: leftovers }) - } - None => { - if need_base.iter().any(|b| *b) { - span_bug!(expr_span, "missing fields and no base expr") - } - None - } - }; - - trans_adt(bcx, - ty, - vinfo.discr, - &numbered_fields, - optbase, - dest, - DebugLoc::At(expr_id, expr_span)) -} - -/// Information that `trans_adt` needs in order to fill in the fields -/// of a struct copied from a base struct (e.g., from an expression -/// like `Foo { a: b, ..base }`. -/// -/// Note that `fields` may be empty; the base expression must always be -/// evaluated for side-effects. -pub struct StructBaseInfo<'a, 'tcx> { - /// The base expression; will be evaluated after all explicit fields. - expr: &'a hir::Expr, - /// The indices of fields to copy paired with their types. - fields: Vec<(usize, Ty<'tcx>)> -} - -/// Constructs an ADT instance: -/// -/// - `fields` should be a list of field indices paired with the -/// expression to store into that field. The initializers will be -/// evaluated in the order specified by `fields`. -/// -/// - `optbase` contains information on the base struct (if any) from -/// which remaining fields are copied; see comments on `StructBaseInfo`. -pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - ty: Ty<'tcx>, - discr: Disr, - fields: &[(usize, &hir::Expr)], - optbase: Option>, - dest: Dest, - debug_location: DebugLoc) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_adt"); - let fcx = bcx.fcx; - let repr = adt::represent_type(bcx.ccx(), ty); - - debug_location.apply(bcx.fcx); - - // If we don't care about the result, just make a - // temporary stack slot - let addr = match dest { - SaveIn(pos) => pos, - Ignore => { - let llresult = alloc_ty(bcx, ty, "temp"); - call_lifetime_start(bcx, llresult); - llresult - } - }; - - debug!("trans_adt"); - - // This scope holds intermediates that must be cleaned should - // panic occur before the ADT as a whole is ready. - let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - - if ty.is_simd() { - // Issue 23112: The original logic appeared vulnerable to same - // order-of-eval bug. But, SIMD values are tuple-structs; - // i.e. functional record update (FRU) syntax is unavailable. - // - // To be safe, double-check that we did not get here via FRU. - assert!(optbase.is_none()); - - // This is the constructor of a SIMD type, such types are - // always primitive machine types and so do not have a - // destructor or require any clean-up. - let llty = type_of::type_of(bcx.ccx(), ty); - - // keep a vector as a register, and running through the field - // `insertelement`ing them directly into that register - // (i.e. avoid GEPi and `store`s to an alloca) . - let mut vec_val = C_undef(llty); - - for &(i, ref e) in fields { - let block_datum = trans(bcx, &e); - bcx = block_datum.bcx; - let position = C_uint(bcx.ccx(), i); - let value = block_datum.datum.to_llscalarish(bcx); - vec_val = InsertElement(bcx, vec_val, value, position); - } - Store(bcx, vec_val, addr); - } else if let Some(base) = optbase { - // Issue 23112: If there is a base, then order-of-eval - // requires field expressions eval'ed before base expression. - - // First, trans field expressions to temporary scratch values. - let scratch_vals: Vec<_> = fields.iter().map(|&(i, ref e)| { - let datum = unpack_datum!(bcx, trans(bcx, &e)); - (i, datum) - }).collect(); - - debug_location.apply(bcx.fcx); - - // Second, trans the base to the dest. - assert_eq!(discr, Disr(0)); - - let addr = adt::MaybeSizedValue::sized(addr); - match expr_kind(bcx.tcx(), &base.expr) { - ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => { - bcx = trans_into(bcx, &base.expr, SaveIn(addr.value)); - }, - ExprKind::RvalueStmt => { - bug!("unexpected expr kind for struct base expr") - } - _ => { - let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &base.expr, "base")); - for &(i, t) in &base.fields { - let datum = base_datum.get_element( - bcx, t, |srcval| adt::trans_field_ptr(bcx, &repr, srcval, discr, i)); - assert!(type_is_sized(bcx.tcx(), datum.ty)); - let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i); - bcx = datum.store_to(bcx, dest); - } - } - } - - // Finally, move scratch field values into actual field locations - for (i, datum) in scratch_vals { - let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i); - bcx = datum.store_to(bcx, dest); - } - } else { - // No base means we can write all fields directly in place. - let addr = adt::MaybeSizedValue::sized(addr); - for &(i, ref e) in fields { - let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i); - let e_ty = expr_ty_adjusted(bcx, &e); - bcx = trans_into(bcx, &e, SaveIn(dest)); - let scope = cleanup::CustomScope(custom_cleanup_scope); - fcx.schedule_lifetime_end(scope, dest); - // FIXME: nonzeroing move should generalize to fields - fcx.schedule_drop_mem(scope, dest, e_ty, None); - } - } - - adt::trans_set_discr(bcx, &repr, addr, discr); - - fcx.pop_custom_cleanup_scope(custom_cleanup_scope); - - // If we don't care about the result drop the temporary we made - match dest { - SaveIn(_) => bcx, - Ignore => { - bcx = glue::drop_ty(bcx, addr, ty, debug_location); - base::call_lifetime_end(bcx, addr); - bcx - } - } -} - - -fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - lit: &ast::Lit) - -> DatumBlock<'blk, 'tcx, Expr> { - // must not be a string constant, that is a RvalueDpsExpr - let _icx = push_ctxt("trans_immediate_lit"); - let ty = expr_ty(bcx, expr); - let v = consts::const_lit(bcx.ccx(), expr, lit); - immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock() -} - -fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - op: hir::UnOp, - sub_expr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let ccx = bcx.ccx(); - let mut bcx = bcx; - let _icx = push_ctxt("trans_unary_datum"); - - let method_call = MethodCall::expr(expr.id); - - // The only overloaded operator that is translated to a datum - // is an overloaded deref, since it is always yields a `&T`. - // Otherwise, we should be in the RvalueDpsExpr path. - assert!(op == hir::UnDeref || !ccx.tcx().is_method_call(expr.id)); - - let un_ty = expr_ty(bcx, expr); - - let debug_loc = expr.debug_loc(); - - match op { - hir::UnNot => { - let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); - let llresult = Not(bcx, datum.to_llscalarish(bcx), debug_loc); - immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock() - } - hir::UnNeg => { - let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); - let val = datum.to_llscalarish(bcx); - let (bcx, llneg) = { - if un_ty.is_fp() { - let result = FNeg(bcx, val, debug_loc); - (bcx, result) - } else { - let is_signed = un_ty.is_signed(); - let result = Neg(bcx, val, debug_loc); - let bcx = if bcx.ccx().check_overflow() && is_signed { - let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty); - let is_min = ICmp(bcx, llvm::IntEQ, val, - C_integral(llty, min, true), debug_loc); - with_cond(bcx, is_min, |bcx| { - let msg = InternedString::new( - "attempt to negate with overflow"); - controlflow::trans_fail(bcx, expr_info(expr), msg) - }) - } else { - bcx - }; - (bcx, result) - } - }; - immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock() - } - hir::UnDeref => { - let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); - deref_once(bcx, expr, datum, method_call) - } - } -} - -fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - box_expr: &hir::Expr, - box_ty: Ty<'tcx>, - contents: &hir::Expr, - contents_ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let _icx = push_ctxt("trans_uniq_expr"); - let fcx = bcx.fcx; - assert!(type_is_sized(bcx.tcx(), contents_ty)); - let llty = type_of::type_of(bcx.ccx(), contents_ty); - let size = llsize_of(bcx.ccx(), llty); - let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty)); - let llty_ptr = llty.ptr_to(); - let Result { bcx, val } = malloc_raw_dyn(bcx, - llty_ptr, - box_ty, - size, - align, - box_expr.debug_loc()); - // Unique boxes do not allocate for zero-size types. The standard library - // may assume that `free` is never called on the pointer returned for - // `Box`. - let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 { - trans_into(bcx, contents, SaveIn(val)) - } else { - let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope), - val, cleanup::HeapExchange, contents_ty); - let bcx = trans_into(bcx, contents, SaveIn(val)); - fcx.pop_custom_cleanup_scope(custom_cleanup_scope); - bcx - }; - immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() -} - -fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - subexpr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let _icx = push_ctxt("trans_addr_of"); - let mut bcx = bcx; - let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of")); - let ty = expr_ty(bcx, expr); - if !type_is_sized(bcx.tcx(), sub_datum.ty) { - // Always generate an lvalue datum, because this pointer doesn't own - // the data and cleanup is scheduled elsewhere. - DatumBlock::new(bcx, Datum::new(sub_datum.val, ty, LvalueExpr(sub_datum.kind))) - } else { - // Sized value, ref to a thin pointer - immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock() - } -} - -fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - binop_expr: &hir::Expr, - binop_ty: Ty<'tcx>, - op: hir::BinOp, - lhs: Datum<'tcx, Rvalue>, - rhs: Datum<'tcx, Rvalue>) - -> DatumBlock<'blk, 'tcx, Expr> -{ - let _icx = push_ctxt("trans_scalar_binop"); - - let lhs_t = lhs.ty; - assert!(!lhs_t.is_simd()); - let is_float = lhs_t.is_fp(); - let is_signed = lhs_t.is_signed(); - let info = expr_info(binop_expr); - - let binop_debug_loc = binop_expr.debug_loc(); - - let mut bcx = bcx; - let lhs = lhs.to_llscalarish(bcx); - let rhs = rhs.to_llscalarish(bcx); - let val = match op.node { - hir::BiAdd => { - if is_float { - FAdd(bcx, lhs, rhs, binop_debug_loc) - } else { - let (newbcx, res) = with_overflow_check( - bcx, OverflowOp::Add, info, lhs_t, lhs, rhs, binop_debug_loc); - bcx = newbcx; - res - } - } - hir::BiSub => { - if is_float { - FSub(bcx, lhs, rhs, binop_debug_loc) - } else { - let (newbcx, res) = with_overflow_check( - bcx, OverflowOp::Sub, info, lhs_t, lhs, rhs, binop_debug_loc); - bcx = newbcx; - res - } - } - hir::BiMul => { - if is_float { - FMul(bcx, lhs, rhs, binop_debug_loc) - } else { - let (newbcx, res) = with_overflow_check( - bcx, OverflowOp::Mul, info, lhs_t, lhs, rhs, binop_debug_loc); - bcx = newbcx; - res - } - } - hir::BiDiv => { - if is_float { - FDiv(bcx, lhs, rhs, binop_debug_loc) - } else { - // Only zero-check integers; fp /0 is NaN - bcx = base::fail_if_zero_or_overflows(bcx, - expr_info(binop_expr), - op, - lhs, - rhs, - lhs_t); - if is_signed { - SDiv(bcx, lhs, rhs, binop_debug_loc) - } else { - UDiv(bcx, lhs, rhs, binop_debug_loc) - } - } - } - hir::BiRem => { - if is_float { - FRem(bcx, lhs, rhs, binop_debug_loc) - } else { - // Only zero-check integers; fp %0 is NaN - bcx = base::fail_if_zero_or_overflows(bcx, - expr_info(binop_expr), - op, lhs, rhs, lhs_t); - if is_signed { - SRem(bcx, lhs, rhs, binop_debug_loc) - } else { - URem(bcx, lhs, rhs, binop_debug_loc) - } - } - } - hir::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc), - hir::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc), - hir::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc), - hir::BiShl => { - let (newbcx, res) = with_overflow_check( - bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc); - bcx = newbcx; - res - } - hir::BiShr => { - let (newbcx, res) = with_overflow_check( - bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc); - bcx = newbcx; - res - } - hir::BiEq | hir::BiNe | hir::BiLt | hir::BiGe | hir::BiLe | hir::BiGt => { - base::compare_scalar_types(bcx, lhs, rhs, lhs_t, op.node, binop_debug_loc) - } - _ => { - span_bug!(binop_expr.span, "unexpected binop"); - } - }; - - immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock() -} - -// refinement types would obviate the need for this -#[derive(Clone, Copy)] -enum lazy_binop_ty { - lazy_and, - lazy_or, -} - - -fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - binop_expr: &hir::Expr, - op: lazy_binop_ty, - a: &hir::Expr, - b: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let _icx = push_ctxt("trans_lazy_binop"); - let binop_ty = expr_ty(bcx, binop_expr); - let fcx = bcx.fcx; - - let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a); - let lhs = lhs.to_llscalarish(past_lhs); - - if past_lhs.unreachable.get() { - return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock(); - } - - // If the rhs can never be reached, don't generate code for it. - if let Some(cond_val) = const_to_opt_uint(lhs) { - match (cond_val, op) { - (0, lazy_and) | - (1, lazy_or) => { - return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock(); - } - _ => { /* continue */ } - } - } - - let join = fcx.new_id_block("join", binop_expr.id); - let before_rhs = fcx.new_id_block("before_rhs", b.id); - - match op { - lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb, DebugLoc::None), - lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb, DebugLoc::None) - } - - let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b); - let rhs = rhs.to_llscalarish(past_rhs); - - if past_rhs.unreachable.get() { - return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock(); - } - - Br(past_rhs, join.llbb, DebugLoc::None); - let phi = Phi(join, Type::i1(bcx.ccx()), &[lhs, rhs], - &[past_lhs.llbb, past_rhs.llbb]); - - return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock(); -} - -fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - op: hir::BinOp, - lhs: &hir::Expr, - rhs: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let _icx = push_ctxt("trans_binary"); - let ccx = bcx.ccx(); - - // if overloaded, would be RvalueDpsExpr - assert!(!ccx.tcx().is_method_call(expr.id)); - - match op.node { - hir::BiAnd => { - trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs) - } - hir::BiOr => { - trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs) - } - _ => { - let mut bcx = bcx; - let binop_ty = expr_ty(bcx, expr); - - let lhs = unpack_datum!(bcx, trans(bcx, lhs)); - let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs")); - debug!("trans_binary (expr {}): lhs={:?}", expr.id, lhs); - let rhs = unpack_datum!(bcx, trans(bcx, rhs)); - let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs")); - debug!("trans_binary (expr {}): rhs={:?}", expr.id, rhs); - - if type_is_fat_ptr(ccx.tcx(), lhs.ty) { - assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty), - "built-in binary operators on fat pointers are homogeneous"); - assert_eq!(binop_ty, bcx.tcx().types.bool); - let val = base::compare_scalar_types( - bcx, - lhs.val, - rhs.val, - lhs.ty, - op.node, - expr.debug_loc()); - immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock() - } else { - assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty), - "built-in binary operators on fat pointers are homogeneous"); - trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs) - } - } - } -} - -pub fn cast_is_noop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - expr: &hir::Expr, - t_in: Ty<'tcx>, - t_out: Ty<'tcx>) - -> bool { - if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) { - return true; - } - - match (t_in.builtin_deref(true, ty::NoPreference), - t_out.builtin_deref(true, ty::NoPreference)) { - (Some(ty::TypeAndMut{ ty: t_in, .. }), Some(ty::TypeAndMut{ ty: t_out, .. })) => { - t_in == t_out - } - _ => { - // This condition isn't redundant with the check for CoercionCast: - // different types can be substituted into the same type, and - // == equality can be overconservative if there are regions. - t_in == t_out - } - } -} - -fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - id: ast::NodeId) - -> DatumBlock<'blk, 'tcx, Expr> -{ - use rustc::ty::cast::CastTy::*; - use rustc::ty::cast::IntTy::*; - - fn int_cast(bcx: Block, - lldsttype: Type, - llsrctype: Type, - llsrc: ValueRef, - signed: bool) - -> ValueRef - { - let _icx = push_ctxt("int_cast"); - let srcsz = llsrctype.int_width(); - let dstsz = lldsttype.int_width(); - return if dstsz == srcsz { - BitCast(bcx, llsrc, lldsttype) - } else if srcsz > dstsz { - TruncOrBitCast(bcx, llsrc, lldsttype) - } else if signed { - SExtOrBitCast(bcx, llsrc, lldsttype) - } else { - ZExtOrBitCast(bcx, llsrc, lldsttype) - } - } - - fn float_cast(bcx: Block, - lldsttype: Type, - llsrctype: Type, - llsrc: ValueRef) - -> ValueRef - { - let _icx = push_ctxt("float_cast"); - let srcsz = llsrctype.float_width(); - let dstsz = lldsttype.float_width(); - return if dstsz > srcsz { - FPExt(bcx, llsrc, lldsttype) - } else if srcsz > dstsz { - FPTrunc(bcx, llsrc, lldsttype) - } else { llsrc }; - } - - let _icx = push_ctxt("trans_cast"); - let mut bcx = bcx; - let ccx = bcx.ccx(); - - let t_in = expr_ty_adjusted(bcx, expr); - let t_out = node_id_type(bcx, id); - - debug!("trans_cast({:?} as {:?})", t_in, t_out); - let mut ll_t_in = type_of::immediate_type_of(ccx, t_in); - let ll_t_out = type_of::immediate_type_of(ccx, t_out); - // Convert the value to be cast into a ValueRef, either by-ref or - // by-value as appropriate given its type: - let mut datum = unpack_datum!(bcx, trans(bcx, expr)); - - let datum_ty = monomorphize_type(bcx, datum.ty); - - if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) { - datum.ty = t_out; - return DatumBlock::new(bcx, datum); - } - - if type_is_fat_ptr(bcx.tcx(), t_in) { - assert!(datum.kind.is_by_ref()); - if type_is_fat_ptr(bcx.tcx(), t_out) { - return DatumBlock::new(bcx, Datum::new( - PointerCast(bcx, datum.val, ll_t_out.ptr_to()), - t_out, - Rvalue::new(ByRef) - )).to_expr_datumblock(); - } else { - // Return the address - return immediate_rvalue_bcx(bcx, - PointerCast(bcx, - Load(bcx, get_dataptr(bcx, datum.val)), - ll_t_out), - t_out).to_expr_datumblock(); - } - } - - let r_t_in = CastTy::from_ty(t_in).expect("bad input type for cast"); - let r_t_out = CastTy::from_ty(t_out).expect("bad output type for cast"); - - let (llexpr, signed) = if let Int(CEnum) = r_t_in { - let repr = adt::represent_type(ccx, t_in); - let datum = unpack_datum!( - bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id)); - let llexpr_ptr = datum.to_llref(); - let discr = adt::trans_get_discr(bcx, &repr, llexpr_ptr, - Some(Type::i64(ccx)), true); - ll_t_in = val_ty(discr); - (discr, adt::is_discr_signed(&repr)) - } else { - (datum.to_llscalarish(bcx), t_in.is_signed()) - }; - - let newval = match (r_t_in, r_t_out) { - (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => { - PointerCast(bcx, llexpr, ll_t_out) - } - (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out), - (Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out), - - (Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed), - (Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr), - (Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out), - (Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out), - (Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out), - (Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out), - - _ => span_bug!(expr.span, - "translating unsupported cast: \ - {:?} -> {:?}", - t_in, - t_out) - }; - return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock(); -} - -fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - op: hir::BinOp, - dst: &hir::Expr, - src: &hir::Expr) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_assign_op"); - let mut bcx = bcx; - - debug!("trans_assign_op(expr={:?})", expr); - - // User-defined operator methods cannot be used with `+=` etc right now - assert!(!bcx.tcx().is_method_call(expr.id)); - - // Evaluate LHS (destination), which should be an lvalue - let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); - assert!(!bcx.fcx.type_needs_drop(dst.ty)); - let lhs = load_ty(bcx, dst.val, dst.ty); - let lhs = immediate_rvalue(lhs, dst.ty); - - // Evaluate RHS - FIXME(#28160) this sucks - let rhs = unpack_datum!(bcx, trans(bcx, &src)); - let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs")); - - // Perform computation and store the result - let result_datum = unpack_datum!( - bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs)); - return result_datum.store_to(bcx, dst.val); -} - -fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - datum: Datum<'tcx, Expr>, - expr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - - // Ensure cleanup of `datum` if not already scheduled and obtain - // a "by ref" pointer. - let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id)); - - // Compute final type. Note that we are loose with the region and - // mutability, since those things don't matter in trans. - let referent_ty = lv_datum.ty; - let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased), referent_ty); - - // Construct the resulting datum. The right datum to return here would be an Lvalue datum, - // because there is cleanup scheduled and the datum doesn't own the data, but for thin pointers - // we microoptimize it to be an Rvalue datum to avoid the extra alloca and level of - // indirection and for thin pointers, this has no ill effects. - let kind = if type_is_sized(bcx.tcx(), referent_ty) { - RvalueExpr(Rvalue::new(ByValue)) - } else { - LvalueExpr(lv_datum.kind) - }; - - // Get the pointer. - let llref = lv_datum.to_llref(); - DatumBlock::new(bcx, Datum::new(llref, ptr_ty, kind)) -} - -fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - datum: Datum<'tcx, Expr>, - times: usize) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let mut datum = datum; - for i in 0..times { - let method_call = MethodCall::autoderef(expr.id, i as u32); - datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call)); - } - DatumBlock { bcx: bcx, datum: datum } -} - -fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - datum: Datum<'tcx, Expr>, - method_call: MethodCall) - -> DatumBlock<'blk, 'tcx, Expr> { - let ccx = bcx.ccx(); - - debug!("deref_once(expr={:?}, datum={:?}, method_call={:?})", - expr, datum, method_call); - - let mut bcx = bcx; - - // Check for overloaded deref. - let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned(); - let datum = match method { - Some(method) => { - let method_ty = monomorphize_type(bcx, method.ty); - - // Overloaded. Invoke the deref() method, which basically - // converts from the `Smaht` pointer that we have into - // a `&T` pointer. We can then proceed down the normal - // path (below) to dereference that `&T`. - let datum = if method_call.autoderef == 0 { - datum - } else { - // Always perform an AutoPtr when applying an overloaded auto-deref - unpack_datum!(bcx, auto_ref(bcx, datum, expr)) - }; - - let ref_ty = // invoked methods have their LB regions instantiated - ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); - - bcx = Callee::method(bcx, method) - .call(bcx, expr.debug_loc(), - ArgOverloadedOp(datum, None), - Some(SaveIn(scratch.val))).bcx; - scratch.to_expr_datum() - } - None => { - // Not overloaded. We already have a pointer we know how to deref. - datum - } - }; - - let r = match datum.ty.sty { - ty::TyBox(content_ty) => { - // Make sure we have an lvalue datum here to get the - // proper cleanups scheduled - let datum = unpack_datum!( - bcx, datum.to_lvalue_datum(bcx, "deref", expr.id)); - - if type_is_sized(bcx.tcx(), content_ty) { - let ptr = load_ty(bcx, datum.val, datum.ty); - DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(datum.kind))) - } else { - // A fat pointer and a DST lvalue have the same representation - // just different types. Since there is no temporary for `*e` - // here (because it is unsized), we cannot emulate the sized - // object code path for running drop glue and free. Instead, - // we schedule cleanup for `e`, turning it into an lvalue. - - let lval = Lvalue::new("expr::deref_once ty_uniq"); - let datum = Datum::new(datum.val, content_ty, LvalueExpr(lval)); - DatumBlock::new(bcx, datum) - } - } - - ty::TyRawPtr(ty::TypeAndMut { ty: content_ty, .. }) | - ty::TyRef(_, ty::TypeAndMut { ty: content_ty, .. }) => { - let lval = Lvalue::new("expr::deref_once ptr"); - if type_is_sized(bcx.tcx(), content_ty) { - let ptr = datum.to_llscalarish(bcx); - - // Always generate an lvalue datum, even if datum.mode is - // an rvalue. This is because datum.mode is only an - // rvalue for non-owning pointers like &T or *T, in which - // case cleanup *is* scheduled elsewhere, by the true - // owner (or, in the case of *T, by the user). - DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(lval))) - } else { - // A fat pointer and a DST lvalue have the same representation - // just different types. - DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr(lval))) - } - } - - _ => { - span_bug!( - expr.span, - "deref invoked on expr of invalid type {:?}", - datum.ty); - } - }; - - debug!("deref_once(expr={}, method_call={:?}, result={:?})", - expr.id, method_call, r.datum); - - return r; -} - -#[derive(Debug)] -enum OverflowOp { - Add, - Sub, - Mul, - Shl, - Shr, -} - -impl OverflowOp { - fn codegen_strategy(&self) -> OverflowCodegen { - use self::OverflowCodegen::{ViaIntrinsic, ViaInputCheck}; - match *self { - OverflowOp::Add => ViaIntrinsic(OverflowOpViaIntrinsic::Add), - OverflowOp::Sub => ViaIntrinsic(OverflowOpViaIntrinsic::Sub), - OverflowOp::Mul => ViaIntrinsic(OverflowOpViaIntrinsic::Mul), - - OverflowOp::Shl => ViaInputCheck(OverflowOpViaInputCheck::Shl), - OverflowOp::Shr => ViaInputCheck(OverflowOpViaInputCheck::Shr), - } - } -} - -enum OverflowCodegen { - ViaIntrinsic(OverflowOpViaIntrinsic), - ViaInputCheck(OverflowOpViaInputCheck), -} - -enum OverflowOpViaInputCheck { Shl, Shr, } - -#[derive(Debug)] -enum OverflowOpViaIntrinsic { Add, Sub, Mul, } - -impl OverflowOpViaIntrinsic { - fn to_intrinsic<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, lhs_ty: Ty) -> ValueRef { - let name = self.to_intrinsic_name(bcx.tcx(), lhs_ty); - bcx.ccx().get_intrinsic(&name) - } - fn to_intrinsic_name(&self, tcx: TyCtxt, ty: Ty) -> &'static str { - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; - use rustc::ty::{TyInt, TyUint}; - - let new_sty = match ty.sty { - TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] { - "16" => TyInt(I16), - "32" => TyInt(I32), - "64" => TyInt(I64), - _ => bug!("unsupported target word size") - }, - TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] { - "16" => TyUint(U16), - "32" => TyUint(U32), - "64" => TyUint(U64), - _ => bug!("unsupported target word size") - }, - ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(), - _ => bug!("tried to get overflow intrinsic for {:?} applied to non-int type", - *self) - }; - - match *self { - OverflowOpViaIntrinsic::Add => match new_sty { - TyInt(I8) => "llvm.sadd.with.overflow.i8", - TyInt(I16) => "llvm.sadd.with.overflow.i16", - TyInt(I32) => "llvm.sadd.with.overflow.i32", - TyInt(I64) => "llvm.sadd.with.overflow.i64", - - TyUint(U8) => "llvm.uadd.with.overflow.i8", - TyUint(U16) => "llvm.uadd.with.overflow.i16", - TyUint(U32) => "llvm.uadd.with.overflow.i32", - TyUint(U64) => "llvm.uadd.with.overflow.i64", - - _ => bug!(), - }, - OverflowOpViaIntrinsic::Sub => match new_sty { - TyInt(I8) => "llvm.ssub.with.overflow.i8", - TyInt(I16) => "llvm.ssub.with.overflow.i16", - TyInt(I32) => "llvm.ssub.with.overflow.i32", - TyInt(I64) => "llvm.ssub.with.overflow.i64", - - TyUint(U8) => "llvm.usub.with.overflow.i8", - TyUint(U16) => "llvm.usub.with.overflow.i16", - TyUint(U32) => "llvm.usub.with.overflow.i32", - TyUint(U64) => "llvm.usub.with.overflow.i64", - - _ => bug!(), - }, - OverflowOpViaIntrinsic::Mul => match new_sty { - TyInt(I8) => "llvm.smul.with.overflow.i8", - TyInt(I16) => "llvm.smul.with.overflow.i16", - TyInt(I32) => "llvm.smul.with.overflow.i32", - TyInt(I64) => "llvm.smul.with.overflow.i64", - - TyUint(U8) => "llvm.umul.with.overflow.i8", - TyUint(U16) => "llvm.umul.with.overflow.i16", - TyUint(U32) => "llvm.umul.with.overflow.i32", - TyUint(U64) => "llvm.umul.with.overflow.i64", - - _ => bug!(), - }, - } - } - - fn build_intrinsic_call<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, - info: NodeIdAndSpan, - lhs_t: Ty<'tcx>, lhs: ValueRef, - rhs: ValueRef, - binop_debug_loc: DebugLoc) - -> (Block<'blk, 'tcx>, ValueRef) { - use rustc_const_math::{ConstMathErr, Op}; - - let llfn = self.to_intrinsic(bcx, lhs_t); - - let val = Call(bcx, llfn, &[lhs, rhs], binop_debug_loc); - let result = ExtractValue(bcx, val, 0); // iN operation result - let overflow = ExtractValue(bcx, val, 1); // i1 "did it overflow?" - - let cond = ICmp(bcx, llvm::IntEQ, overflow, C_integral(Type::i1(bcx.ccx()), 1, false), - binop_debug_loc); - - let expect = bcx.ccx().get_intrinsic(&"llvm.expect.i1"); - let expected = Call(bcx, expect, &[cond, C_bool(bcx.ccx(), false)], - binop_debug_loc); - - let op = match *self { - OverflowOpViaIntrinsic::Add => Op::Add, - OverflowOpViaIntrinsic::Sub => Op::Sub, - OverflowOpViaIntrinsic::Mul => Op::Mul - }; - - let bcx = - base::with_cond(bcx, expected, |bcx| - controlflow::trans_fail(bcx, info, - InternedString::new(ConstMathErr::Overflow(op).description()))); - - (bcx, result) - } -} - -impl OverflowOpViaInputCheck { - fn build_with_input_check<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, - info: NodeIdAndSpan, - lhs_t: Ty<'tcx>, - lhs: ValueRef, - rhs: ValueRef, - binop_debug_loc: DebugLoc) - -> (Block<'blk, 'tcx>, ValueRef) - { - use rustc_const_math::{ConstMathErr, Op}; - - let lhs_llty = val_ty(lhs); - let rhs_llty = val_ty(rhs); - - // Panic if any bits are set outside of bits that we always - // mask in. - // - // Note that the mask's value is derived from the LHS type - // (since that is where the 32/64 distinction is relevant) but - // the mask's type must match the RHS type (since they will - // both be fed into an and-binop) - let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true); - - let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc); - let cond = build_nonzero_check(bcx, outer_bits, binop_debug_loc); - let (result, op) = match *self { - OverflowOpViaInputCheck::Shl => - (build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc), Op::Shl), - OverflowOpViaInputCheck::Shr => - (build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc), Op::Shr) - }; - let bcx = - base::with_cond(bcx, cond, |bcx| - controlflow::trans_fail(bcx, info, - InternedString::new(ConstMathErr::Overflow(op).description()))); - - (bcx, result) - } -} - -// Check if an integer or vector contains a nonzero element. -fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - value: ValueRef, - binop_debug_loc: DebugLoc) -> ValueRef { - let llty = val_ty(value); - let kind = llty.kind(); - match kind { - TypeKind::Integer => ICmp(bcx, llvm::IntNE, value, C_null(llty), binop_debug_loc), - TypeKind::Vector => { - // Check if any elements of the vector are nonzero by treating - // it as a wide integer and checking if the integer is nonzero. - let width = llty.vector_length() as u64 * llty.element_type().int_width(); - let int_value = BitCast(bcx, value, Type::ix(bcx.ccx(), width)); - build_nonzero_check(bcx, int_value, binop_debug_loc) - }, - _ => bug!("build_nonzero_check: expected Integer or Vector, found {:?}", kind), - } -} - -fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan, - lhs_t: Ty<'tcx>, lhs: ValueRef, - rhs: ValueRef, - binop_debug_loc: DebugLoc) - -> (Block<'blk, 'tcx>, ValueRef) { - if bcx.unreachable.get() { return (bcx, _Undef(lhs)); } - if bcx.ccx().check_overflow() { - - match oop.codegen_strategy() { - OverflowCodegen::ViaIntrinsic(oop) => - oop.build_intrinsic_call(bcx, info, lhs_t, lhs, rhs, binop_debug_loc), - OverflowCodegen::ViaInputCheck(oop) => - oop.build_with_input_check(bcx, info, lhs_t, lhs, rhs, binop_debug_loc), - } - } else { - let res = match oop { - OverflowOp::Add => Add(bcx, lhs, rhs, binop_debug_loc), - OverflowOp::Sub => Sub(bcx, lhs, rhs, binop_debug_loc), - OverflowOp::Mul => Mul(bcx, lhs, rhs, binop_debug_loc), - - OverflowOp::Shl => - build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc), - OverflowOp::Shr => - build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc), - }; - (bcx, res) - } -} - -/// We categorize expressions into three kinds. The distinction between -/// lvalue/rvalue is fundamental to the language. The distinction between the -/// two kinds of rvalues is an artifact of trans which reflects how we will -/// generate code for that kind of expression. See trans/expr.rs for more -/// information. -#[derive(Copy, Clone)] -enum ExprKind { - Lvalue, - RvalueDps, - RvalueDatum, - RvalueStmt -} - -fn expr_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expr: &hir::Expr) -> ExprKind { - if tcx.is_method_call(expr.id) { - // Overloaded operations are generally calls, and hence they are - // generated via DPS, but there are a few exceptions: - return match expr.node { - // `a += b` has a unit result. - hir::ExprAssignOp(..) => ExprKind::RvalueStmt, - - // the deref method invoked for `*a` always yields an `&T` - hir::ExprUnary(hir::UnDeref, _) => ExprKind::Lvalue, - - // the index method invoked for `a[i]` always yields an `&T` - hir::ExprIndex(..) => ExprKind::Lvalue, - - // in the general case, result could be any type, use DPS - _ => ExprKind::RvalueDps - }; - } - - match expr.node { - hir::ExprPath(..) => { - match tcx.expect_def(expr.id) { - // Put functions and ctors with the ADTs, as they - // are zero-sized, so DPS is the cheapest option. - Def::Struct(..) | Def::Variant(..) | - Def::Fn(..) | Def::Method(..) => { - ExprKind::RvalueDps - } - - // Note: there is actually a good case to be made that - // DefArg's, particularly those of immediate type, ought to - // considered rvalues. - Def::Static(..) | - Def::Upvar(..) | - Def::Local(..) => ExprKind::Lvalue, - - Def::Const(..) | - Def::AssociatedConst(..) => ExprKind::RvalueDatum, - - def => { - span_bug!( - expr.span, - "uncategorized def for expr {}: {:?}", - expr.id, - def); - } - } - } - - hir::ExprType(ref expr, _) => { - expr_kind(tcx, expr) - } - - hir::ExprUnary(hir::UnDeref, _) | - hir::ExprField(..) | - hir::ExprTupField(..) | - hir::ExprIndex(..) => { - ExprKind::Lvalue - } - - hir::ExprCall(..) | - hir::ExprMethodCall(..) | - hir::ExprStruct(..) | - hir::ExprTup(..) | - hir::ExprIf(..) | - hir::ExprMatch(..) | - hir::ExprClosure(..) | - hir::ExprBlock(..) | - hir::ExprRepeat(..) | - hir::ExprVec(..) => { - ExprKind::RvalueDps - } - - hir::ExprLit(ref lit) if lit.node.is_str() => { - ExprKind::RvalueDps - } - - hir::ExprBreak(..) | - hir::ExprAgain(..) | - hir::ExprRet(..) | - hir::ExprWhile(..) | - hir::ExprLoop(..) | - hir::ExprAssign(..) | - hir::ExprInlineAsm(..) | - hir::ExprAssignOp(..) => { - ExprKind::RvalueStmt - } - - hir::ExprLit(_) | // Note: LitStr is carved out above - hir::ExprUnary(..) | - hir::ExprBox(_) | - hir::ExprAddrOf(..) | - hir::ExprBinary(..) | - hir::ExprCast(..) => { - ExprKind::RvalueDatum - } - } -} diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 080844782f205..d2784610ff55e 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -21,15 +21,11 @@ use rustc::ty::subst::{Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use adt; -use adt::GetDtorType; // for tcx.dtor_type() use base::*; use build::*; -use callee::{Callee, ArgVals}; -use cleanup; -use cleanup::CleanupMethods; +use callee::{Callee}; use common::*; use debuginfo::DebugLoc; -use expr; use machine::*; use monomorphize; use trans_item::TransItem; @@ -51,7 +47,7 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem); let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align]; Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx())) - .call(bcx, debug_loc, ArgVals(&args), None).bcx + .call(bcx, debug_loc, &args, None).bcx } pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, @@ -133,20 +129,18 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>, debug_loc: DebugLoc) -> Block<'blk, 'tcx> { - drop_ty_core(bcx, v, t, debug_loc, false, None) + drop_ty_core(bcx, v, t, debug_loc, false) } pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>, debug_loc: DebugLoc, - skip_dtor: bool, - drop_hint: Option) + skip_dtor: bool) -> Block<'blk, 'tcx> { // NB: v is an *alias* of type t here, not a direct value. - debug!("drop_ty_core(t={:?}, skip_dtor={} drop_hint={:?})", t, skip_dtor, drop_hint); + debug!("drop_ty_core(t={:?}, skip_dtor={})", t, skip_dtor); let _icx = push_ctxt("drop_ty"); - let mut bcx = bcx; if bcx.fcx.type_needs_drop(t) { let ccx = bcx.ccx(); let g = if skip_dtor { @@ -162,23 +156,8 @@ pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v }; - match drop_hint { - Some(drop_hint) => { - let hint_val = load_ty(bcx, drop_hint.value(), bcx.tcx().types.u8); - let moved_val = - C_integral(Type::i8(bcx.ccx()), adt::DTOR_MOVED_HINT as u64, false); - let may_need_drop = - ICmp(bcx, llvm::IntNE, hint_val, moved_val, DebugLoc::None); - bcx = with_cond(bcx, may_need_drop, |cx| { - Call(cx, glue, &[ptr], debug_loc); - cx - }) - } - None => { - // No drop-hint ==> call standard drop glue - Call(bcx, glue, &[ptr], debug_loc); - } - } + // No drop-hint ==> call standard drop glue + Call(bcx, glue, &[ptr], debug_loc); } bcx } @@ -193,7 +172,7 @@ pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let vp = alloc_ty(bcx, t, ""); call_lifetime_start(bcx, vp); store_ty(bcx, v, vp, t); - let bcx = drop_ty_core(bcx, vp, t, debug_loc, skip_dtor, None); + let bcx = drop_ty_core(bcx, vp, t, debug_loc, skip_dtor); call_lifetime_end(bcx, vp); bcx } @@ -273,7 +252,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arena = TypedArena::new(); fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &arena); - let bcx = fcx.init(false, None); + let bcx = fcx.init(false); ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1); // All glue functions take values passed *by alias*; this is a @@ -288,40 +267,6 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fcx.finish(bcx, DebugLoc::None); } - -fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - t: Ty<'tcx>, - struct_data: ValueRef) - -> Block<'blk, 'tcx> { - assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized"); - - let repr = adt::represent_type(bcx.ccx(), t); - let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &repr, struct_data)); - let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type()); - let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type()); - let init_val = C_integral(drop_flag_llty, adt::DTOR_NEEDED as u64, false); - - let bcx = if !bcx.ccx().check_drop_flag_for_sanity() { - bcx - } else { - let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type()); - let done_val = C_integral(drop_flag_llty, adt::DTOR_DONE as u64, false); - let not_init = ICmp(bcx, llvm::IntNE, loaded, init_val, DebugLoc::None); - let not_done = ICmp(bcx, llvm::IntNE, loaded, done_val, DebugLoc::None); - let drop_flag_neither_initialized_nor_cleared = - And(bcx, not_init, not_done, DebugLoc::None); - with_cond(bcx, drop_flag_neither_initialized_nor_cleared, |cx| { - let llfn = cx.ccx().get_intrinsic(&("llvm.debugtrap")); - Call(cx, llfn, &[], DebugLoc::None); - cx - }) - }; - - let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None); - with_cond(bcx, drop_flag_dtor_needed, |cx| { - trans_struct_drop(cx, t, struct_data) - }) -} fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef) @@ -343,14 +288,17 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Issue #23611: schedule cleanup of contents, re-inspecting the // discriminant (if any) in case of variant swap in drop code. - bcx.fcx.schedule_drop_adt_contents(cleanup::CustomScope(contents_scope), v0, t); + bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t); let (sized_args, unsized_args); let args: &[ValueRef] = if type_is_sized(tcx, t) { sized_args = [v0]; &sized_args } else { - unsized_args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_meta(bcx, v0))]; + unsized_args = [ + Load(bcx, get_dataptr(bcx, v0)), + Load(bcx, get_meta(bcx, v0)) + ]; &unsized_args }; @@ -364,7 +312,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let dtor_did = def.destructor().unwrap(); bcx = Callee::def(bcx.ccx(), dtor_did, vtbl.substs) - .call(bcx, DebugLoc::None, ArgVals(args), None).bcx; + .call(bcx, DebugLoc::None, args, None).bcx; bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope) } @@ -492,9 +440,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK // must definitely check for special bit-patterns corresponding to // the special dtor markings. - let inttype = Type::int(bcx.ccx()); - let dropped_pattern = C_integral(inttype, adt::DTOR_DONE_U64, false); - match t.sty { ty::TyBox(content_ty) => { // Support for TyBox is built-in and its drop glue is @@ -502,59 +447,33 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK // a safe-guard, assert TyBox not used with TyContents. assert!(!skip_dtor); if !type_is_sized(bcx.tcx(), content_ty) { - let llval = expr::get_dataptr(bcx, v0); + let llval = get_dataptr(bcx, v0); let llbox = Load(bcx, llval); - let llbox_as_usize = PtrToInt(bcx, llbox, Type::int(bcx.ccx())); - let drop_flag_not_dropped_already = - ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None); - with_cond(bcx, drop_flag_not_dropped_already, |bcx| { - let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None); - let info = expr::get_meta(bcx, v0); - let info = Load(bcx, info); - let (llsize, llalign) = - size_and_align_of_dst(&bcx.build(), content_ty, info); - - // `Box` does not allocate. - let needs_free = ICmp(bcx, - llvm::IntNE, - llsize, - C_uint(bcx.ccx(), 0u64), - DebugLoc::None); - with_cond(bcx, needs_free, |bcx| { - trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None) - }) + let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None); + let info = get_meta(bcx, v0); + let info = Load(bcx, info); + let (llsize, llalign) = + size_and_align_of_dst(&bcx.build(), content_ty, info); + + // `Box` does not allocate. + let needs_free = ICmp(bcx, + llvm::IntNE, + llsize, + C_uint(bcx.ccx(), 0u64), + DebugLoc::None); + with_cond(bcx, needs_free, |bcx| { + trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None) }) } else { let llval = v0; let llbox = Load(bcx, llval); - let llbox_as_usize = PtrToInt(bcx, llbox, inttype); - let drop_flag_not_dropped_already = - ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None); - with_cond(bcx, drop_flag_not_dropped_already, |bcx| { - let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None); - trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None) - }) + let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None); + trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None) } } ty::TyStruct(def, _) | ty::TyEnum(def, _) => { match (def.dtor_kind(), skip_dtor) { - (ty::TraitDtor(true), false) => { - // FIXME(16758) Since the struct is unsized, it is hard to - // find the drop flag (which is at the end of the struct). - // Lets just ignore the flag and pretend everything will be - // OK. - if type_is_sized(bcx.tcx(), t) { - trans_struct_drop_flag(bcx, t, v0) - } else { - // Give the user a heads up that we are doing something - // stupid and dangerous. - bcx.sess().warn(&format!("Ignoring drop flag in destructor for {} \ - because the struct is unsized. See issue \ - #16758", t)); - trans_struct_drop(bcx, t, v0) - } - } - (ty::TraitDtor(false), false) => { + (ty::TraitDtor(_), false) => { trans_struct_drop(bcx, t, v0) } (ty::NoDtor, _) | (_, true) => { @@ -568,8 +487,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK // versus without calling Drop::drop. Assert caller is // okay with always calling the Drop impl, if any. assert!(!skip_dtor); - let data_ptr = expr::get_dataptr(bcx, v0); - let vtable_ptr = Load(bcx, expr::get_meta(bcx, v0)); + let data_ptr = get_dataptr(bcx, v0); + let vtable_ptr = Load(bcx, get_meta(bcx, v0)); let dtor = Load(bcx, vtable_ptr); Call(bcx, dtor, diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index ecee470551059..ef06030785af8 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -14,21 +14,14 @@ use arena::TypedArena; use intrinsics::{self, Intrinsic}; use libc; use llvm; -use llvm::{ValueRef, TypeKind}; -use rustc::ty::subst::Substs; +use llvm::{ValueRef}; use abi::{Abi, FnType}; use adt; use base::*; use build::*; -use callee::{self, Callee}; -use cleanup; -use cleanup::CleanupMethods; use common::*; -use consts; -use datum::*; use debuginfo::DebugLoc; use declare; -use expr; use glue; use type_of; use machine; @@ -37,11 +30,9 @@ use rustc::ty::{self, Ty}; use Disr; use rustc::hir; use syntax::ast; -use syntax::ptr::P; use syntax::parse::token; use rustc::session::Session; -use rustc_const_eval::fatal_const_eval_err; use syntax_pos::{Span, DUMMY_SP}; use std::cmp::Ordering; @@ -98,8 +89,8 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, callee_ty: Ty<'tcx>, fn_ty: &FnType, - args: callee::CallArgs<'a, 'tcx>, - dest: expr::Dest, + llargs: &[ValueRef], + llresult: ValueRef, call_debug_location: DebugLoc) -> Result<'blk, 'tcx> { let fcx = bcx.fcx; @@ -127,210 +118,19 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } }; - let cleanup_scope = fcx.push_custom_cleanup_scope(); - - // For `transmute` we can just trans the input expr directly into dest - if name == "transmute" { - let llret_ty = type_of::type_of(ccx, ret_ty); - match args { - callee::ArgExprs(arg_exprs) => { - assert_eq!(arg_exprs.len(), 1); - - let (in_type, out_type) = (substs.types[0], - substs.types[1]); - let llintype = type_of::type_of(ccx, in_type); - let llouttype = type_of::type_of(ccx, out_type); - - let in_type_size = machine::llbitsize_of_real(ccx, llintype); - let out_type_size = machine::llbitsize_of_real(ccx, llouttype); - - if let ty::TyFnDef(def_id, substs, _) = in_type.sty { - if out_type_size != 0 { - // FIXME #19925 Remove this hack after a release cycle. - let _ = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); - let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val; - let llfnty = val_ty(llfn); - let llresult = match dest { - expr::SaveIn(d) => d, - expr::Ignore => alloc_ty(bcx, out_type, "ret") - }; - Store(bcx, llfn, PointerCast(bcx, llresult, llfnty.ptr_to())); - if dest == expr::Ignore { - bcx = glue::drop_ty(bcx, llresult, out_type, - call_debug_location); - } - fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); - fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); - return Result::new(bcx, llresult); - } - } - - // This should be caught by the intrinsicck pass - assert_eq!(in_type_size, out_type_size); - - let nonpointer_nonaggregate = |llkind: TypeKind| -> bool { - use llvm::TypeKind::*; - match llkind { - Half | Float | Double | X86_FP80 | FP128 | - PPC_FP128 | Integer | Vector | X86_MMX => true, - _ => false - } - }; - - // An approximation to which types can be directly cast via - // LLVM's bitcast. This doesn't cover pointer -> pointer casts, - // but does, importantly, cover SIMD types. - let in_kind = llintype.kind(); - let ret_kind = llret_ty.kind(); - let bitcast_compatible = - (nonpointer_nonaggregate(in_kind) && nonpointer_nonaggregate(ret_kind)) || { - in_kind == TypeKind::Pointer && ret_kind == TypeKind::Pointer - }; - - let dest = if bitcast_compatible { - // if we're here, the type is scalar-like (a primitive, a - // SIMD type or a pointer), and so can be handled as a - // by-value ValueRef and can also be directly bitcast to the - // target type. Doing this special case makes conversions - // like `u32x4` -> `u64x2` much nicer for LLVM and so more - // efficient (these are done efficiently implicitly in C - // with the `__m128i` type and so this means Rust doesn't - // lose out there). - let expr = &arg_exprs[0]; - let datum = unpack_datum!(bcx, expr::trans(bcx, expr)); - let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "transmute_temp")); - let val = if datum.kind.is_by_ref() { - load_ty(bcx, datum.val, datum.ty) - } else { - from_immediate(bcx, datum.val) - }; - - let cast_val = BitCast(bcx, val, llret_ty); - - match dest { - expr::SaveIn(d) => { - // this often occurs in a sequence like `Store(val, - // d); val2 = Load(d)`, so disappears easily. - Store(bcx, cast_val, d); - } - expr::Ignore => {} - } - dest - } else { - // The types are too complicated to do with a by-value - // bitcast, so pointer cast instead. We need to cast the - // dest so the types work out. - let dest = match dest { - expr::SaveIn(d) => expr::SaveIn(PointerCast(bcx, d, llintype.ptr_to())), - expr::Ignore => expr::Ignore - }; - bcx = expr::trans_into(bcx, &arg_exprs[0], dest); - dest - }; - - fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); - fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); - - return match dest { - expr::SaveIn(d) => Result::new(bcx, d), - expr::Ignore => Result::new(bcx, C_undef(llret_ty.ptr_to())) - }; - - } - - _ => { - bug!("expected expr as argument for transmute"); - } - } - } - - // For `move_val_init` we can evaluate the destination address - // (the first argument) and then trans the source value (the - // second argument) directly into the resulting destination - // address. - if name == "move_val_init" { - if let callee::ArgExprs(ref exprs) = args { - let (dest_expr, source_expr) = if exprs.len() != 2 { - bug!("expected two exprs as arguments for `move_val_init` intrinsic"); - } else { - (&exprs[0], &exprs[1]) - }; - - // evaluate destination address - let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr)); - let dest_datum = unpack_datum!( - bcx, dest_datum.to_rvalue_datum(bcx, "arg")); - let dest_datum = unpack_datum!( - bcx, dest_datum.to_appropriate_datum(bcx)); - - // `expr::trans_into(bcx, expr, dest)` is equiv to - // - // `trans(bcx, expr).store_to_dest(dest)`, - // - // which for `dest == expr::SaveIn(addr)`, is equivalent to: - // - // `trans(bcx, expr).store_to(bcx, addr)`. - let lldest = expr::Dest::SaveIn(dest_datum.val); - bcx = expr::trans_into(bcx, source_expr, lldest); - - let llresult = C_nil(ccx); - fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); - - return Result::new(bcx, llresult); - } else { - bug!("expected two exprs as arguments for `move_val_init` intrinsic"); - } - } - - // save the actual AST arguments for later (some places need to do - // const-evaluation on them) - let expr_arguments = match args { - callee::ArgExprs(args) => Some(args), - _ => None, - }; - - // Push the arguments. - let mut llargs = Vec::new(); - bcx = callee::trans_args(bcx, - Abi::RustIntrinsic, - fn_ty, - &mut callee::Intrinsic, - args, - &mut llargs, - cleanup::CustomScope(cleanup_scope)); - - fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); - // These are the only intrinsic functions that diverge. if name == "abort" { let llfn = ccx.get_intrinsic(&("llvm.trap")); Call(bcx, llfn, &[], call_debug_location); - fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); Unreachable(bcx); return Result::new(bcx, C_undef(Type::nil(ccx).ptr_to())); } else if &name[..] == "unreachable" { - fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); Unreachable(bcx); return Result::new(bcx, C_nil(ccx)); } let llret_ty = type_of::type_of(ccx, ret_ty); - // Get location to store the result. If the user does - // not care about the result, just make a stack slot - let llresult = match dest { - expr::SaveIn(d) => d, - expr::Ignore => { - if !type_is_zero_size(ccx, ret_ty) { - let llresult = alloc_ty(bcx, ret_ty, "intrinsic_result"); - call_lifetime_start(bcx, llresult); - llresult - } else { - C_undef(llret_ty.ptr_to()) - } - } - }; - let simple = get_simple_intrinsic(ccx, &name); let llval = match (simple, &name[..]) { (Some(llfn), _) => { @@ -382,16 +182,20 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, "drop_in_place") => { let tp_ty = substs.types[0]; - let ptr = if type_is_sized(tcx, tp_ty) { + let is_sized = type_is_sized(tcx, tp_ty); + let ptr = if is_sized { llargs[0] } else { - let scratch = rvalue_scratch_datum(bcx, tp_ty, "tmp"); - Store(bcx, llargs[0], expr::get_dataptr(bcx, scratch.val)); - Store(bcx, llargs[1], expr::get_meta(bcx, scratch.val)); - fcx.schedule_lifetime_end(cleanup::CustomScope(cleanup_scope), scratch.val); - scratch.val + let scratch = alloc_ty(bcx, tp_ty, "drop"); + call_lifetime_start(bcx, scratch); + Store(bcx, llargs[0], get_dataptr(bcx, scratch)); + Store(bcx, llargs[1], get_meta(bcx, scratch)); + scratch }; glue::drop_ty(bcx, ptr, tp_ty, call_debug_location); + if !is_sized { + call_lifetime_end(bcx, ptr); + } C_nil(ccx) } (_, "type_name") => { @@ -403,11 +207,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_u64(ccx, ccx.tcx().type_id_hash(substs.types[0])) } (_, "init_dropped") => { - let tp_ty = substs.types[0]; - if !type_is_zero_size(ccx, tp_ty) { - drop_done_fill_mem(bcx, llresult, tp_ty); - } - C_nil(ccx) + span_bug!(span, "init_dropped intrinsic unsupported"); } (_, "init") => { let tp_ty = substs.types[0]; @@ -511,8 +311,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "volatile_store") => { let tp_ty = substs.types[0]; if type_is_fat_ptr(bcx.tcx(), tp_ty) { - VolatileStore(bcx, llargs[1], expr::get_dataptr(bcx, llargs[0])); - VolatileStore(bcx, llargs[2], expr::get_meta(bcx, llargs[0])); + VolatileStore(bcx, llargs[1], get_dataptr(bcx, llargs[0])); + VolatileStore(bcx, llargs[2], get_meta(bcx, llargs[0])); } else { let val = if fn_ty.args[1].is_indirect() { Load(bcx, llargs[1]) @@ -621,9 +421,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, name) if name.starts_with("simd_") => { generic_simd_intrinsic(bcx, name, - substs, callee_ty, - expr_arguments, &llargs, ret_ty, llret_ty, call_debug_location, @@ -868,13 +666,13 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let llargs = if !any_changes_needed { // no aggregates to flatten, so no change needed - llargs + llargs.to_vec() } else { // there are some aggregates that need to be flattened // in the LLVM call, so we need to run over the types // again to find them and extract the arguments intr.inputs.iter() - .zip(&llargs) + .zip(llargs) .zip(&arg_tys) .flat_map(|((t, llarg), ty)| modify_as_needed(bcx, t, ty, *llarg)) .collect() @@ -919,17 +717,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } - // If we made a temporary stack slot, let's clean it up - match dest { - expr::Ignore => { - bcx = glue::drop_ty(bcx, llresult, ret_ty, call_debug_location); - call_lifetime_end(bcx, llresult); - } - expr::SaveIn(_) => {} - } - - fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); - Result::new(bcx, llresult) } @@ -1064,10 +851,10 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, SetPersonalityFn(bcx, bcx.fcx.eh_personality()); - let normal = bcx.fcx.new_temp_block("normal"); - let catchswitch = bcx.fcx.new_temp_block("catchswitch"); - let catchpad = bcx.fcx.new_temp_block("catchpad"); - let caught = bcx.fcx.new_temp_block("caught"); + let normal = bcx.fcx.new_block("normal"); + let catchswitch = bcx.fcx.new_block("catchswitch"); + let catchpad = bcx.fcx.new_block("catchpad"); + let caught = bcx.fcx.new_block("caught"); let func = llvm::get_param(bcx.fcx.llfn, 0); let data = llvm::get_param(bcx.fcx.llfn, 1); @@ -1123,7 +910,7 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = ccx.tcx(); let tydesc = match tcx.lang_items.msvc_try_filter() { - Some(did) => ::consts::get_static(ccx, did).to_llref(), + Some(did) => ::consts::get_static(ccx, did), None => bug!("msvc_try_filter not defined"), }; let tok = CatchPad(catchpad, cs, &[tydesc, C_i32(ccx, 0), slot]); @@ -1184,8 +971,8 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // expected to be `*mut *mut u8` for this to actually work, but that's // managed by the standard library. - let then = bcx.fcx.new_temp_block("then"); - let catch = bcx.fcx.new_temp_block("catch"); + let then = bcx.fcx.new_block("then"); + let catch = bcx.fcx.new_block("catch"); let func = llvm::get_param(bcx.fcx.llfn, 0); let data = llvm::get_param(bcx.fcx.llfn, 1); @@ -1240,8 +1027,7 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, let (fcx, block_arena); block_arena = TypedArena::new(); fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena); - let bcx = fcx.init(true, None); - trans(bcx); + trans(fcx.init(true)); fcx.cleanup(); llfn } @@ -1283,9 +1069,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { fn generic_simd_intrinsic<'blk, 'tcx, 'a> (bcx: Block<'blk, 'tcx>, name: &str, - substs: &'tcx Substs<'tcx>, callee_ty: Ty<'tcx>, - args: Option<&[P]>, llargs: &[ValueRef], ret_ty: Ty<'tcx>, llret_ty: Type, @@ -1386,20 +1170,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> let total_len = in_len as u64 * 2; - let vector = match args { - Some(args) => { - match consts::const_expr(bcx.ccx(), &args[2], substs, None, - // this should probably help simd error reporting - consts::TrueConst::Yes) { - Ok((vector, _)) => vector, - Err(err) => { - fatal_const_eval_err(bcx.tcx(), err.as_inner(), span, - "shuffle indices"); - } - } - } - None => llargs[2] - }; + let vector = llargs[2]; let indices: Option> = (0..n) .map(|i| { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 81a1dbeb7fe74..d989acc27effd 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -110,17 +110,13 @@ mod collector; mod common; mod consts; mod context; -mod controlflow; -mod datum; mod debuginfo; mod declare; mod disr; -mod expr; mod glue; mod inline; mod intrinsic; mod machine; -mod _match; mod meth; mod mir; mod monomorphize; diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index b051028ebda6b..97c77ee3d8c72 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -20,13 +20,12 @@ use rustc::traits::{self, Reveal}; use abi::FnType; use base::*; use build::*; -use callee::{Callee, Virtual, ArgVals, trans_fn_pointer_shim}; +use callee::{Callee, Virtual, trans_fn_pointer_shim}; use closure; use common::*; use consts; use debuginfo::DebugLoc; use declare; -use expr; use glue; use machine; use type_::Type; @@ -96,25 +95,21 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena); - let mut bcx = fcx.init(false, None); - assert!(!fcx.needs_ret_allocas); + let mut bcx = fcx.init(false); - - let dest = - fcx.llretslotptr.get().map( - |_| expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))); + let dest = fcx.llretslotptr.get(); debug!("trans_object_shim: method_offset_in_vtable={}", vtable_index); let llargs = get_params(fcx.llfn); - let args = ArgVals(&llargs[fcx.fn_ty.ret.is_indirect() as usize..]); let callee = Callee { data: Virtual(vtable_index), ty: method_ty }; - bcx = callee.call(bcx, DebugLoc::None, args, dest).bcx; + bcx = callee.call(bcx, DebugLoc::None, + &llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx; fcx.finish(bcx, DebugLoc::None); @@ -160,7 +155,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, get_vtable_methods(tcx, id, substs) .into_iter() .map(|opt_mth| opt_mth.map_or(nullptr, |mth| { - Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx).val + Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx) })) .collect::>() .into_iter() diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 56d02fa1fac4f..3ab4290e7b9b9 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::{self, ValueRef}; -use rustc_const_eval::ErrKind; +use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; use rustc::ty; use rustc::mir::repr as mir; @@ -78,7 +78,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { debug!("llblock: creating cleanup trampoline for {:?}", target); let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target); - let trampoline = this.fcx.new_block(name, None).build(); + let trampoline = this.fcx.new_block(name).build(); trampoline.set_personality_fn(this.fcx.eh_personality()); trampoline.cleanup_ret(cp, Some(lltarget)); trampoline.llbb() @@ -291,7 +291,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Create the failure block and the conditional branch to it. let lltarget = llblock(self, target); - let panic_block = self.fcx.new_block("panic", None); + let panic_block = self.fcx.new_block("panic"); if expected { bcx.cond_br(cond, lltarget, panic_block.llbb); } else { @@ -354,9 +354,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // is also constant, then we can produce a warning. if const_cond == Some(!expected) { if let Some(err) = const_err { - let _ = consts::const_err(bcx.ccx(), span, - Err::<(), _>(err), - consts::TrueConst::No); + let err = ConstEvalErr{ span: span, kind: err }; + let mut diag = bcx.tcx().sess.struct_span_warn( + span, "this expression will panic at run-time"); + note_const_eval_err(bcx.tcx(), &err, span, "expression", &mut diag); + diag.emit(); } } @@ -364,7 +366,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item); let callee = Callee::def(bcx.ccx(), def_id, bcx.ccx().empty_substs_for_def_id(def_id)); - let llfn = callee.reify(bcx.ccx()).val; + let llfn = callee.reify(bcx.ccx()); // Translate the actual panic invoke/call. if let Some(unwind) = cleanup { @@ -497,28 +499,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let fn_ptr = match callee.data { NamedTupleConstructor(_) => { // FIXME translate this like mir::Rvalue::Aggregate. - callee.reify(bcx.ccx()).val + callee.reify(bcx.ccx()) } Intrinsic => { - use callee::ArgVals; - use expr::{Ignore, SaveIn}; use intrinsic::trans_intrinsic_call; let (dest, llargs) = match ret_dest { _ if fn_ty.ret.is_indirect() => { - (SaveIn(llargs[0]), &llargs[1..]) + (llargs[0], &llargs[1..]) + } + ReturnDest::Nothing => { + (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..]) } - ReturnDest::Nothing => (Ignore, &llargs[..]), ReturnDest::IndirectOperand(dst, _) | - ReturnDest::Store(dst) => (SaveIn(dst), &llargs[..]), + ReturnDest::Store(dst) => (dst, &llargs[..]), ReturnDest::DirectOperand(_) => bug!("Cannot use direct operand with an intrinsic call") }; bcx.with_block(|bcx| { trans_intrinsic_call(bcx, callee.ty, &fn_ty, - ArgVals(llargs), dest, - debug_loc); + &llargs, dest, debug_loc); }); if let ReturnDest::IndirectOperand(dst, _) = ret_dest { @@ -766,7 +767,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let target = self.bcx(target_bb); - let block = self.fcx.new_block("cleanup", None); + let block = self.fcx.new_block("cleanup"); self.landing_pads[target_bb] = Some(block); let bcx = block.build(); @@ -809,7 +810,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> { self.unreachable_block.unwrap_or_else(|| { - let bl = self.fcx.new_block("unreachable", None); + let bl = self.fcx.new_block("unreachable"); bl.build().unreachable(); self.unreachable_block = Some(bl); bl @@ -878,10 +879,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if out_type_size != 0 { // FIXME #19925 Remove this hack after a release cycle. let f = Callee::def(bcx.ccx(), def_id, substs); - let datum = f.reify(bcx.ccx()); + let ty = match f.ty.sty { + ty::TyFnDef(_, _, f) => bcx.tcx().mk_fn_ptr(f), + _ => f.ty + }; val = OperandRef { - val: Immediate(datum.val), - ty: datum.ty + val: Immediate(f.reify(bcx.ccx())), + ty: ty }; } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4da973bb7f946..1badfdba6603f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -10,10 +10,10 @@ use llvm::{self, ValueRef}; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::ErrKind; +use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err}; use rustc_const_math::ConstInt::*; use rustc_const_math::ConstFloat::*; -use rustc_const_math::ConstMathErr; +use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::mir::repr as mir; @@ -28,12 +28,14 @@ use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty}; use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral}; use common::{C_null, C_struct, C_str_slice, C_undef, C_uint}; -use consts::{self, ConstEvalFailure, TrueConst, to_const_int}; +use common::{const_to_opt_int, const_to_opt_uint}; +use consts; use monomorphize::{self, Instance}; use type_of; use type_::Type; use value::Value; +use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use std::ptr; @@ -230,7 +232,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, mut instance: Instance<'tcx>, args: IndexVec>) - -> Result, ConstEvalFailure> { + -> Result, ConstEvalErr> { // Try to resolve associated constants. if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) { let trait_ref = ty::TraitRef::new(trait_id, instance.substs); @@ -261,7 +263,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { value) } - fn trans(&mut self) -> Result, ConstEvalFailure> { + fn trans(&mut self) -> Result, ConstEvalErr> { let tcx = self.ccx.tcx(); let mut bb = mir::START_BLOCK; @@ -320,10 +322,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { ErrKind::Math(err.clone()) } }; - match consts::const_err(self.ccx, span, Err(err), TrueConst::Yes) { - Ok(()) => {} - Err(err) => if failure.is_ok() { failure = Err(err); } - } + + let err = ConstEvalErr{ span: span, kind: err }; + report_const_eval_err(tcx, &err, span, "expression").emit(); + failure = Err(err); } target } @@ -370,7 +372,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span) - -> Result, ConstEvalFailure> { + -> Result, ConstEvalErr> { let tcx = self.ccx.tcx(); if let Some(index) = self.mir.local_index(lvalue) { @@ -386,7 +388,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::Lvalue::ReturnPointer => bug!(), // handled above mir::Lvalue::Static(def_id) => { ConstLvalue { - base: Base::Static(consts::get_static(self.ccx, def_id).val), + base: Base::Static(consts::get_static(self.ccx, def_id)), llextra: ptr::null_mut(), ty: lvalue.ty(self.mir, tcx).to_ty(tcx) } @@ -411,11 +413,18 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } else if let ty::TyStr = projected_ty.sty { (Base::Str(base), extra) } else { - let val = consts::load_const(self.ccx, base, projected_ty); + let v = base; + let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v); + let mut val = unsafe { llvm::LLVMGetInitializer(v) }; if val.is_null() { span_bug!(span, "dereference of non-constant pointer `{:?}`", Value(base)); } + if projected_ty.is_bool() { + unsafe { + val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref()); + } + } (Base::Value(val), extra) } } @@ -462,7 +471,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span) - -> Result, ConstEvalFailure> { + -> Result, ConstEvalErr> { match *operand { mir::Operand::Consume(ref lvalue) => { Ok(self.const_lvalue(lvalue, span)?.to_const(span)) @@ -497,7 +506,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, dest_ty: Ty<'tcx>, span: Span) - -> Result, ConstEvalFailure> { + -> Result, ConstEvalErr> { let tcx = self.ccx.tcx(); let val = match *rvalue { mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?, @@ -565,7 +574,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { match operand.ty.sty { ty::TyFnDef(def_id, substs, _) => { Callee::def(self.ccx, def_id, substs) - .reify(self.ccx).val + .reify(self.ccx) } _ => { span_bug!(span, "{} cannot be reified to a fn ptr", @@ -782,6 +791,54 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } +fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { + match t.sty { + ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type { + ast::IntTy::I8 => { + assert_eq!(input as i8 as i64, input); + Some(ConstInt::I8(input as i8)) + }, + ast::IntTy::I16 => { + assert_eq!(input as i16 as i64, input); + Some(ConstInt::I16(input as i16)) + }, + ast::IntTy::I32 => { + assert_eq!(input as i32 as i64, input); + Some(ConstInt::I32(input as i32)) + }, + ast::IntTy::I64 => { + Some(ConstInt::I64(input)) + }, + ast::IntTy::Is => { + ConstIsize::new(input, tcx.sess.target.int_type) + .ok().map(ConstInt::Isize) + }, + }), + ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type { + ast::UintTy::U8 => { + assert_eq!(input as u8 as u64, input); + Some(ConstInt::U8(input as u8)) + }, + ast::UintTy::U16 => { + assert_eq!(input as u16 as u64, input); + Some(ConstInt::U16(input as u16)) + }, + ast::UintTy::U32 => { + assert_eq!(input as u32 as u64, input); + Some(ConstInt::U32(input as u32)) + }, + ast::UintTy::U64 => { + Some(ConstInt::U64(input)) + }, + ast::UintTy::Us => { + ConstUsize::new(input, tcx.sess.target.uint_type) + .ok().map(ConstInt::Usize) + }, + }), + _ => None, + } +} + pub fn const_scalar_binop(op: mir::BinOp, lhs: ValueRef, rhs: ValueRef, @@ -902,25 +959,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }; - match result { - Ok(v) => v, - Err(ConstEvalFailure::Compiletime(_)) => { - // We've errored, so we don't have to produce working code. - let llty = type_of::type_of(bcx.ccx(), ty); - Const::new(C_undef(llty), ty) - } - Err(ConstEvalFailure::Runtime(err)) => { - span_bug!(constant.span, - "MIR constant {:?} results in runtime panic: {:?}", - constant, err.description()) - } - } + result.unwrap_or_else(|_| { + // We've errored, so we don't have to produce working code. + let llty = type_of::type_of(bcx.ccx(), ty); + Const::new(C_undef(llty), ty) + }) } } pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId) - -> Result { + -> Result { let instance = Instance::mono(ccx.shared(), def_id); MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval) } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 94db2e3c23cef..5e180887a3604 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -109,7 +109,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::Lvalue::ReturnPointer => bug!(), // handled above mir::Lvalue::Static(def_id) => { let const_ty = self.monomorphized_lvalue_ty(lvalue); - LvalueRef::new_sized(consts::get_static(ccx, def_id).val, + LvalueRef::new_sized(consts::get_static(ccx, def_id), LvalueTy::from_ty(const_ty)) }, mir::Lvalue::Projection(box mir::Projection { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index fe90d7f2725ae..474b2552e7079 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -145,7 +145,7 @@ impl<'tcx> LocalRef<'tcx> { /////////////////////////////////////////////////////////////////////////// pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { - let bcx = fcx.init(true, None).build(); + let bcx = fcx.init(true).build(); let mir = bcx.mir(); // Analyze the temps to determine which must be lvalues @@ -207,9 +207,9 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let block_bcxs: IndexVec> = mir.basic_blocks().indices().map(|bb| { if bb == mir::START_BLOCK { - fcx.new_block("start", None) + fcx.new_block("start") } else { - fcx.new_block(&format!("{:?}", bb), None) + fcx.new_block(&format!("{:?}", bb)) } }).collect(); diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 9f7c2ee219eb5..6c740a93e2d70 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -17,7 +17,6 @@ use asm; use base; use callee::Callee; use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result}; -use datum::{Datum, Lvalue}; use debuginfo::DebugLoc; use adt; use machine; @@ -157,8 +156,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => { let outputs = outputs.iter().map(|output| { let lvalue = self.trans_lvalue(&bcx, output); - Datum::new(lvalue.llval, lvalue.ty.to_ty(bcx.tcx()), - Lvalue::new("out")) + (lvalue.llval, lvalue.ty.to_ty(bcx.tcx())) }).collect(); let input_vals = inputs.iter().map(|input| { @@ -202,7 +200,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { ty::TyFnDef(def_id, substs, _) => { OperandValue::Immediate( Callee::def(bcx.ccx(), def_id, substs) - .reify(bcx.ccx()).val) + .reify(bcx.ccx())) } _ => { bug!("{} cannot be reified to a fn ptr", operand.ty) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 580882e31dd60..66ea5264dd28e 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -88,13 +88,13 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = ccx.tcx().map.local_def_id(node_id); let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*) let item = ccx.tcx().map.expect_item(node_id); - if let hir::ItemStatic(_, m, ref expr) = item.node { - match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) { + if let hir::ItemStatic(_, m, _) = item.node { + match consts::trans_static(&ccx, m, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, Err(err) => { // FIXME: shouldn't this be a `span_err`? fatal_const_eval_err( - ccx.tcx(), &err, expr.span, "static"); + ccx.tcx(), &err, item.span, "static"); } }; } else { diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index 92a2d3787bfd6..df4f381f28761 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -13,347 +13,10 @@ use llvm; use llvm::ValueRef; use base::*; -use base; use build::*; -use cleanup; -use cleanup::CleanupMethods; use common::*; -use consts; -use datum::*; use debuginfo::DebugLoc; -use expr::{Dest, Ignore, SaveIn}; -use expr; -use machine::llsize_of_alloc; -use type_::Type; -use type_of; -use value::Value; -use rustc::ty::{self, Ty}; - -use rustc::hir; -use rustc_const_eval::eval_length; - -use syntax::ast; -use syntax::parse::token::InternedString; - -#[derive(Copy, Clone, Debug)] -struct VecTypes<'tcx> { - unit_ty: Ty<'tcx>, - llunit_ty: Type -} - -pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - dest: expr::Dest) - -> Block<'blk, 'tcx> { - //! - // - // [...] allocates a fixed-size array and moves it around "by value". - // In this case, it means that the caller has already given us a location - // to store the array of the suitable size, so all we have to do is - // generate the content. - - debug!("trans_fixed_vstore(expr={:?}, dest={:?})", expr, dest); - - let vt = vec_types_from_expr(bcx, expr); - - return match dest { - Ignore => write_content(bcx, &vt, expr, expr, dest), - SaveIn(lldest) => { - // lldest will have type *[T x N], but we want the type *T, - // so use GEP to convert: - let lldest = StructGEP(bcx, lldest, 0); - write_content(bcx, &vt, expr, expr, SaveIn(lldest)) - } - }; -} - -/// &[...] allocates memory on the stack and writes the values into it, returning the vector (the -/// caller must make the reference). "..." is similar except that the memory can be statically -/// allocated and we return a reference (strings are always by-ref). -pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - slice_expr: &hir::Expr, - content_expr: &hir::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { - let fcx = bcx.fcx; - let mut bcx = bcx; - - debug!("trans_slice_vec(slice_expr={:?})", - slice_expr); - - let vec_ty = node_id_type(bcx, slice_expr.id); - - // Handle the "..." case (returns a slice since strings are always unsized): - if let hir::ExprLit(ref lit) = content_expr.node { - if let ast::LitKind::Str(ref s, _) = lit.node { - let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); - bcx = trans_lit_str(bcx, - content_expr, - s.clone(), - SaveIn(scratch.val)); - return DatumBlock::new(bcx, scratch.to_expr_datum()); - } - } - - // Handle the &[...] case: - let vt = vec_types_from_expr(bcx, content_expr); - let count = elements_required(bcx, content_expr); - debug!(" vt={:?}, count={}", vt, count); - - let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count); - - // Always create an alloca even if zero-sized, to preserve - // the non-null invariant of the inner slice ptr - let llfixed; - // Issue 30018: ensure state is initialized as dropped if necessary. - if fcx.type_needs_drop(vt.unit_ty) { - llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, ""); - } else { - let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop"); - llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, ""); - call_lifetime_start(bcx, llfixed); - }; - - if count > 0 { - // Arrange for the backing array to be cleaned up. - let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id); - fcx.schedule_lifetime_end(cleanup_scope, llfixed); - fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None); - - // Generate the content into the backing array. - // llfixed has type *[T x N], but we want the type *T, - // so use GEP to convert - bcx = write_content(bcx, &vt, slice_expr, content_expr, - SaveIn(StructGEP(bcx, llfixed, 0))); - }; - - immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock() -} - -/// Literal strings translate to slices into static memory. This is different from -/// trans_slice_vstore() above because it doesn't need to copy the content anywhere. -pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lit_expr: &hir::Expr, - str_lit: InternedString, - dest: Dest) - -> Block<'blk, 'tcx> { - debug!("trans_lit_str(lit_expr={:?}, dest={:?})", lit_expr, dest); - - match dest { - Ignore => bcx, - SaveIn(lldest) => { - let bytes = str_lit.len(); - let llbytes = C_uint(bcx.ccx(), bytes); - let llcstr = C_cstr(bcx.ccx(), str_lit, false); - let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx())); - Store(bcx, llcstr, expr::get_dataptr(bcx, lldest)); - Store(bcx, llbytes, expr::get_meta(bcx, lldest)); - bcx - } - } -} - -fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - vt: &VecTypes<'tcx>, - vstore_expr: &hir::Expr, - content_expr: &hir::Expr, - dest: Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("tvec::write_content"); - let fcx = bcx.fcx; - let mut bcx = bcx; - - debug!("write_content(vt={:?}, dest={:?}, vstore_expr={:?})", - vt, dest, vstore_expr); - - match content_expr.node { - hir::ExprLit(ref lit) => { - match lit.node { - ast::LitKind::Str(ref s, _) => { - match dest { - Ignore => return bcx, - SaveIn(lldest) => { - let bytes = s.len(); - let llbytes = C_uint(bcx.ccx(), bytes); - let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false); - if !bcx.unreachable.get() { - base::call_memcpy(&B(bcx), lldest, llcstr, llbytes, 1); - } - return bcx; - } - } - } - _ => { - span_bug!(content_expr.span, "unexpected evec content"); - } - } - } - hir::ExprVec(ref elements) => { - match dest { - Ignore => { - for element in elements { - bcx = expr::trans_into(bcx, &element, Ignore); - } - } - - SaveIn(lldest) => { - let temp_scope = fcx.push_custom_cleanup_scope(); - for (i, element) in elements.iter().enumerate() { - let lleltptr = GEPi(bcx, lldest, &[i]); - debug!("writing index {} with lleltptr={:?}", - i, Value(lleltptr)); - bcx = expr::trans_into(bcx, &element, - SaveIn(lleltptr)); - let scope = cleanup::CustomScope(temp_scope); - // Issue #30822: mark memory as dropped after running destructor - fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None); - } - fcx.pop_custom_cleanup_scope(temp_scope); - } - } - return bcx; - } - hir::ExprRepeat(ref element, ref count_expr) => { - match dest { - Ignore => { - return expr::trans_into(bcx, &element, Ignore); - } - SaveIn(lldest) => { - match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() { - 0 => expr::trans_into(bcx, &element, Ignore), - 1 => expr::trans_into(bcx, &element, SaveIn(lldest)), - count => { - let elem = unpack_datum!(bcx, expr::trans(bcx, &element)); - let bcx = iter_vec_loop(bcx, lldest, vt, - C_uint(bcx.ccx(), count), - |set_bcx, lleltptr, _| { - elem.shallow_copy(set_bcx, lleltptr) - }); - bcx - } - } - } - } - } - _ => { - span_bug!(content_expr.span, "unexpected vec content"); - } - } -} - -fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &hir::Expr) - -> VecTypes<'tcx> { - let vec_ty = node_id_type(bcx, vec_expr.id); - vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx())) -} - -fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>) - -> VecTypes<'tcx> { - VecTypes { - unit_ty: unit_ty, - llunit_ty: type_of::type_of(bcx.ccx(), unit_ty) - } -} - -fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { - //! Figure out the number of elements we need to store this content - - match content_expr.node { - hir::ExprLit(ref lit) => { - match lit.node { - ast::LitKind::Str(ref s, _) => s.len(), - _ => { - span_bug!(content_expr.span, "unexpected evec content") - } - } - }, - hir::ExprVec(ref es) => es.len(), - hir::ExprRepeat(_, ref count_expr) => { - eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() - } - _ => span_bug!(content_expr.span, "unexpected vec content") - } -} - -/// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval` -/// which should be by ref. -pub fn get_fixed_base_and_len(bcx: Block, - llval: ValueRef, - vec_length: usize) - -> (ValueRef, ValueRef) { - let ccx = bcx.ccx(); - - let base = expr::get_dataptr(bcx, llval); - let len = C_uint(ccx, vec_length); - (base, len) -} - -/// Converts a vector into the slice pair. The vector should be stored in `llval` which should be -/// by-reference. If you have a datum, you would probably prefer to call -/// `Datum::get_base_and_len()` which will handle any conversions for you. -pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - llval: ValueRef, - vec_ty: Ty<'tcx>) - -> (ValueRef, ValueRef) { - match vec_ty.sty { - ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n), - ty::TySlice(_) | ty::TyStr => { - let base = Load(bcx, expr::get_dataptr(bcx, llval)); - let len = Load(bcx, expr::get_meta(bcx, llval)); - (base, len) - } - - // Only used for pattern matching. - ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => { - let inner = if type_is_sized(bcx.tcx(), ty) { - Load(bcx, llval) - } else { - llval - }; - get_base_and_len(bcx, inner, ty) - }, - _ => bug!("unexpected type in get_base_and_len"), - } -} - -fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - data_ptr: ValueRef, - vt: &VecTypes<'tcx>, - count: ValueRef, - f: F) - -> Block<'blk, 'tcx> where - F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, -{ - let _icx = push_ctxt("tvec::iter_vec_loop"); - - if bcx.unreachable.get() { - return bcx; - } - - let fcx = bcx.fcx; - let loop_bcx = fcx.new_temp_block("expr_repeat"); - let next_bcx = fcx.new_temp_block("expr_repeat: next"); - - Br(bcx, loop_bcx.llbb, DebugLoc::None); - - let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(), - &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]); - - let bcx = loop_bcx; - - let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 { - data_ptr - } else { - InBoundsGEP(bcx, data_ptr, &[loop_counter]) - }; - let bcx = f(bcx, lleltptr, vt.unit_ty); - let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None); - AddIncomingToPhi(loop_counter, plusone, bcx.llbb); - - let cond_val = ICmp(bcx, llvm::IntULT, plusone, count, DebugLoc::None); - CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None); - - next_bcx -} +use rustc::ty::Ty; pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, data_ptr: ValueRef, @@ -366,24 +29,42 @@ pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("tvec::iter_vec_raw"); let fcx = bcx.fcx; - let vt = vec_types(bcx, unit_ty); - - if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 { + if type_is_zero_size(bcx.ccx(), unit_ty) { // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) - iter_vec_loop(bcx, data_ptr, &vt, len, f) + if bcx.unreachable.get() { + return bcx; + } + + let loop_bcx = fcx.new_block("expr_repeat"); + let next_bcx = fcx.new_block("expr_repeat: next"); + + Br(bcx, loop_bcx.llbb, DebugLoc::None); + + let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(), + &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]); + + let bcx = loop_bcx; + let bcx = f(bcx, data_ptr, unit_ty); + let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None); + AddIncomingToPhi(loop_counter, plusone, bcx.llbb); + + let cond_val = ICmp(bcx, llvm::IntULT, plusone, len, DebugLoc::None); + CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None); + + next_bcx } else { // Calculate the last pointer address we want to handle. let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]); // Now perform the iteration. - let header_bcx = fcx.new_temp_block("iter_vec_loop_header"); + let header_bcx = fcx.new_block("iter_vec_loop_header"); Br(bcx, header_bcx.llbb, DebugLoc::None); let data_ptr = Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]); let not_yet_at_end = ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None); - let body_bcx = fcx.new_temp_block("iter_vec_loop_body"); - let next_bcx = fcx.new_temp_block("iter_vec_next"); + let body_bcx = fcx.new_block("iter_vec_loop_body"); + let next_bcx = fcx.new_block("iter_vec_next"); CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None); let body_bcx = f(body_bcx, data_ptr, unit_ty); AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, From 119508cdb4051280a6b89d4ba1a8157f1113d379 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 23 Aug 2016 10:39:30 +0300 Subject: [PATCH 251/768] Remove drop flags from structs and enums implementing Drop. --- src/liballoc/arc.rs | 19 +- src/liballoc/lib.rs | 2 +- src/liballoc/raw_vec.rs | 11 +- src/liballoc/rc.rs | 38 ++-- src/libcollections/lib.rs | 2 +- src/libcollections/vec.rs | 10 +- src/libcore/intrinsics.rs | 13 -- src/libcore/mem.rs | 71 ------- src/libcore/ptr.rs | 15 -- src/librustc/session/config.rs | 6 - src/librustc/ty/layout.rs | 39 +--- src/librustc/ty/mod.rs | 24 +-- src/librustc_lint/builtin.rs | 55 +----- src/librustc_lint/lib.rs | 2 +- src/librustc_trans/adt.rs | 167 ++++------------ src/librustc_trans/base.rs | 158 +-------------- src/librustc_trans/common.rs | 13 -- src/librustc_trans/debuginfo/metadata.rs | 6 +- src/librustc_trans/glue.rs | 181 +++++++++++++++--- src/librustc_trans/intrinsic.rs | 3 - src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/tvec.rs | 85 ++++---- src/librustc_typeck/check/intrinsic.rs | 2 +- src/libstd/collections/hash/table.rs | 4 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 11 +- src/libsyntax/lib.rs | 1 - src/libsyntax/ptr.rs | 20 +- .../lint-no-drop-on-repr-extern.rs | 61 ------ .../compile-fail/unsafe_no_drop_flag-gate.rs | 23 --- src/test/run-pass/auxiliary/issue-10028.rs | 3 - src/test/run-pass/drop-flag-sanity-check.rs | 68 ------- .../run-pass/drop-flag-skip-sanity-check.rs | 67 ------- src/test/run-pass/intrinsic-move-val.rs | 9 - src/test/run-pass/issue-10734.rs | 4 - src/test/run-pass/issue-2895.rs | 4 +- src/test/run-pass/mir_cross_crate.rs | 27 --- ...drop-flag-size.rs => no-drop-flag-size.rs} | 5 +- .../run-pass/zero-size-type-destructors.rs | 5 - 39 files changed, 304 insertions(+), 934 deletions(-) delete mode 100644 src/test/compile-fail/lint-no-drop-on-repr-extern.rs delete mode 100644 src/test/compile-fail/unsafe_no_drop_flag-gate.rs delete mode 100644 src/test/run-pass/drop-flag-sanity-check.rs delete mode 100644 src/test/run-pass/drop-flag-skip-sanity-check.rs delete mode 100644 src/test/run-pass/mir_cross_crate.rs rename src/test/run-pass/{attr-no-drop-flag-size.rs => no-drop-flag-size.rs} (83%) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 64b780413f884..9c9f1e7b9de07 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -121,7 +121,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// } /// ``` -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { ptr: Shared>, @@ -147,7 +147,7 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} /// nodes behind strong `Arc` pointers, and then storing the parent pointers /// as `Weak` pointers. -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -559,15 +559,6 @@ impl Drop for Arc { #[unsafe_destructor_blind_to_params] #[inline] fn drop(&mut self) { - // 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 (); - - if thin as usize == mem::POST_DROP_USIZE { - return; - } - // Because `fetch_sub` is already atomic, we do not need to synchronize // with other threads unless we are going to delete the object. This // same logic applies to the below `fetch_sub` to the `weak` count. @@ -755,12 +746,6 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { let ptr = *self.ptr; - let thin = ptr as *const (); - - // see comments above for why this check is here - if thin as usize == mem::POST_DROP_USIZE { - return; - } // If we find out that we were the last weak pointer, then its time to // deallocate the data entirely. See the discussion in Arc::drop() about diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 90037f813cda6..d9fd2d92710dc 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,7 +88,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(unique)] -#![feature(unsafe_no_drop_flag, filling_drop)] +#![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![feature(unsize)] #![cfg_attr(not(test), feature(fused, raw, fn_traits, placement_new_protocol))] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index cdb70ce57708a..23542215fa890 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -44,7 +44,7 @@ use core::cmp; /// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] pub struct RawVec { ptr: Unique, cap: usize, @@ -546,13 +546,6 @@ impl RawVec { mem::forget(self); output } - - /// This is a stupid name in the hopes that someone will find this in the - /// not too distant future and remove it with the rest of - /// #[unsafe_no_drop_flag] - pub fn unsafe_no_drop_flag_needs_drop(&self) -> bool { - self.cap != mem::POST_DROP_USIZE - } } impl Drop for RawVec { @@ -560,7 +553,7 @@ impl Drop for RawVec { /// Frees the memory owned by the RawVec *without* trying to Drop its contents. fn drop(&mut self) { let elem_size = mem::size_of::(); - if elem_size != 0 && self.cap != 0 && self.unsafe_no_drop_flag_needs_drop() { + if elem_size != 0 && self.cap != 0 { let align = mem::align_of::(); let num_bytes = elem_size * self.cap; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 3a158240c3a26..8e43e9eec1608 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -182,7 +182,7 @@ struct RcBox { /// A reference-counted pointer type over an immutable value. /// /// See the [module level documentation](./index.html) for more details. -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { ptr: Shared>, @@ -466,21 +466,18 @@ impl Drop for Rc { fn drop(&mut self) { unsafe { let ptr = *self.ptr; - let thin = ptr as *const (); - if thin as usize != mem::POST_DROP_USIZE { - self.dec_strong(); - if self.strong() == 0 { - // destroy the contained object - ptr::drop_in_place(&mut (*ptr).value); + self.dec_strong(); + if self.strong() == 0 { + // destroy the contained object + ptr::drop_in_place(&mut (*ptr).value); - // remove the implicit "strong weak" pointer now that we've - // destroyed the contents. - self.dec_weak(); + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. + self.dec_weak(); - if self.weak() == 0 { - deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) - } + if self.weak() == 0 { + deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } } @@ -724,7 +721,7 @@ impl From for Rc { /// dropped. /// /// See the [module level documentation](./index.html) for more. -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -825,15 +822,12 @@ impl Drop for Weak { fn drop(&mut self) { unsafe { let ptr = *self.ptr; - let thin = ptr as *const (); - if thin as usize != mem::POST_DROP_USIZE { - self.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if self.weak() == 0 { - deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) - } + self.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if self.weak() == 0 { + deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 2781059c1d543..c5a921693475a 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -52,7 +52,7 @@ #![feature(step_by)] #![feature(unicode)] #![feature(unique)] -#![feature(unsafe_no_drop_flag)] +#![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![cfg_attr(test, feature(rand, test))] #![no_std] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a866cdeb7ec3e..876314613f523 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -268,7 +268,7 @@ use super::range::RangeArgument; /// Vec does not currently guarantee the order in which elements are dropped /// (the order has changed in the past, and may change again). /// -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Vec { buf: RawVec, @@ -1600,11 +1600,9 @@ impl Ord for Vec { impl Drop for Vec { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { - if self.buf.unsafe_no_drop_flag_needs_drop() { - unsafe { - // use drop for [T] - ptr::drop_in_place(&mut self[..]); - } + unsafe { + // use drop for [T] + ptr::drop_in_place(&mut self[..]); } // RawVec handles deallocation } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index c645608dda790..3c2c5abcb2821 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -244,19 +244,6 @@ extern "rust-intrinsic" { /// crate it is invoked in. pub fn type_id() -> u64; - /// Creates a value initialized to so that its drop flag, - /// if any, says that it has been dropped. - /// - /// `init_dropped` is unsafe because it returns a datum with all - /// of its bytes set to the drop flag, which generally does not - /// correspond to a valid value. - /// - /// This intrinsic is likely to be deprecated in the future when - /// Rust moves to non-zeroing dynamic drop (and thus removes the - /// embedded drop flags that are being established by this - /// intrinsic). - pub fn init_dropped() -> T; - /// Creates a value initialized to zero. /// /// `init` is unsafe because it returns a zeroed-out datum, diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 5c2179ccf33a1..6ebbe97d064a2 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -241,27 +241,6 @@ pub unsafe fn zeroed() -> T { intrinsics::init() } -/// Creates a value initialized to an unspecified series of bytes. -/// -/// The byte sequence usually indicates that the value at the memory -/// in question has been dropped. Thus, *if* T carries a drop flag, -/// any associated destructor will not be run when the value falls out -/// of scope. -/// -/// Some code at one time used the `zeroed` function above to -/// accomplish this goal. -/// -/// This function is expected to be deprecated with the transition -/// to non-zeroing drop. -#[inline] -#[unstable(feature = "filling_drop", issue = "5016")] -pub unsafe fn dropped() -> T { - #[inline(always)] - unsafe fn dropped_impl() -> T { intrinsics::init_dropped() } - - dropped_impl() -} - /// Bypasses Rust's normal memory-initialization checks by pretending to /// produce a value of type T, while doing nothing at all. /// @@ -518,56 +497,6 @@ pub fn replace(dest: &mut T, mut src: T) -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) { } -macro_rules! repeat_u8_as_u16 { - ($name:expr) => { (($name as u16) << 8 | - ($name as u16)) } -} -macro_rules! repeat_u8_as_u32 { - ($name:expr) => { (($name as u32) << 24 | - ($name as u32) << 16 | - ($name as u32) << 8 | - ($name as u32)) } -} -macro_rules! repeat_u8_as_u64 { - ($name:expr) => { ((repeat_u8_as_u32!($name) as u64) << 32 | - (repeat_u8_as_u32!($name) as u64)) } -} - -// NOTE: Keep synchronized with values used in librustc_trans::trans::adt. -// -// In particular, the POST_DROP_U8 marker must never equal the -// DTOR_NEEDED_U8 marker. -// -// For a while pnkfelix was using 0xc1 here. -// But having the sign bit set is a pain, so 0x1d is probably better. -// -// And of course, 0x00 brings back the old world of zero'ing on drop. -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_U8: u8 = 0x1d; -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_U16: u16 = repeat_u8_as_u16!(POST_DROP_U8); -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8); -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8); - -#[cfg(target_pointer_width = "16")] -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_USIZE: usize = POST_DROP_U16 as usize; -#[cfg(target_pointer_width = "32")] -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize; -#[cfg(target_pointer_width = "64")] -#[unstable(feature = "filling_drop", issue = "5016")] -#[allow(missing_docs)] -pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize; - /// Interprets `src` as `&U`, and then reads `src` without moving the contained /// value. /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 8cb485872b3f3..dd76843793332 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -140,21 +140,6 @@ pub unsafe fn read(src: *const T) -> T { tmp } -#[allow(missing_docs)] -#[inline(always)] -#[unstable(feature = "filling_drop", - reason = "may play a larger role in std::ptr future extensions", - issue = "5016")] -pub unsafe fn read_and_drop(dest: *mut T) -> T { - // Copy the data out from `dest`: - let tmp = read(&*dest); - - // Now mark `dest` as dropped: - write_bytes(dest, mem::POST_DROP_U8, 1); - - tmp -} - /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 852ff091259d1..a991a1a9ba4b5 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -889,8 +889,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "adds unstable command line options to rustc interface"), force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], "force overflow checks on or off"), - force_dropflag_checks: Option = (None, parse_opt_bool, [TRACKED], - "force drop flag checks on or off"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments"), enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED], @@ -2427,10 +2425,6 @@ mod tests { opts.debugging_opts.force_overflow_checks = Some(true); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); - opts = reference.clone(); - opts.debugging_opts.force_dropflag_checks = Some(true); - assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); - opts = reference.clone(); opts.debugging_opts.enable_nonzeroing_move_hints = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 195cece6bc4e0..1ede8545e08e8 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -891,17 +891,6 @@ impl<'a, 'gcx, 'tcx> Layout { let mut st = Struct::new(dl, packed); st.extend(dl, fields, ty)?; - // FIXME(16758) don't add a drop flag to unsized structs, as it - // won't actually be in the location we say it is because it'll be after - // the unsized field. Several other pieces of code assume that the unsized - // field is definitely the last one. - if def.dtor_kind().has_drop_flag() && - ty.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { - st.extend(dl, Some(Ok(&Scalar { - value: Int(I8), - non_zero: false - })).into_iter(), ty)?; - } Univariant { variant: st, non_zero: Some(def.did) == tcx.lang_items.non_zero() @@ -911,24 +900,18 @@ impl<'a, 'gcx, 'tcx> Layout { let hint = *tcx.lookup_repr_hints(def.did).get(0) .unwrap_or(&attr::ReprAny); - let dtor = def.dtor_kind().has_drop_flag(); - let drop_flag = if dtor { - Some(Scalar { value: Int(I8), non_zero: false }) - } else { - None - }; - if def.variants.is_empty() { // Uninhabitable; represent as unit // (Typechecking will reject discriminant-sizing attrs.) assert_eq!(hint, attr::ReprAny); - let mut st = Struct::new(dl, false); - st.extend(dl, drop_flag.iter().map(Ok), ty)?; - return success(Univariant { variant: st, non_zero: false }); + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false + }); } - if !dtor && def.variants.iter().all(|v| v.fields.is_empty()) { + if def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike let (mut min, mut max) = (i64::MAX, i64::MIN); for v in &def.variants { @@ -964,7 +947,7 @@ impl<'a, 'gcx, 'tcx> Layout { field.ty(tcx, substs).layout(infcx) }); let mut st = Struct::new(dl, false); - st.extend(dl, fields.chain(drop_flag.iter().map(Ok)), ty)?; + st.extend(dl, fields, ty)?; return success(Univariant { variant: st, non_zero: false }); } @@ -973,7 +956,7 @@ impl<'a, 'gcx, 'tcx> Layout { v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() }).collect::>(); - if !dtor && variants.len() == 2 && hint == attr::ReprAny { + if variants.len() == 2 && hint == attr::ReprAny { // Nullable pointer optimization for discr in 0..2 { let other_fields = variants[1 - discr].iter().map(|ty| { @@ -1045,8 +1028,7 @@ impl<'a, 'gcx, 'tcx> Layout { Ok(field) }); let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields) - .chain(drop_flag.iter().map(Ok)), ty)?; + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; size = cmp::max(size, st.min_size()); align = align.max(st.align); Ok(st) @@ -1277,11 +1259,6 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { return Err(err); } - // If there's a drop flag, it can't be just a pointer. - if def.dtor_kind().has_drop_flag() { - return Err(err); - } - // Get a zero-sized variant or a pointer newtype. let zero_or_ptr_variant = |i: usize| { let fields = def.variants[i].fields.iter().map(|field| { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1f747ddfb2959..6c82157c8ca7c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -122,23 +122,16 @@ pub struct CrateAnalysis<'a> { #[derive(Copy, Clone)] pub enum DtorKind { NoDtor, - TraitDtor(bool) + TraitDtor } impl DtorKind { pub fn is_present(&self) -> bool { match *self { - TraitDtor(..) => true, + TraitDtor => true, _ => false } } - - pub fn has_drop_flag(&self) -> bool { - match self { - &NoDtor => false, - &TraitDtor(flag) => flag - } - } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -1440,7 +1433,6 @@ bitflags! { const IS_PHANTOM_DATA = 1 << 3, const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 5, - const IS_NO_DROP_FLAG = 1 << 6, } } @@ -1558,9 +1550,6 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { if attr::contains_name(&attrs, "fundamental") { flags = flags | AdtFlags::IS_FUNDAMENTAL; } - if attr::contains_name(&attrs, "unsafe_no_drop_flag") { - flags = flags | AdtFlags::IS_NO_DROP_FLAG; - } if tcx.lookup_simd(did) { flags = flags | AdtFlags::IS_SIMD; } @@ -1627,10 +1616,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { /// Returns whether this type has a destructor. pub fn has_dtor(&self) -> bool { - match self.dtor_kind() { - NoDtor => false, - TraitDtor(..) => true - } + self.dtor_kind().is_present() } /// Asserts this is a struct and returns the struct's unique @@ -1710,9 +1696,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn dtor_kind(&self) -> DtorKind { match self.destructor.get() { - Some(_) => { - TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG)) - } + Some(_) => TraitDtor, None => NoDtor, } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 61d927239828b..b4a2648b5dca7 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -45,7 +45,7 @@ use std::collections::HashSet; use syntax::{ast}; use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; -use syntax_pos::{self, Span}; +use syntax_pos::Span; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::FnKind; @@ -1154,56 +1154,3 @@ impl LateLintPass for UnstableFeatures { } } } - -/// Lints for attempts to impl Drop on types that have `#[repr(C)]` -/// attribute (see issue #24585). -#[derive(Copy, Clone)] -pub struct DropWithReprExtern; - -declare_lint! { - DROP_WITH_REPR_EXTERN, - Warn, - "use of #[repr(C)] on a type that implements Drop" -} - -impl LintPass for DropWithReprExtern { - fn get_lints(&self) -> LintArray { - lint_array!(DROP_WITH_REPR_EXTERN) - } -} - -impl LateLintPass for DropWithReprExtern { - fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) { - let drop_trait = match ctx.tcx.lang_items.drop_trait() { - Some(id) => ctx.tcx.lookup_trait_def(id), None => { return } - }; - drop_trait.for_each_impl(ctx.tcx, |drop_impl_did| { - if !drop_impl_did.is_local() { - return; - } - let dtor_self_type = ctx.tcx.lookup_item_type(drop_impl_did).ty; - - match dtor_self_type.sty { - ty::TyEnum(self_type_def, _) | - ty::TyStruct(self_type_def, _) => { - let self_type_did = self_type_def.did; - let hints = ctx.tcx.lookup_repr_hints(self_type_did); - if hints.iter().any(|attr| *attr == attr::ReprExtern) && - self_type_def.dtor_kind().has_drop_flag() { - let drop_impl_span = ctx.tcx.map.def_id_span(drop_impl_did, - syntax_pos::DUMMY_SP); - let self_defn_span = ctx.tcx.map.def_id_span(self_type_did, - syntax_pos::DUMMY_SP); - ctx.span_lint_note(DROP_WITH_REPR_EXTERN, - drop_impl_span, - "implementing Drop adds hidden state to types, \ - possibly conflicting with `#[repr(C)]`", - self_defn_span, - "the `#[repr(C)]` attribute is attached here"); - } - } - _ => {} - } - }) - } -} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index cb0036eb5b034..1a4330f58c3cd 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -127,7 +127,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnconditionalRecursion, InvalidNoMangleItems, PluginAsLibrary, - DropWithReprExtern, MutableTransmutes, ); @@ -218,4 +217,5 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // This was renamed to raw_pointer_derive, which was then removed, // so it is also considered removed store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok"); + store.register_removed("drop_with_repr_extern", "drop flags have been removed"); } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index c0841bb167341..2fb7a69d36186 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -72,48 +72,16 @@ pub enum BranchKind { type Hint = attr::ReprAttr; -// Representation of the context surrounding an unsized type. I want -// to be able to track the drop flags that are injected by trans. -#[derive(Clone, Copy, PartialEq, Debug)] -pub struct TypeContext { - prefix: Type, - needs_drop_flag: bool, -} - -impl TypeContext { - pub fn prefix(&self) -> Type { self.prefix } - pub fn needs_drop_flag(&self) -> bool { self.needs_drop_flag } - - fn direct(t: Type) -> TypeContext { - TypeContext { prefix: t, needs_drop_flag: false } - } - fn may_need_drop_flag(t: Type, needs_drop_flag: bool) -> TypeContext { - TypeContext { prefix: t, needs_drop_flag: needs_drop_flag } - } -} - /// Representations. #[derive(Eq, PartialEq, Debug)] pub enum Repr<'tcx> { /// C-like enums; basically an int. CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType) /// Single-case variants, and structs/tuples/records. - /// - /// Structs with destructors need a dynamic destroyedness flag to - /// avoid running the destructor too many times; this is included - /// in the `Struct` if present. - /// (The flag if nonzero, represents the initialization value to use; - /// if zero, then use no flag at all.) - Univariant(Struct<'tcx>, u8), + Univariant(Struct<'tcx>), /// General-case enums: for each case there is a struct, and they /// all start with a field for the discriminant. - /// - /// Types with destructors need a dynamic destroyedness flag to - /// avoid running the destructor too many times; the last argument - /// indicates whether such a flag is present. - /// (The flag, if nonzero, represents the initialization value to use; - /// if zero, then use no flag at all.) - General(IntType, Vec>, u8), + General(IntType, Vec>), /// Two cases distinguished by a nullable pointer: the case with discriminant /// `nndiscr` must have single field which is known to be nonnull due to its type. /// The other case is known to be zero sized. Hence we represent the enum @@ -194,57 +162,36 @@ pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, repr } -fn dtor_to_init_u8(dtor: bool) -> u8 { - if dtor { 1 } else { 0 } -} - -pub trait GetDtorType<'tcx> { fn dtor_type(self) -> Ty<'tcx>; } -impl<'a, 'tcx> GetDtorType<'tcx> for TyCtxt<'a, 'tcx, 'tcx> { - fn dtor_type(self) -> Ty<'tcx> { self.types.u8 } -} - fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Repr<'tcx> { match t.sty { ty::TyTuple(ref elems) => { - Univariant(mk_struct(cx, &elems[..], false, t), 0) + Univariant(mk_struct(cx, &elems[..], false, t)) } ty::TyStruct(def, substs) => { - let mut ftys = def.struct_variant().fields.iter().map(|field| { + let ftys = def.struct_variant().fields.iter().map(|field| { monomorphize::field_ty(cx.tcx(), substs, field) }).collect::>(); let packed = cx.tcx().lookup_packed(def.did); - // FIXME(16758) don't add a drop flag to unsized structs, as it - // won't actually be in the location we say it is because it'll be after - // the unsized field. Several other pieces of code assume that the unsized - // field is definitely the last one. - let dtor = def.dtor_kind().has_drop_flag() && type_is_sized(cx.tcx(), t); - if dtor { - ftys.push(cx.tcx().dtor_type()); - } - Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor)) + Univariant(mk_struct(cx, &ftys[..], packed, t)) } ty::TyClosure(_, ref substs) => { - Univariant(mk_struct(cx, &substs.upvar_tys, false, t), 0) + Univariant(mk_struct(cx, &substs.upvar_tys, false, t)) } ty::TyEnum(def, substs) => { let cases = get_cases(cx.tcx(), def, substs); let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) .unwrap_or(&attr::ReprAny); - let dtor = def.dtor_kind().has_drop_flag(); - if cases.is_empty() { // Uninhabitable; represent as unit // (Typechecking will reject discriminant-sizing attrs.) assert_eq!(hint, attr::ReprAny); - let ftys = if dtor { vec!(cx.tcx().dtor_type()) } else { vec!() }; - return Univariant(mk_struct(cx, &ftys[..], false, t), - dtor_to_init_u8(dtor)); + return Univariant(mk_struct(cx, &[], false, t)); } - if !dtor && cases.iter().all(|c| c.tys.is_empty()) { + if cases.iter().all(|c| c.tys.is_empty()) { // All bodies empty -> intlike let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); let bounds = IntBounds { @@ -266,13 +213,10 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if cases.len() == 1 && hint == attr::ReprAny { // Equivalent to a struct/tuple/newtype. - let mut ftys = cases[0].tys.clone(); - if dtor { ftys.push(cx.tcx().dtor_type()); } - return Univariant(mk_struct(cx, &ftys[..], false, t), - dtor_to_init_u8(dtor)); + return Univariant(mk_struct(cx, &cases[0].tys, false, t)); } - if !dtor && cases.len() == 2 && hint == attr::ReprAny { + if cases.len() == 2 && hint == attr::ReprAny { // Nullable pointer optimization let mut discr = 0; while discr < 2 { @@ -315,7 +259,6 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields : Vec<_> = cases.iter().map(|c| { let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); ftys.extend_from_slice(&c.tys); - if dtor { ftys.push(cx.tcx().dtor_type()); } mk_struct(cx, &ftys, false, t) }).collect(); @@ -377,13 +320,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields : Vec<_> = cases.iter().map(|c| { let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); ftys.extend_from_slice(&c.tys); - if dtor { ftys.push(cx.tcx().dtor_type()); } mk_struct(cx, &ftys[..], false, t) }).collect(); ensure_enum_fits_in_address_space(cx, &fields[..], t); - General(ity, fields, dtor_to_init_u8(dtor)) + General(ity, fields) } _ => bug!("adt::represent_type called on non-ADT type: {}", t) } @@ -681,9 +623,7 @@ fn ensure_enum_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, /// and fill in the actual contents in a second pass to prevent /// unbounded recursion; see also the comments in `trans::type_of`. pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>) -> Type { - let c = generic_type_of(cx, r, None, false, false, false); - assert!(!c.needs_drop_flag); - c.prefix + generic_type_of(cx, r, None, false, false) } @@ -692,25 +632,19 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>) -> Type { // are going to get the wrong type (it will not include the unsized parts of it). pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, dst: bool) -> Type { - let c = generic_type_of(cx, r, None, true, dst, false); - assert!(!c.needs_drop_flag); - c.prefix -} -pub fn sizing_type_context_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - r: &Repr<'tcx>, dst: bool) -> TypeContext { - generic_type_of(cx, r, None, true, dst, true) + generic_type_of(cx, r, None, true, dst) } + pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, name: &str) -> Type { - let c = generic_type_of(cx, r, Some(name), false, false, false); - assert!(!c.needs_drop_flag); - c.prefix + generic_type_of(cx, r, Some(name), false, false) } + pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, llty: &mut Type) { match *r { CEnum(..) | General(..) | RawNullablePointer { .. } => { } - Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => + Univariant(ref st) | StructWrappedNullablePointer { nonnull: ref st, .. } => llty.set_struct_body(&struct_llfields(cx, st, false, false), st.packed) } @@ -720,50 +654,40 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, name: Option<&str>, sizing: bool, - dst: bool, - delay_drop_flag: bool) -> TypeContext { - debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {} delay_drop_flag: {}", - r, name, sizing, dst, delay_drop_flag); + dst: bool) -> Type { + debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {}", + r, name, sizing, dst); match *r { - CEnum(ity, _, _) => TypeContext::direct(ll_inttype(cx, ity)), + CEnum(ity, _, _) => ll_inttype(cx, ity), RawNullablePointer { nnty, .. } => - TypeContext::direct(type_of::sizing_type_of(cx, nnty)), + type_of::sizing_type_of(cx, nnty), StructWrappedNullablePointer { nonnull: ref st, .. } => { match name { None => { - TypeContext::direct( - Type::struct_(cx, &struct_llfields(cx, st, sizing, dst), - st.packed)) + Type::struct_(cx, &struct_llfields(cx, st, sizing, dst), + st.packed) } Some(name) => { assert_eq!(sizing, false); - TypeContext::direct(Type::named_struct(cx, name)) + Type::named_struct(cx, name) } } } - Univariant(ref st, dtor_needed) => { - let dtor_needed = dtor_needed != 0; + Univariant(ref st) => { match name { None => { - let mut fields = struct_llfields(cx, st, sizing, dst); - if delay_drop_flag && dtor_needed { - fields.pop(); - } - TypeContext::may_need_drop_flag( - Type::struct_(cx, &fields, - st.packed), - delay_drop_flag && dtor_needed) + let fields = struct_llfields(cx, st, sizing, dst); + Type::struct_(cx, &fields, st.packed) } Some(name) => { // Hypothesis: named_struct's can never need a // drop flag. (... needs validation.) assert_eq!(sizing, false); - TypeContext::direct(Type::named_struct(cx, name)) + Type::named_struct(cx, name) } } } - General(ity, ref sts, dtor_needed) => { - let dtor_needed = dtor_needed != 0; + General(ity, ref sts) => { // We need a representation that has: // * The alignment of the most-aligned field // * The size of the largest variant (rounded up to that alignment) @@ -795,25 +719,18 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; assert_eq!(machine::llalign_of_min(cx, fill_ty), align); assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly - let mut fields: Vec = + let fields: Vec = [discr_ty, Type::array(&discr_ty, (padded_discr_size - discr_size)/discr_size), fill_ty].iter().cloned().collect(); - if delay_drop_flag && dtor_needed { - fields.pop(); - } match name { None => { - TypeContext::may_need_drop_flag( - Type::struct_(cx, &fields[..], false), - delay_drop_flag && dtor_needed) + Type::struct_(cx, &fields[..], false) } Some(name) => { let mut llty = Type::named_struct(cx, name); llty.set_struct_body(&fields[..], false); - TypeContext::may_need_drop_flag( - llty, - delay_drop_flag && dtor_needed) + llty } } } @@ -852,7 +769,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool { match *r { CEnum(ity, _, _) => ity.is_signed(), - General(ity, _, _) => ity.is_signed(), + General(ity, _) => ity.is_signed(), Univariant(..) => false, RawNullablePointer { .. } => false, StructWrappedNullablePointer { .. } => false, @@ -869,7 +786,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, CEnum(ity, min, max) => { load_discr(bcx, ity, scrutinee, min, max, range_assert) } - General(ity, ref cases, _) => { + General(ity, ref cases) => { let ptr = StructGEP(bcx, scrutinee, 0); load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1), range_assert) @@ -933,7 +850,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr) CEnum(ity, _, _) => { C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true) } - General(ity, _, _) => { + General(ity, _) => { C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true) } Univariant(..) => { @@ -957,11 +874,11 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true), val); } - General(ity, _, _) => { + General(ity, _) => { Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true), StructGEP(bcx, val, 0)); } - Univariant(_, _) => { + Univariant(_) => { assert_eq!(discr, Disr(0)); } RawNullablePointer { nndiscr, nnty, ..} => { @@ -1012,11 +929,11 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, CEnum(..) => { bug!("element access in C-like enum") } - Univariant(ref st, _dtor) => { + Univariant(ref st) => { assert_eq!(discr, Disr(0)); struct_field_ptr(bcx, st, val, ix, false) } - General(_, ref cases, _) => { + General(_, ref cases) => { struct_field_ptr(bcx, &cases[discr.0 as usize], val, ix + 1, true) } RawNullablePointer { nndiscr, ref nullfields, .. } | @@ -1170,7 +1087,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr assert_discr_in_range(ity, min, max, discr); C_integral(ll_inttype(ccx, ity), discr.0, true) } - General(ity, ref cases, _) => { + General(ity, ref cases) => { let case = &cases[discr.0 as usize]; let (max_sz, _) = union_size_and_align(&cases[..]); let lldiscr = C_integral(ll_inttype(ccx, ity), discr.0 as u64, true); @@ -1180,7 +1097,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]); C_struct(ccx, &contents[..], false) } - Univariant(ref st, _dro) => { + Univariant(ref st) => { assert_eq!(discr, Disr(0)); let contents = build_const_struct(ccx, st, vals); C_struct(ccx, &contents[..], st.packed) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 2f215ab113513..e33c04f7e82ed 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -57,8 +57,8 @@ use callee::{Callee}; use common::{Block, C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; use common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; -use common::{CrateContext, Field, FunctionContext}; -use common::{Result, VariantInfo}; +use common::{CrateContext, FunctionContext}; +use common::{Result}; use common::{fulfill_obligation}; use common::{type_is_zero_size, val_ty}; use common; @@ -76,7 +76,6 @@ use partitioning::{self, PartitioningStrategy, CodegenUnit}; use symbol_map::SymbolMap; use symbol_names_test; use trans_item::TransItem; -use tvec; use type_::Type; use type_of; use value::Value; @@ -386,155 +385,6 @@ pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty) } -// Iterates through the elements of a structural type. -pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, - av: ValueRef, - t: Ty<'tcx>, - mut f: F) - -> Block<'blk, 'tcx> - where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx> -{ - let _icx = push_ctxt("iter_structural_ty"); - - fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, - repr: &adt::Repr<'tcx>, - av: adt::MaybeSizedValue, - variant: ty::VariantDef<'tcx>, - substs: &Substs<'tcx>, - f: &mut F) - -> Block<'blk, 'tcx> - where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx> - { - let _icx = push_ctxt("iter_variant"); - let tcx = cx.tcx(); - let mut cx = cx; - - for (i, field) in variant.fields.iter().enumerate() { - let arg = monomorphize::field_ty(tcx, substs, field); - cx = f(cx, - adt::trans_field_ptr(cx, repr, av, Disr::from(variant.disr_val), i), - arg); - } - return cx; - } - - let value = if common::type_is_sized(cx.tcx(), t) { - adt::MaybeSizedValue::sized(av) - } else { - let data = Load(cx, get_dataptr(cx, av)); - let info = Load(cx, get_meta(cx, av)); - adt::MaybeSizedValue::unsized_(data, info) - }; - - let mut cx = cx; - match t.sty { - ty::TyStruct(..) => { - let repr = adt::represent_type(cx.ccx(), t); - let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); - for (i, &Field(_, field_ty)) in fields.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); - - let val = if common::type_is_sized(cx.tcx(), field_ty) { - llfld_a - } else { - let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); - Store(cx, llfld_a, get_dataptr(cx, scratch)); - Store(cx, value.meta, get_meta(cx, scratch)); - scratch - }; - cx = f(cx, val, field_ty); - } - } - ty::TyClosure(_, ref substs) => { - let repr = adt::represent_type(cx.ccx(), t); - for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { - let llupvar = adt::trans_field_ptr(cx, &repr, value, Disr(0), i); - cx = f(cx, llupvar, upvar_ty); - } - } - ty::TyArray(_, n) => { - let base = get_dataptr(cx, value.value); - let len = C_uint(cx.ccx(), n); - let unit_ty = t.sequence_element_type(cx.tcx()); - cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); - } - ty::TySlice(_) | ty::TyStr => { - let unit_ty = t.sequence_element_type(cx.tcx()); - cx = tvec::iter_vec_raw(cx, value.value, unit_ty, value.meta, f); - } - ty::TyTuple(ref args) => { - let repr = adt::represent_type(cx.ccx(), t); - for (i, arg) in args.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr(0), i); - cx = f(cx, llfld_a, *arg); - } - } - ty::TyEnum(en, substs) => { - let fcx = cx.fcx; - let ccx = fcx.ccx; - - let repr = adt::represent_type(ccx, t); - let n_variants = en.variants.len(); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - - match adt::trans_switch(cx, &repr, av, false) { - (adt::BranchKind::Single, None) => { - if n_variants != 0 { - assert!(n_variants == 1); - cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), - &en.variants[0], substs, &mut f); - } - } - (adt::BranchKind::Switch, Some(lldiscrim_a)) => { - cx = f(cx, lldiscrim_a, cx.tcx().types.isize); - - // Create a fall-through basic block for the "else" case of - // the switch instruction we're about to generate. Note that - // we do **not** use an Unreachable instruction here, even - // though most of the time this basic block will never be hit. - // - // When an enum is dropped it's contents are currently - // overwritten to DTOR_DONE, which means the discriminant - // could have changed value to something not within the actual - // range of the discriminant. Currently this function is only - // used for drop glue so in this case we just return quickly - // from the outer function, and any other use case will only - // call this for an already-valid enum in which case the `ret - // void` will never be hit. - let ret_void_cx = fcx.new_block("enum-iter-ret-void"); - RetVoid(ret_void_cx, DebugLoc::None); - let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); - let next_cx = fcx.new_block("enum-iter-next"); - - for variant in &en.variants { - let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", - &variant.disr_val - .to_string())); - let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); - AddCase(llswitch, case_val, variant_cx.llbb); - let variant_cx = iter_variant(variant_cx, - &repr, - value, - variant, - substs, - &mut f); - Br(variant_cx, next_cx.llbb, DebugLoc::None); - } - cx = next_cx; - } - _ => ccx.sess().unimpl("value from adt::trans_switch in iter_structural_ty"), - } - } - _ => { - cx.sess().unimpl(&format!("type in iter_structural_ty: {}", t)) - } - } - return cx; -} - - /// Retrieve the information we are losing (making dynamic) in an unsizing /// adjustment. /// @@ -626,12 +476,12 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let src_repr = adt::represent_type(bcx.ccx(), src_ty); let src_fields = match &*src_repr { - &adt::Repr::Univariant(ref s, _) => &s.fields, + &adt::Repr::Univariant(ref s) => &s.fields, _ => bug!("struct has non-univariant repr"), }; let dst_repr = adt::represent_type(bcx.ccx(), dst_ty); let dst_fields = match &*dst_repr { - &adt::Repr::Univariant(ref s, _) => &s.fields, + &adt::Repr::Univariant(ref s) => &s.fields, _ => bug!("struct has non-univariant repr"), }; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 0823f65a7a1e8..3a456b1dd7968 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -783,19 +783,6 @@ pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef { C_integral(Type::i64(ccx), i, false) } -pub fn C_int(ccx: &CrateContext, i: I) -> ValueRef { - let v = i.as_i64(); - - let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type()); - - if bit_size < 64 { - // make sure it doesn't overflow - assert!(v < (1<<(bit_size-1)) && v >= -(1<<(bit_size-1))); - } - - C_integral(ccx.int_type(), v as u64, true) -} - pub fn C_uint(ccx: &CrateContext, i: I) -> ValueRef { let v = i.as_u64(); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index fb1a5f7eb04f9..bd984a71badea 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1247,7 +1247,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { -> Vec { let adt = &self.enum_type.ty_adt_def().unwrap(); match *self.type_rep { - adt::General(_, ref struct_defs, _) => { + adt::General(_, ref struct_defs) => { let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata .expect("")); struct_defs @@ -1281,7 +1281,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { } }).collect() }, - adt::Univariant(ref struct_def, _) => { + adt::Univariant(ref struct_def) => { assert!(adt.variants.len() <= 1); if adt.variants.is_empty() { @@ -1631,7 +1631,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, adt::RawNullablePointer { .. } | adt::StructWrappedNullablePointer { .. } | adt::Univariant(..) => None, - adt::General(inttype, _, _) => Some(discriminant_type_metadata(inttype)), + adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)), }; let enum_llvm_type = type_of::type_of(cx, enum_type); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index d2784610ff55e..ed61f1f589a03 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -29,9 +29,11 @@ use debuginfo::DebugLoc; use machine::*; use monomorphize; use trans_item::TransItem; +use tvec; use type_of::{type_of, sizing_type_of, align_of}; use type_::Type; use value::Value; +use Disr; use arena::TypedArena; use syntax_pos::DUMMY_SP; @@ -343,10 +345,10 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, // Don't use type_of::sizing_type_of because that expects t to be sized. assert!(!t.is_simd()); let repr = adt::represent_type(ccx, t); - let sizing_type = adt::sizing_type_context_of(ccx, &repr, true); + let sizing_type = adt::sizing_type_of(ccx, &repr, true); debug!("DST {} sizing_type: {:?}", t, sizing_type); - let sized_size = llsize_of_alloc(ccx, sizing_type.prefix()); - let sized_align = llalign_of_min(ccx, sizing_type.prefix()); + let sized_size = llsize_of_alloc(ccx, sizing_type); + let sized_align = llalign_of_min(ccx, sizing_type); debug!("DST {} statically sized prefix size: {} align: {}", t, sized_size, sized_align); let sized_size = C_uint(ccx, sized_size); @@ -366,15 +368,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, // here. But this is where the add would go.) // Return the sum of sizes and max of aligns. - let mut size = bcx.add(sized_size, unsized_size); - - // Issue #27023: If there is a drop flag, *now* we add 1 - // to the size. (We can do this without adding any - // padding because drop flags do not have any alignment - // constraints.) - if sizing_type.needs_drop_flag() { - size = bcx.add(size, C_uint(bcx.ccx(), 1_u64)); - } + let size = bcx.add(sized_size, unsized_size); // Choose max of two known alignments (combined value must // be aligned according to more restrictive of the two). @@ -471,17 +465,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None) } } - ty::TyStruct(def, _) | ty::TyEnum(def, _) => { - match (def.dtor_kind(), skip_dtor) { - (ty::TraitDtor(_), false) => { - trans_struct_drop(bcx, t, v0) - } - (ty::NoDtor, _) | (_, true) => { - // No dtor? Just the default case - iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None)) - } - } - } ty::TyTrait(..) => { // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is @@ -496,15 +479,159 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK DebugLoc::None); bcx } + ty::TyStruct(def, _) | ty::TyEnum(def, _) + if def.dtor_kind().is_present() && !skip_dtor => { + trans_struct_drop(bcx, t, v0) + } _ => { if bcx.fcx.type_needs_drop(t) { - iter_structural_ty(bcx, - v0, - t, - |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None)) + drop_structural_ty(bcx, v0, t) } else { bcx } } } } + +// Iterates through the elements of a structural type, dropping them. +fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, + av: ValueRef, + t: Ty<'tcx>) + -> Block<'blk, 'tcx> { + let _icx = push_ctxt("drop_structural_ty"); + + fn iter_variant<'blk, 'tcx>(cx: Block<'blk, 'tcx>, + repr: &adt::Repr<'tcx>, + av: adt::MaybeSizedValue, + variant: ty::VariantDef<'tcx>, + substs: &Substs<'tcx>) + -> Block<'blk, 'tcx> { + let _icx = push_ctxt("iter_variant"); + let tcx = cx.tcx(); + let mut cx = cx; + + for (i, field) in variant.fields.iter().enumerate() { + let arg = monomorphize::field_ty(tcx, substs, field); + cx = drop_ty(cx, + adt::trans_field_ptr(cx, repr, av, Disr::from(variant.disr_val), i), + arg, DebugLoc::None); + } + return cx; + } + + let value = if type_is_sized(cx.tcx(), t) { + adt::MaybeSizedValue::sized(av) + } else { + let data = Load(cx, get_dataptr(cx, av)); + let info = Load(cx, get_meta(cx, av)); + adt::MaybeSizedValue::unsized_(data, info) + }; + + let mut cx = cx; + match t.sty { + ty::TyStruct(..) => { + let repr = adt::represent_type(cx.ccx(), t); + let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); + for (i, &Field(_, field_ty)) in fields.iter().enumerate() { + let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); + + let val = if type_is_sized(cx.tcx(), field_ty) { + llfld_a + } else { + let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, get_dataptr(cx, scratch)); + Store(cx, value.meta, get_meta(cx, scratch)); + scratch + }; + cx = drop_ty(cx, val, field_ty, DebugLoc::None); + } + } + ty::TyClosure(_, ref substs) => { + let repr = adt::represent_type(cx.ccx(), t); + for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { + let llupvar = adt::trans_field_ptr(cx, &repr, value, Disr(0), i); + cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None); + } + } + ty::TyArray(_, n) => { + let base = get_dataptr(cx, value.value); + let len = C_uint(cx.ccx(), n); + let unit_ty = t.sequence_element_type(cx.tcx()); + cx = tvec::slice_for_each(cx, base, unit_ty, len, + |bb, vv| drop_ty(bb, vv, unit_ty, DebugLoc::None)); + } + ty::TySlice(_) | ty::TyStr => { + let unit_ty = t.sequence_element_type(cx.tcx()); + cx = tvec::slice_for_each(cx, value.value, unit_ty, value.meta, + |bb, vv| drop_ty(bb, vv, unit_ty, DebugLoc::None)); + } + ty::TyTuple(ref args) => { + let repr = adt::represent_type(cx.ccx(), t); + for (i, arg) in args.iter().enumerate() { + let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr(0), i); + cx = drop_ty(cx, llfld_a, *arg, DebugLoc::None); + } + } + ty::TyEnum(en, substs) => { + let fcx = cx.fcx; + let ccx = fcx.ccx; + + let repr = adt::represent_type(ccx, t); + let n_variants = en.variants.len(); + + // NB: we must hit the discriminant first so that structural + // comparison know not to proceed when the discriminants differ. + + match adt::trans_switch(cx, &repr, av, false) { + (adt::BranchKind::Single, None) => { + if n_variants != 0 { + assert!(n_variants == 1); + cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), + &en.variants[0], substs); + } + } + (adt::BranchKind::Switch, Some(lldiscrim_a)) => { + cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); + + // Create a fall-through basic block for the "else" case of + // the switch instruction we're about to generate. Note that + // we do **not** use an Unreachable instruction here, even + // though most of the time this basic block will never be hit. + // + // When an enum is dropped it's contents are currently + // overwritten to DTOR_DONE, which means the discriminant + // could have changed value to something not within the actual + // range of the discriminant. Currently this function is only + // used for drop glue so in this case we just return quickly + // from the outer function, and any other use case will only + // call this for an already-valid enum in which case the `ret + // void` will never be hit. + let ret_void_cx = fcx.new_block("enum-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); + let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); + let next_cx = fcx.new_block("enum-iter-next"); + + for variant in &en.variants { + let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", + &variant.disr_val + .to_string())); + let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); + AddCase(llswitch, case_val, variant_cx.llbb); + let variant_cx = iter_variant(variant_cx, + &repr, + value, + variant, + substs); + Br(variant_cx, next_cx.llbb, DebugLoc::None); + } + cx = next_cx; + } + _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), + } + } + _ => { + cx.sess().unimpl(&format!("type in drop_structural_ty: {}", t)) + } + } + return cx; +} diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index ef06030785af8..afe258f68e49f 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -206,9 +206,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "type_id") => { C_u64(ccx, ccx.tcx().type_id_hash(substs.types[0])) } - (_, "init_dropped") => { - span_bug!(span, "init_dropped intrinsic unsupported"); - } (_, "init") => { let tp_ty = substs.types[0]; if !type_is_zero_size(ccx, tp_ty) { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 6c740a93e2d70..13484cb7a4ece 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -100,7 +100,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let size = C_uint(bcx.ccx(), size); let base = get_dataptr(&bcx, dest.llval); let bcx = bcx.map_block(|block| { - tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| { + tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| { self.store_operand_direct(block, llslot, tr_elem); block }) diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index df4f381f28761..7e4719870cd83 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -18,59 +18,46 @@ use common::*; use debuginfo::DebugLoc; use rustc::ty::Ty; -pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - data_ptr: ValueRef, - unit_ty: Ty<'tcx>, - len: ValueRef, - f: F) - -> Block<'blk, 'tcx> where - F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, +pub fn slice_for_each<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, + data_ptr: ValueRef, + unit_ty: Ty<'tcx>, + len: ValueRef, + f: F) + -> Block<'blk, 'tcx> where + F: FnOnce(Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>, { - let _icx = push_ctxt("tvec::iter_vec_raw"); + let _icx = push_ctxt("tvec::slice_for_each"); let fcx = bcx.fcx; - if type_is_zero_size(bcx.ccx(), unit_ty) { - // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) - if bcx.unreachable.get() { - return bcx; - } - - let loop_bcx = fcx.new_block("expr_repeat"); - let next_bcx = fcx.new_block("expr_repeat: next"); - - Br(bcx, loop_bcx.llbb, DebugLoc::None); - - let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(), - &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]); - - let bcx = loop_bcx; - let bcx = f(bcx, data_ptr, unit_ty); - let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None); - AddIncomingToPhi(loop_counter, plusone, bcx.llbb); + // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) + let zst = type_is_zero_size(bcx.ccx(), unit_ty); + let add = |bcx, a, b| if zst { + Add(bcx, a, b, DebugLoc::None) + } else { + InBoundsGEP(bcx, a, &[b]) + }; - let cond_val = ICmp(bcx, llvm::IntULT, plusone, len, DebugLoc::None); - CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None); + let header_bcx = fcx.new_block("slice_loop_header"); + let body_bcx = fcx.new_block("slice_loop_body"); + let next_bcx = fcx.new_block("slice_loop_next"); - next_bcx + let start = if zst { + C_uint(bcx.ccx(), 0 as usize) } else { - // Calculate the last pointer address we want to handle. - let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]); - - // Now perform the iteration. - let header_bcx = fcx.new_block("iter_vec_loop_header"); - Br(bcx, header_bcx.llbb, DebugLoc::None); - let data_ptr = - Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]); - let not_yet_at_end = - ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None); - let body_bcx = fcx.new_block("iter_vec_loop_body"); - let next_bcx = fcx.new_block("iter_vec_next"); - CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None); - let body_bcx = f(body_bcx, data_ptr, unit_ty); - AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, - &[C_int(bcx.ccx(), 1)]), - body_bcx.llbb); - Br(body_bcx, header_bcx.llbb, DebugLoc::None); - next_bcx - } + data_ptr + }; + let end = add(bcx, start, len); + + Br(bcx, header_bcx.llbb, DebugLoc::None); + let current = Phi(header_bcx, val_ty(start), &[start], &[bcx.llbb]); + + let keep_going = + ICmp(header_bcx, llvm::IntULT, current, end, DebugLoc::None); + CondBr(header_bcx, keep_going, body_bcx.llbb, next_bcx.llbb, DebugLoc::None); + + let body_bcx = f(body_bcx, if zst { data_ptr } else { current }); + let next = add(body_bcx, current, C_uint(bcx.ccx(), 1usize)); + AddIncomingToPhi(current, next, body_bcx.llbb); + Br(body_bcx, header_bcx.llbb, DebugLoc::None); + next_bcx } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index e6da03a903f21..7f9e715b7fafc 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -122,7 +122,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { ], ccx.tcx.types.usize) } "rustc_peek" => (1, vec![param(ccx, 0)], param(ccx, 0)), - "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)), + "init" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()), "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)), diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 02931e5e3890d..8f02c9c7d3de0 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -59,7 +59,7 @@ const EMPTY_BUCKET: u64 = 0; /// around just the "table" part of the hashtable. It enforces some /// invariants at the type level and employs some performance trickery, /// but in general is just a tricked out `Vec>`. -#[unsafe_no_drop_flag] +#[cfg_attr(stage0, unsafe_no_drop_flag)] pub struct RawTable { capacity: usize, size: usize, @@ -1042,7 +1042,7 @@ impl Clone for RawTable { impl Drop for RawTable { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { - if self.capacity == 0 || self.capacity == mem::POST_DROP_USIZE { + if self.capacity == 0 { return; } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d4644a190f4d9..2b15f3dd9455c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,7 +275,7 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] -#![feature(unsafe_no_drop_flag, filling_drop)] +#![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 05a485cefab7e..d746f8e21141f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -164,10 +164,6 @@ declare_features! ( // Allows using `box` in patterns; RFC 469 (active, box_patterns, "1.0.0", Some(29641)), - // Allows using the unsafe_no_drop_flag attribute (unlikely to - // switch to Accepted; see RFC 320) - (active, unsafe_no_drop_flag, "1.0.0", None), - // Allows using the unsafe_destructor_blind_to_params attribute; // RFC 1238 (active, dropck_parametricity, "1.3.0", Some(28498)), @@ -300,7 +296,8 @@ declare_features! ( (removed, quad_precision_float, "1.0.0", None), (removed, struct_inherit, "1.0.0", None), (removed, test_removed_feature, "1.0.0", None), - (removed, visible_private_types, "1.0.0", None) + (removed, visible_private_types, "1.0.0", None), + (removed, unsafe_no_drop_flag, "1.0.0", None) ); declare_features! ( @@ -565,10 +562,6 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat attribute is just used for the Rust test \ suite", cfg_fn!(omit_gdb_pretty_printer_section))), - ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag", - "unsafe_no_drop_flag has unstable semantics \ - and may be removed in the future", - cfg_fn!(unsafe_no_drop_flag))), ("unsafe_destructor_blind_to_params", Normal, Gated("dropck_parametricity", diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index b4311fc007d3d..65bc9f34c9061 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -26,7 +26,6 @@ #![feature(associated_consts)] #![feature(const_fn)] -#![feature(filling_drop)] #![feature(libc)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 9d04cb75daa0e..c3f8a977a659b 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -39,7 +39,7 @@ use std::fmt::{self, Display, Debug}; use std::iter::FromIterator; use std::ops::Deref; -use std::{ptr, slice, vec}; +use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -74,12 +74,22 @@ impl P { pub fn map(mut self, f: F) -> P where F: FnOnce(T) -> T, { + let p: *mut T = &mut *self.ptr; + + // Leak self in case of panic. + // FIXME(eddyb) Use some sort of "free guard" that + // only deallocates, without dropping the pointee, + // in case the call the `f` below ends in a panic. + mem::forget(self); + unsafe { - let p = &mut *self.ptr; - // FIXME(#5016) this shouldn't need to drop-fill to be safe. - ptr::write(p, f(ptr::read_and_drop(p))); + ptr::write(p, f(ptr::read(p))); + + // Recreate self from the raw pointer. + P { + ptr: Box::from_raw(p) + } } - self } } diff --git a/src/test/compile-fail/lint-no-drop-on-repr-extern.rs b/src/test/compile-fail/lint-no-drop-on-repr-extern.rs deleted file mode 100644 index 91e5065517dcc..0000000000000 --- a/src/test/compile-fail/lint-no-drop-on-repr-extern.rs +++ /dev/null @@ -1,61 +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. - -// Check we reject structs that mix a `Drop` impl with `#[repr(C)]`. -// -// As a special case, also check that we do not warn on such structs -// if they also are declared with `#[unsafe_no_drop_flag]` - -#![feature(unsafe_no_drop_flag)] -#![deny(drop_with_repr_extern)] -//~^ NOTE lint level defined here -//~| NOTE lint level defined here - -#[repr(C)] struct As { x: Box } -#[repr(C)] enum Ae { Ae(Box), _None } - -struct Bs { x: Box } -enum Be { Be(Box), _None } - -#[repr(C)] struct Cs { x: Box } -//~^ NOTE the `#[repr(C)]` attribute is attached here - -impl Drop for Cs { fn drop(&mut self) { } } -//~^ ERROR implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]` - -#[repr(C)] enum Ce { Ce(Box), _None } -//~^ NOTE the `#[repr(C)]` attribute is attached here - -impl Drop for Ce { fn drop(&mut self) { } } -//~^ ERROR implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]` - -#[unsafe_no_drop_flag] -#[repr(C)] struct Ds { x: Box } - -impl Drop for Ds { fn drop(&mut self) { } } - -#[unsafe_no_drop_flag] -#[repr(C)] enum De { De(Box), _None } - -impl Drop for De { fn drop(&mut self) { } } - -fn main() { - let a = As { x: Box::new(3) }; - let b = Bs { x: Box::new(3) }; - let c = Cs { x: Box::new(3) }; - let d = Ds { x: Box::new(3) }; - - println!("{:?}", (*a.x, *b.x, *c.x, *d.x)); - - let _a = Ae::Ae(Box::new(3)); - let _b = Be::Be(Box::new(3)); - let _c = Ce::Ce(Box::new(3)); - let _d = De::De(Box::new(3)); -} diff --git a/src/test/compile-fail/unsafe_no_drop_flag-gate.rs b/src/test/compile-fail/unsafe_no_drop_flag-gate.rs deleted file mode 100644 index 542698fd15295..0000000000000 --- a/src/test/compile-fail/unsafe_no_drop_flag-gate.rs +++ /dev/null @@ -1,23 +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. - -pub struct T; - -#[unsafe_no_drop_flag] -//~^ ERROR unsafe_no_drop_flag has unstable semantics and may be removed -pub struct S { - pub x: T, -} - -impl Drop for S { - fn drop(&mut self) {} -} - -pub fn main() {} diff --git a/src/test/run-pass/auxiliary/issue-10028.rs b/src/test/run-pass/auxiliary/issue-10028.rs index a21deb44fcc83..ed42ad6e87527 100644 --- a/src/test/run-pass/auxiliary/issue-10028.rs +++ b/src/test/run-pass/auxiliary/issue-10028.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unsafe_no_drop_flag)] - -#[unsafe_no_drop_flag] pub struct ZeroLengthThingWithDestructor; impl Drop for ZeroLengthThingWithDestructor { fn drop(&mut self) {} diff --git a/src/test/run-pass/drop-flag-sanity-check.rs b/src/test/run-pass/drop-flag-sanity-check.rs deleted file mode 100644 index a8014768d7847..0000000000000 --- a/src/test/run-pass/drop-flag-sanity-check.rs +++ /dev/null @@ -1,68 +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. - -// compile-flags: -Z force-dropflag-checks=on -// ignore-emscripten - -// Quick-and-dirty test to ensure -Z force-dropflag-checks=on works as -// expected. Note that the inlined drop-flag is slated for removal -// (RFC 320); when that happens, the -Z flag and this test should -// simply be removed. -// -// See also drop-flag-skip-sanity-check.rs. - -use std::env; -use std::process::Command; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "test" { - return test(); - } - - let mut p = Command::new(&args[0]).arg("test").spawn().unwrap(); - // The invocation should fail due to the drop-flag sanity check. - assert!(!p.wait().unwrap().success()); -} - -#[derive(Debug)] -struct Corrupted { - x: u8 -} - -impl Drop for Corrupted { - fn drop(&mut self) { println!("dropping"); } -} - -fn test() { - { - let mut c1 = Corrupted { x: 1 }; - let mut c2 = Corrupted { x: 2 }; - unsafe { - let p1 = &mut c1 as *mut Corrupted as *mut u8; - let p2 = &mut c2 as *mut Corrupted as *mut u8; - for i in 0..std::mem::size_of::() { - // corrupt everything, *including the drop flag. - // - // (We corrupt via two different means to safeguard - // against the hypothetical assignment of the - // dtor_needed/dtor_done values to v and v+k. that - // happen to match with one of the corruption values - // below.) - *p1.offset(i as isize) += 2; - *p2.offset(i as isize) += 3; - } - } - // Here, at the end of the scope of `c1` and `c2`, the - // drop-glue should detect the corruption of (at least one of) - // the drop-flags. - } - println!("We should never get here."); -} diff --git a/src/test/run-pass/drop-flag-skip-sanity-check.rs b/src/test/run-pass/drop-flag-skip-sanity-check.rs deleted file mode 100644 index 07a10c8d45443..0000000000000 --- a/src/test/run-pass/drop-flag-skip-sanity-check.rs +++ /dev/null @@ -1,67 +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. - -// compile-flags: -Z force-dropflag-checks=off -// ignore-emscripten no threads support - -// Quick-and-dirty test to ensure -Z force-dropflag-checks=off works as -// expected. Note that the inlined drop-flag is slated for removal -// (RFC 320); when that happens, the -Z flag and this test should -// simply be removed. -// -// See also drop-flag-sanity-check.rs. - -use std::env; -use std::process::Command; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "test" { - return test(); - } - - let s = Command::new(&args[0]).arg("test").status().unwrap(); - // Invocatinn should succeed as drop-flag sanity check is skipped. - assert!(s.success()); -} - -#[derive(Debug)] -struct Corrupted { - x: u8 -} - -impl Drop for Corrupted { - fn drop(&mut self) { println!("dropping"); } -} - -fn test() { - { - let mut c1 = Corrupted { x: 1 }; - let mut c2 = Corrupted { x: 2 }; - unsafe { - let p1 = &mut c1 as *mut Corrupted as *mut u8; - let p2 = &mut c2 as *mut Corrupted as *mut u8; - for i in 0..std::mem::size_of::() { - // corrupt everything, *including the drop flag. - // - // (We corrupt via two different means to safeguard - // against the hypothetical assignment of the - // dtor_needed/dtor_done values to v and v+k. that - // happen to match with one of the corruption values - // below.) - *p1.offset(i as isize) += 2; - *p2.offset(i as isize) += 3; - } - } - // Here, at the end of the scope of `c1` and `c2`, the - // drop-glue should detect the corruption of (at least one of) - // the drop-flags. - } -} diff --git a/src/test/run-pass/intrinsic-move-val.rs b/src/test/run-pass/intrinsic-move-val.rs index eb482b3230a43..ea42b59f1f2b8 100644 --- a/src/test/run-pass/intrinsic-move-val.rs +++ b/src/test/run-pass/intrinsic-move-val.rs @@ -55,15 +55,6 @@ pub fn main() { // compiler is hidden. rusti::move_val_init(&mut y, x); - // In particular, it may be tracked via a drop-flag embedded - // in the value, or via a null pointer, or via - // mem::POST_DROP_USIZE, or (most preferably) via a - // stack-local drop flag. - // - // (This test used to build-in knowledge of how it was - // tracked, and check that the underlying stack slot had been - // set to `mem::POST_DROP_USIZE`.) - // But what we *can* observe is how many times the destructor // for `D` is invoked, and what the last value we saw was // during such a destructor call. We do so after the end of diff --git a/src/test/run-pass/issue-10734.rs b/src/test/run-pass/issue-10734.rs index 3dc96ecde1c07..a521e5d4b6c34 100644 --- a/src/test/run-pass/issue-10734.rs +++ b/src/test/run-pass/issue-10734.rs @@ -8,12 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unsafe_no_drop_flag)] - static mut drop_count: usize = 0; -#[unsafe_no_drop_flag] struct Foo { dropped: bool } diff --git a/src/test/run-pass/issue-2895.rs b/src/test/run-pass/issue-2895.rs index 5587f68bd1854..b0fd0e148c8c2 100644 --- a/src/test/run-pass/issue-2895.rs +++ b/src/test/run-pass/issue-2895.rs @@ -26,11 +26,11 @@ impl Drop for Kitty { #[cfg(target_pointer_width = "64")] pub fn main() { assert_eq!(mem::size_of::(), 8 as usize); - assert_eq!(mem::size_of::(), 16 as usize); + assert_eq!(mem::size_of::(), 8 as usize); } #[cfg(target_pointer_width = "32")] pub fn main() { assert_eq!(mem::size_of::(), 4 as usize); - assert_eq!(mem::size_of::(), 8 as usize); + assert_eq!(mem::size_of::(), 4 as usize); } diff --git a/src/test/run-pass/mir_cross_crate.rs b/src/test/run-pass/mir_cross_crate.rs deleted file mode 100644 index 2cb975b98d2dc..0000000000000 --- a/src/test/run-pass/mir_cross_crate.rs +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -// Tests that MIR trans is used for functions from other crates. - -#![feature(unsafe_no_drop_flag)] - -#[unsafe_no_drop_flag] -struct Foo; - -impl Drop for Foo { - fn drop(&mut self) { - panic!("MIR trans is not enabled for mem::forget"); - } -} - -fn main() { - let x = Foo; - std::mem::forget(x); -} diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/no-drop-flag-size.rs similarity index 83% rename from src/test/run-pass/attr-no-drop-flag-size.rs rename to src/test/run-pass/no-drop-flag-size.rs index 0c464c9bad728..a606a8a9f4b3b 100644 --- a/src/test/run-pass/attr-no-drop-flag-size.rs +++ b/src/test/run-pass/no-drop-flag-size.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unsafe_no_drop_flag)] - use std::mem::size_of; -#[unsafe_no_drop_flag] struct Test { a: T } diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs index e36ae6b11b3c7..18b6c372a5ec2 100644 --- a/src/test/run-pass/zero-size-type-destructors.rs +++ b/src/test/run-pass/zero-size-type-destructors.rs @@ -8,14 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unsafe_no_drop_flag)] - -// ignore-pretty : (#23623) problems when ending with // comments - static mut destructions : isize = 3; pub fn foo() { - #[unsafe_no_drop_flag] struct Foo; impl Drop for Foo { From 25cf8001b1352fdaccdd1d71071c941f99acc2a1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 22:50:55 +0300 Subject: [PATCH 252/768] Remove AST from metadata except for consts and const fns. --- src/librustc/hir/map/mod.rs | 5 +- src/librustc/middle/cstore.rs | 7 +- src/librustc_metadata/astencode.rs | 8 +- src/librustc_metadata/csearch.rs | 5 - src/librustc_metadata/encoder.rs | 26 +-- src/librustc_trans/base.rs | 27 +-- src/librustc_trans/callee.rs | 197 +++++++-------------- src/librustc_trans/common.rs | 34 ---- src/librustc_trans/consts.rs | 12 +- src/librustc_trans/context.rs | 10 -- src/librustc_trans/debuginfo/metadata.rs | 22 +-- src/librustc_trans/debuginfo/mod.rs | 61 ++----- src/librustc_trans/debuginfo/source_loc.rs | 5 +- src/librustc_trans/glue.rs | 4 - src/librustc_trans/inline.rs | 52 ------ src/librustc_trans/intrinsic.rs | 2 +- src/librustc_trans/lib.rs | 1 - src/librustc_trans/monomorphize.rs | 150 +--------------- src/librustc_trans/trans_item.rs | 69 ++------ 19 files changed, 126 insertions(+), 571 deletions(-) delete mode 100644 src/librustc_trans/inline.rs diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 04031fabc5866..5e14bb51ce867 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -315,8 +315,7 @@ impl<'ast> Map<'ast> { RootInlinedParent(parent) => match *parent { InlinedItem::Item(def_id, _) | InlinedItem::TraitItem(def_id, _) | - InlinedItem::ImplItem(def_id, _) | - InlinedItem::Foreign(def_id, _) => + InlinedItem::ImplItem(def_id, _) => return DepNode::MetaData(def_id) }, @@ -940,8 +939,6 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, II::ImplItem(fld.fold_ops.new_def_id(d), ii.map(|ii| fld.fold_impl_item(ii))) } - II::Foreign(d, i) => II::Foreign(fld.fold_ops.new_def_id(d), - i.map(|i| fld.fold_foreign_item(i))) }; let ii = map.forest.inlined_items.alloc(ii); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index abb22783ddc84..92e1b0681cc7e 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -96,8 +96,7 @@ pub enum DefLike { pub enum InlinedItem { Item(DefId /* def-id in source crate */, P), TraitItem(DefId /* impl id */, P), - ImplItem(DefId /* impl id */, P), - Foreign(DefId /* extern item */, P), + ImplItem(DefId /* impl id */, P) } /// A borrowed version of `hir::InlinedItem`. @@ -105,8 +104,7 @@ pub enum InlinedItem { pub enum InlinedItemRef<'a> { Item(DefId, &'a hir::Item), TraitItem(DefId, &'a hir::TraitItem), - ImplItem(DefId, &'a hir::ImplItem), - Foreign(DefId, &'a hir::ForeignItem) + ImplItem(DefId, &'a hir::ImplItem) } /// Item definitions in the currently-compiled crate would have the CrateNum @@ -286,7 +284,6 @@ impl InlinedItem { { match *self { InlinedItem::Item(_, ref i) => visitor.visit_item(&i), - InlinedItem::Foreign(_, ref i) => visitor.visit_foreign_item(&i), InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti), InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii), } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 1ef48e6d6565f..ad52d346857ff 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -79,7 +79,6 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, ii: InlinedItemRef) { let id = match ii { InlinedItemRef::Item(_, i) => i.id, - InlinedItemRef::Foreign(_, i) => i.id, InlinedItemRef::TraitItem(_, ti) => ti.id, InlinedItemRef::ImplItem(_, ii) => ii.id, }; @@ -147,7 +146,6 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, dcx); let name = match *ii { InlinedItem::Item(_, ref i) => i.name, - InlinedItem::Foreign(_, ref i) => i.name, InlinedItem::TraitItem(_, ref ti) => ti.name, InlinedItem::ImplItem(_, ref ii) => ii.name }; @@ -357,9 +355,6 @@ fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) { InlinedItemRef::ImplItem(d, ii) => { InlinedItem::ImplItem(d, P(fold::noop_fold_impl_item(ii.clone(), &mut fld))) } - InlinedItemRef::Foreign(d, i) => { - InlinedItem::Foreign(d, P(fold::noop_fold_foreign_item(i.clone(), &mut fld))) - } }; (ii, fld.id_range) @@ -1208,8 +1203,7 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { let item_node_id = match ii { &InlinedItem::Item(_, ref i) => i.id, &InlinedItem::TraitItem(_, ref ti) => ti.id, - &InlinedItem::ImplItem(_, ref ii) => ii.id, - &InlinedItem::Foreign(_, ref fi) => fi.id + &InlinedItem::ImplItem(_, ref ii) => ii.id }; copy_item_type(dcx, item_node_id, orig_did); diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index f6d698eb969d8..94426dcbf1d8d 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -562,11 +562,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { let inlined_root_node_id = find_inlined_item_root(item.id); cache_inlined_item(def_id, item.id, inlined_root_node_id); } - decoder::FoundAst::Found(&InlinedItem::Foreign(d, ref item)) => { - assert_eq!(d, def_id); - let inlined_root_node_id = find_inlined_item_root(item.id); - cache_inlined_item(def_id, item.id, inlined_root_node_id); - } decoder::FoundAst::FoundParent(parent_did, item) => { let inlined_root_node_id = find_inlined_item_root(item.id); cache_inlined_item(parent_did, item.id, inlined_root_node_id); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 420dfbc58bf19..9a668b69b2eeb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -40,7 +40,6 @@ use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; use std::rc::Rc; use std::u32; -use syntax::abi::Abi; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; use syntax::attr::{self,AttrMetaMethods,AttributeMethods}; use errors::Handler; @@ -626,11 +625,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { if body.is_some() { encode_item_sort(self.rbml_w, 'p'); - encode_inlined_item(ecx, - self.rbml_w, - InlinedItemRef::TraitItem( - trait_def_id, - trait_item)); self.encode_mir(trait_item.id); } else { encode_item_sort(self.rbml_w, 'r'); @@ -728,12 +722,14 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || is_default_impl || attr::requests_inline(&impl_item.attrs); - if needs_inline || sig.constness == hir::Constness::Const { + if sig.constness == hir::Constness::Const { encode_inlined_item( ecx, self.rbml_w, InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), impl_item)); + } + if needs_inline || sig.constness == hir::Constness::Const { self.encode_mir(impl_item.id); } encode_constness(self.rbml_w, sig.constness); @@ -934,8 +930,10 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { encode_name(self.rbml_w, item.name); encode_attributes(self.rbml_w, &item.attrs); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { + if constness == hir::Constness::Const { encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); + } + if needs_inline || constness == hir::Constness::Const { self.encode_mir(item.id); } encode_constness(self.rbml_w, constness); @@ -982,8 +980,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { for v in &enum_definition.variants { encode_variant_id(self.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); } - encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(item.id); // Encode inherent implementations for self enumeration. encode_inherent_implementations(ecx, self.rbml_w, def_id); @@ -1019,9 +1015,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { needs to know*/ self.encode_struct_fields(variant); - encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(item.id); - // Encode inherent implementations for self structure. encode_inherent_implementations(ecx, self.rbml_w, def_id); @@ -1265,7 +1258,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { let ecx = self.ecx(); debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); - let abi = ecx.tcx.map.get_foreign_abi(nitem.id); encode_def_id_and_key(ecx, self.rbml_w, def_id); let parent_id = ecx.tcx.map.get_parent(nitem.id); @@ -1276,12 +1268,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { encode_family(self.rbml_w, FN_FAMILY); self.encode_bounds_and_type_for_item(nitem.id); encode_name(self.rbml_w, nitem.name); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - encode_inlined_item(ecx, - self.rbml_w, - InlinedItemRef::Foreign(def_id, nitem)); - self.encode_mir(nitem.id); - } encode_attributes(self.rbml_w, &nitem.attrs); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index e33c04f7e82ed..165884c8f55a2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -66,7 +66,6 @@ use consts; use context::{SharedCrateContext, CrateContextList}; use debuginfo::{self, DebugLoc}; use declare; -use inline; use machine; use machine::{llalign_of_min, llsize_of}; use meth; @@ -949,14 +948,17 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { false }; - let debug_context = if let (false, Some((instance, sig, abi))) = (no_debug, definition) { - debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl) + let mir = def_id.and_then(|id| ccx.get_mir(id)); + + let debug_context = if let (false, Some((instance, sig, abi)), &Some(ref mir)) = + (no_debug, definition, &mir) { + debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl, mir) } else { debuginfo::empty_function_debug_context(ccx) }; FunctionContext { - mir: def_id.and_then(|id| ccx.get_mir(id)), + mir: mir, llfn: llfndecl, llretslotptr: Cell::new(None), param_env: ccx.tcx().empty_parameter_environment(), @@ -1134,8 +1136,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let sig = ccx.tcx().normalize_associated_type(&sig); let abi = fn_ty.fn_abi(); - let local_instance = inline::maybe_inline_instance(ccx, instance); - let lldecl = match ccx.instances().borrow().get(&local_instance) { + let lldecl = match ccx.instances().borrow().get(&instance) { Some(&val) => val, None => bug!("Instance `{:?}` not already declared", instance) }; @@ -1144,12 +1145,15 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance } pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - ctor_id: ast::NodeId, + def_id: DefId, + substs: &'tcx Substs<'tcx>, disr: Disr, - param_substs: &'tcx Substs<'tcx>, llfndecl: ValueRef) { - let ctor_ty = ccx.tcx().node_id_to_type(ctor_id); - let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty); + attributes::inline(llfndecl, attributes::InlineAttr::Hint); + attributes::set_frame_pointer_elimination(ccx, llfndecl); + + let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty; + let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &ctor_ty); let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); let sig = ccx.tcx().normalize_associated_type(&sig); @@ -1742,10 +1746,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, println!("n_null_glues: {}", stats.n_null_glues.get()); println!("n_real_glues: {}", stats.n_real_glues.get()); - println!("n_fallback_instantiations: {}", stats.n_fallback_instantiations.get()); - println!("n_fns: {}", stats.n_fns.get()); - println!("n_monos: {}", stats.n_monos.get()); println!("n_inlines: {}", stats.n_inlines.get()); println!("n_closures: {}", stats.n_closures.get()); println!("fn stats:"); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index b661383d6060f..9aa486dc62811 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -18,12 +18,10 @@ pub use self::CalleeData::*; use arena::TypedArena; use back::symbol_names; -use llvm::{ValueRef, get_params}; -use middle::cstore::LOCAL_CRATE; +use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; -use rustc::hir::map as hir_map; use abi::{Abi, FnType}; use attributes; use base; @@ -34,18 +32,15 @@ use common::{self, Block, Result, CrateContext, FunctionContext}; use consts; use debuginfo::DebugLoc; use declare; -use inline; use meth; use monomorphize::{self, Instance}; use trans_item::TransItem; use type_of; -use value::Value; use Disr; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::hir; use syntax_pos::DUMMY_SP; -use errors; #[derive(Debug)] pub enum CalleeData { @@ -102,35 +97,28 @@ impl<'tcx> Callee<'tcx> { return Callee::trait_method(ccx, trait_id, def_id, substs); } - let maybe_node_id = inline::get_local_instance(ccx, def_id) - .and_then(|def_id| tcx.map.as_local_node_id(def_id)); - let maybe_ast_node = maybe_node_id.and_then(|node_id| { - tcx.map.find(node_id) - }); - - let data = match maybe_ast_node { - Some(hir_map::NodeStructCtor(_)) => { - NamedTupleConstructor(Disr(0)) - } - Some(hir_map::NodeVariant(_)) => { - let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap()); - NamedTupleConstructor(Disr::from(vinfo.disr_val)) - } - Some(hir_map::NodeForeignItem(fi)) if { - let abi = tcx.map.get_foreign_abi(fi.id); - abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic - } => Intrinsic, - - _ => { - let (llfn, ty) = get_fn(ccx, def_id, substs); - return Callee::ptr(llfn, ty); + let fn_ty = def_ty(tcx, def_id, substs); + if let ty::TyFnDef(_, _, f) = fn_ty.sty { + if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic { + return Callee { + data: Intrinsic, + ty: fn_ty + }; } - }; + } - Callee { - data: data, - ty: def_ty(tcx, def_id, substs) + // FIXME(eddyb) Detect ADT constructors more efficiently. + if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() { + if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) { + return Callee { + data: NamedTupleConstructor(Disr::from(v.disr_val)), + ty: fn_ty + }; + } } + + let (llfn, ty) = get_fn(ccx, def_id, substs); + Callee::ptr(llfn, ty) } /// Trait method, which has to be resolved to an impl method. @@ -168,24 +156,14 @@ impl<'tcx> Callee<'tcx> { trait_closure_kind); let method_ty = def_ty(tcx, def_id, substs); - let fn_ptr_ty = match method_ty.sty { - ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty), - _ => bug!("expected fn item type, found {}", - method_ty) - }; - Callee::ptr(llfn, fn_ptr_ty) + Callee::ptr(llfn, method_ty) } traits::VtableFnPointer(vtable_fn_pointer) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty); let method_ty = def_ty(tcx, def_id, substs); - let fn_ptr_ty = match method_ty.sty { - ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty), - _ => bug!("expected fn item type, found {}", - method_ty) - }; - Callee::ptr(llfn, fn_ptr_ty) + Callee::ptr(llfn, method_ty) } traits::VtableObject(ref data) => { Callee { @@ -242,9 +220,21 @@ impl<'tcx> Callee<'tcx> { Virtual(idx) => { meth::trans_object_shim(ccx, self.ty, idx) } - NamedTupleConstructor(_) => match self.ty.sty { + NamedTupleConstructor(disr) => match self.ty.sty { ty::TyFnDef(def_id, substs, _) => { - return get_fn(ccx, def_id, substs).0; + let instance = Instance::new(def_id, substs); + if let Some(&llfn) = ccx.instances().borrow().get(&instance) { + return llfn; + } + + let sym = ccx.symbol_map().get_or_compute(ccx.shared(), + TransItem::Fn(instance)); + assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance))); + let lldecl = declare::define_internal_fn(ccx, &sym, self.ty); + base::trans_ctor_shim(ccx, def_id, substs, disr, lldecl); + ccx.instances().borrow_mut().insert(instance, lldecl); + + lldecl } _ => bug!("expected fn item type, found {}", self.ty) }, @@ -412,83 +402,20 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert!(!substs.types.needs_infer()); assert!(!substs.types.has_escaping_regions()); + assert!(!substs.types.has_param_types()); - // Check whether this fn has an inlined copy and, if so, redirect - // def_id to the local id of the inlined copy. - let def_id = inline::maybe_instantiate_inline(ccx, def_id); - - fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool { - let node_id = match tcx.map.as_local_node_id(def_id) { - Some(n) => n, - None => { return false; } - }; - let map_node = errors::expect( - &tcx.sess.diagnostic(), - tcx.map.find(node_id), - || "local item should be in ast map".to_string()); - - match map_node { - hir_map::NodeVariant(v) => { - v.node.data.is_tuple() - } - hir_map::NodeStructCtor(_) => true, - _ => false - } - } - let must_monomorphise = - !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id); - - debug!("get_fn({:?}) must_monomorphise: {}", - def_id, must_monomorphise); - - // Create a monomorphic version of generic functions - if must_monomorphise { - // Should be either intra-crate or inlined. - assert_eq!(def_id.krate, LOCAL_CRATE); - - let substs = tcx.normalize_associated_type(&substs); - let (val, fn_ty) = monomorphize::monomorphic_fn(ccx, def_id, substs); - let fn_ptr_ty = match fn_ty.sty { - ty::TyFnDef(_, _, fty) => { - // Create a fn pointer with the substituted signature. - tcx.mk_fn_ptr(fty) - } - _ => bug!("expected fn item type, found {}", fn_ty) - }; - assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val)); - return (val, fn_ptr_ty); - } - - // Find the actual function pointer. - let ty = ccx.tcx().lookup_item_type(def_id).ty; - let fn_ptr_ty = match ty.sty { - ty::TyFnDef(_, _, ref fty) => { - // Create a fn pointer with the normalized signature. - tcx.mk_fn_ptr(tcx.normalize_associated_type(fty)) - } - _ => bug!("expected fn item type, found {}", ty) - }; + let substs = tcx.normalize_associated_type(&substs); + let instance = Instance::new(def_id, substs); + let item_ty = ccx.tcx().lookup_item_type(def_id).ty; + let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &item_ty); - let instance = Instance::mono(ccx.shared(), def_id); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - return (llfn, fn_ptr_ty); + return (llfn, fn_ty); } - let local_id = ccx.tcx().map.as_local_node_id(def_id); - let local_item = match local_id.and_then(|id| tcx.map.find(id)) { - Some(hir_map::NodeItem(&hir::Item { - span, node: hir::ItemFn(..), .. - })) | - Some(hir_map::NodeTraitItem(&hir::TraitItem { - span, node: hir::MethodTraitItem(_, Some(_)), .. - })) | - Some(hir_map::NodeImplItem(&hir::ImplItem { - span, node: hir::ImplItemKind::Method(..), .. - })) => { - Some(span) - } - _ => None - }; + let sym = ccx.symbol_map().get_or_compute(ccx.shared(), + TransItem::Fn(instance)); + debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); // This is subtle and surprising, but sometimes we have to bitcast // the resulting fn pointer. The reason has to do with external @@ -514,23 +441,17 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let sym = ccx.symbol_map().get_or_compute(ccx.shared(), - TransItem::Fn(instance)); - - let llptrty = type_of::type_of(ccx, fn_ptr_ty); - let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { - if let Some(span) = local_item { - if declare::get_defined_value(ccx, &sym).is_some() { - ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", &sym)); - } + let fn_ptr_ty = match fn_ty.sty { + ty::TyFnDef(_, _, fty) => { + // Create a fn pointer with the substituted signature. + tcx.mk_fn_ptr(fty) } + _ => bug!("expected fn item type, found {}", fn_ty) + }; + let llptrty = type_of::type_of(ccx, fn_ptr_ty); + let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { if common::val_ty(llfn) != llptrty { - if local_item.is_some() { - bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}", - sym, Value(llfn), llptrty); - } debug!("get_fn: casting {:?} to {:?}", llfn, llptrty); consts::ptrcast(llfn, llptrty) } else { @@ -538,15 +459,21 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } } else { - let llfn = declare::declare_fn(ccx, &sym, ty); + let llfn = declare::declare_fn(ccx, &sym, fn_ty); assert_eq!(common::val_ty(llfn), llptrty); debug!("get_fn: not casting pointer!"); let attrs = ccx.tcx().get_attrs(def_id); attributes::from_fn_attrs(ccx, &attrs, llfn); - if local_item.is_some() { + + let is_local_def = ccx.shared().translation_items().borrow() + .contains(&TransItem::Fn(instance)); + if is_local_def { // FIXME(eddyb) Doubt all extern fn should allow unwinding. attributes::unwind(llfn, true); + unsafe { + llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage); + } } llfn @@ -554,7 +481,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, llfn); - (llfn, fn_ptr_ty) + (llfn, fn_ty) } // ______________________________________________________________________ diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 3a456b1dd7968..c5053e4feee62 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -199,12 +199,6 @@ pub fn gensym_name(name: &str) -> ast::Name { use Disr; -#[derive(Copy, Clone)] -pub struct NodeIdAndSpan { - pub id: ast::NodeId, - pub span: Span, -} - /// The concrete version of ty::FieldDef. The name is the field index if /// the field is numeric. pub struct Field<'tcx>(pub ast::Name, pub Ty<'tcx>); @@ -1066,34 +1060,6 @@ pub fn langcall(tcx: TyCtxt, } } -/// Return the VariantDef corresponding to an inlined variant node -pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - inlined_vid: ast::NodeId) - -> ty::VariantDef<'tcx> -{ - let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid); - debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty, - inlined_vid); - let adt_def = match ctor_ty.sty { - ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { - output, .. - }), ..}) => output, - _ => ctor_ty - }.ty_adt_def().unwrap(); - let variant_def_id = if ccx.tcx().map.is_inlined_node_id(inlined_vid) { - ccx.defid_for_inlined_node(inlined_vid).unwrap() - } else { - ccx.tcx().map.local_def_id(inlined_vid) - }; - - adt_def.variants - .iter() - .find(|v| variant_def_id == v.did) - .unwrap_or_else(|| { - bug!("no variant for {:?}::{}", adt_def, inlined_vid) - }) -} - // To avoid UB from LLVM, these two functions mask RHS with an // appropriate mask unconditionally (i.e. the fallback behavior for // all shifts). For 32- and 64-bit types, this matches the semantics diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index c1d855649123a..fa1e008d496e4 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -105,14 +105,10 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { let defined_in_current_codegen_unit = ccx.codegen_unit() .items() .contains_key(&TransItem::Static(id)); - if defined_in_current_codegen_unit { - if declare::get_declared_value(ccx, sym).is_none() { - span_bug!(span, "trans: Static not properly pre-defined?"); - } - } else { - if declare::get_declared_value(ccx, sym).is_some() { - span_bug!(span, "trans: Conflicting symbol names for static?"); - } + assert!(!defined_in_current_codegen_unit); + + if declare::get_declared_value(ccx, sym).is_some() { + span_bug!(span, "trans: Conflicting symbol names for static?"); } let g = declare::define_global(ccx, sym, llty).unwrap(); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 8a836c692e1a8..0a295b251b31e 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -53,9 +53,7 @@ pub struct Stats { pub n_glues_created: Cell, pub n_null_glues: Cell, pub n_real_glues: Cell, - pub n_fallback_instantiations: Cell, pub n_fns: Cell, - pub n_monos: Cell, pub n_inlines: Cell, pub n_closures: Cell, pub n_llvm_insns: Cell, @@ -103,7 +101,6 @@ pub struct LocalCrateContext<'tcx> { drop_glues: RefCell, (ValueRef, FnType)>>, /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, - monomorphizing: RefCell>, /// Cache generated vtables vtables: RefCell, ValueRef>>, /// Cache of constant strings, @@ -488,9 +485,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { n_glues_created: Cell::new(0), n_null_glues: Cell::new(0), n_real_glues: Cell::new(0), - n_fallback_instantiations: Cell::new(0), n_fns: Cell::new(0), - n_monos: Cell::new(0), n_inlines: Cell::new(0), n_closures: Cell::new(0), n_llvm_insns: Cell::new(0), @@ -626,7 +621,6 @@ impl<'tcx> LocalCrateContext<'tcx> { fn_pointer_shims: RefCell::new(FnvHashMap()), drop_glues: RefCell::new(FnvHashMap()), instances: RefCell::new(FnvHashMap()), - monomorphizing: RefCell::new(DefIdMap()), vtables: RefCell::new(FnvHashMap()), const_cstr_cache: RefCell::new(FnvHashMap()), const_unsized: RefCell::new(FnvHashMap()), @@ -830,10 +824,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().instances } - pub fn monomorphizing<'a>(&'a self) -> &'a RefCell> { - &self.local().monomorphizing - } - pub fn vtables<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().vtables } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index bd984a71badea..ba91b44343868 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -28,7 +28,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::hir; use {type_of, adt, machine, monomorphize}; -use common::{CrateContext, FunctionContext}; +use common::CrateContext; use type_::Type; use rustc::ty::{self, Ty}; use session::config; @@ -882,26 +882,6 @@ fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str) file_metadata } -/// Finds the scope metadata node for the given AST node. -pub fn scope_metadata(fcx: &FunctionContext, - node_id: ast::NodeId, - error_reporting_span: Span) - -> DIScope { - let scope_map = &fcx.debug_context - .get_ref(error_reporting_span) - .scope_map; - match scope_map.borrow().get(&node_id).cloned() { - Some(scope_metadata) => scope_metadata, - None => { - let node = fcx.ccx.tcx().map.get(node_id); - - span_bug!(error_reporting_span, - "debuginfo: Could not find scope info for node {:?}", - node); - } - } -} - fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> DIType { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index a864f974c96fc..cbf423b0739a3 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -27,15 +27,14 @@ use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArr use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::ty::subst::Substs; -use rustc::hir; use abi::Abi; -use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder}; -use inline; +use common::{CrateContext, FunctionContext, Block, BlockAndBuilder}; use monomorphize::{self, Instance}; use rustc::ty::{self, Ty}; +use rustc::mir::repr as mir; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; -use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet}; use libc::c_uint; use std::cell::{Cell, RefCell}; @@ -134,7 +133,6 @@ impl FunctionDebugContext { } pub struct FunctionDebugContextData { - scope_map: RefCell>, fn_metadata: DISubprogram, source_locations_enabled: Cell, source_location_override: Cell, @@ -222,7 +220,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>, sig: &ty::FnSig<'tcx>, abi: Abi, - llfn: ValueRef) -> FunctionDebugContext { + llfn: ValueRef, + mir: &mir::Mir) -> FunctionDebugContext { if cx.sess().opts.debuginfo == NoDebugInfo { return FunctionDebugContext::DebugInfoDisabled; } @@ -231,8 +230,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Do this here already, in case we do an early exit from this function. source_loc::set_debug_location(cx, None, UnknownLocation); - let instance = inline::maybe_inline_instance(cx, instance); - let (containing_scope, span) = get_containing_scope_and_span(cx, instance); + let containing_scope = get_containing_scope(cx, instance); + let span = mir.span; // This can be the case for functions inlined from another crate if span == syntax_pos::DUMMY_SP { @@ -298,7 +297,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Initialize fn debug context (including scope map and namespace map) let fn_debug_context = box FunctionDebugContextData { - scope_map: RefCell::new(NodeMap()), fn_metadata: fn_metadata, source_locations_enabled: Cell::new(false), source_location_override: Cell::new(false), @@ -406,9 +404,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, names } - fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>, - instance: Instance<'tcx>) - -> (DIScope, Span) { + fn get_containing_scope<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>, + instance: Instance<'tcx>) + -> DIScope { // First, let's see if this is a method within an inherent impl. Because // if yes, we want to make the result subroutine DIE a child of the // subroutine's self-type. @@ -428,22 +426,15 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }); - let containing_scope = self_type.unwrap_or_else(|| { + self_type.unwrap_or_else(|| { namespace::item_namespace(cx, DefId { krate: instance.def.krate, index: cx.tcx() .def_key(instance.def) .parent - .expect("get_containing_scope_and_span: missing parent?") + .expect("get_containing_scope: missing parent?") }) - }); - - // Try to get some span information, if we have an inlined item. - let definition_span = cx.tcx() - .map - .def_id_span(instance.def, syntax_pos::DUMMY_SP); - - (containing_scope, definition_span) + }) } } @@ -521,7 +512,6 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DebugLoc { - At(ast::NodeId, Span), ScopeAt(DIScope, Span), None } @@ -535,28 +525,3 @@ impl DebugLoc { source_loc::set_source_location(bcx.fcx(), Some(bcx), self); } } - -pub trait ToDebugLoc { - fn debug_loc(&self) -> DebugLoc; -} - -impl ToDebugLoc for hir::Expr { - fn debug_loc(&self) -> DebugLoc { - DebugLoc::At(self.id, self.span) - } -} - -impl ToDebugLoc for NodeIdAndSpan { - fn debug_loc(&self) -> DebugLoc { - DebugLoc::At(self.id, self.span) - } -} - -impl ToDebugLoc for Option { - fn debug_loc(&self) -> DebugLoc { - match *self { - Some(NodeIdAndSpan { id, span }) => DebugLoc::At(id, span), - None => DebugLoc::None - } - } -} diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_trans/debuginfo/source_loc.rs index 32b414d279628..1aee27c144a36 100644 --- a/src/librustc_trans/debuginfo/source_loc.rs +++ b/src/librustc_trans/debuginfo/source_loc.rs @@ -11,7 +11,7 @@ use self::InternalDebugLocation::*; use super::utils::{debug_context, span_start}; -use super::metadata::{scope_metadata,UNKNOWN_COLUMN_NUMBER}; +use super::metadata::{UNKNOWN_COLUMN_NUMBER}; use super::{FunctionDebugContext, DebugLoc}; use llvm; @@ -47,9 +47,6 @@ pub fn set_source_location(fcx: &FunctionContext, let dbg_loc = if function_debug_context.source_locations_enabled.get() { let (scope, span) = match debug_loc { - DebugLoc::At(node_id, span) => { - (scope_metadata(fcx, node_id, span), span) - } DebugLoc::ScopeAt(scope, span) => (scope, span), DebugLoc::None => { set_debug_location(fcx.ccx, builder, UnknownLocation); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index ed61f1f589a03..6a072c84dd9b3 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -221,10 +221,6 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g, TransItem::DropGlue(g).to_raw_string(), ccx.codegen_unit().name()); - - ccx.stats().n_fallback_instantiations.set(ccx.stats() - .n_fallback_instantiations - .get() + 1); } } diff --git a/src/librustc_trans/inline.rs b/src/librustc_trans/inline.rs deleted file mode 100644 index 8581fccf10ab5..0000000000000 --- a/src/librustc_trans/inline.rs +++ /dev/null @@ -1,52 +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. - -use rustc::hir::def_id::DefId; -use base::push_ctxt; -use common::*; -use monomorphize::Instance; - -use rustc::dep_graph::DepNode; - -fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { - debug!("instantiate_inline({:?})", fn_id); - let _icx = push_ctxt("instantiate_inline"); - let tcx = ccx.tcx(); - let _task = tcx.dep_graph.in_task(DepNode::TransInlinedItem(fn_id)); - - tcx.sess - .cstore - .maybe_get_item_ast(tcx, fn_id) - .map(|(_, inline_id)| { - tcx.map.local_def_id(inline_id) - }) -} - -pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId) - -> Option { - if let Some(_) = ccx.tcx().map.as_local_node_id(fn_id) { - Some(fn_id) - } else { - instantiate_inline(ccx, fn_id) - } -} - -pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> DefId { - get_local_instance(ccx, fn_id).unwrap_or(fn_id) -} - -pub fn maybe_inline_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>) -> Instance<'tcx> { - let def_id = maybe_instantiate_inline(ccx, instance.def); - Instance { - def: def_id, - substs: instance.substs - } -} diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index afe258f68e49f..7faff98aea442 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -111,7 +111,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let name = tcx.item_name(def_id).as_str(); let span = match call_debug_location { - DebugLoc::At(_, span) | DebugLoc::ScopeAt(_, span) => span, + DebugLoc::ScopeAt(_, span) => span, DebugLoc::None => { span_bug!(fcx.span.unwrap_or(DUMMY_SP), "intrinsic `{}` called with missing span", name); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d989acc27effd..1286df7b97e67 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -114,7 +114,6 @@ mod debuginfo; mod declare; mod disr; mod glue; -mod inline; mod intrinsic; mod machine; mod meth; diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index d1837883aaeb0..020ac8d643b86 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,162 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::ValueRef; -use llvm; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; -use attributes; -use base::{push_ctxt}; -use base; +use rustc::ty::{self, Ty, TyCtxt}; use common::*; -use declare; -use Disr; -use rustc::hir::map as hir_map; use rustc::util::ppaux; -use rustc::hir; - -use errors; - use std::fmt; -use trans_item::TransItem; - -pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_id: DefId, - psubsts: &'tcx Substs<'tcx>) - -> (ValueRef, Ty<'tcx>) { - debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts); - assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); - - let _icx = push_ctxt("monomorphic_fn"); - - let instance = Instance::new(fn_id, psubsts); - - let item_ty = ccx.tcx().lookup_item_type(fn_id).ty; - - debug!("monomorphic_fn about to subst into {:?}", item_ty); - let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty); - debug!("mono_ty = {:?} (post-substitution)", mono_ty); - - if let Some(&val) = ccx.instances().borrow().get(&instance) { - debug!("leaving monomorphic fn {:?}", instance); - return (val, mono_ty); - } else { - assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance))); - } - - debug!("monomorphic_fn({:?})", instance); - - ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1); - - let depth; - { - let mut monomorphizing = ccx.monomorphizing().borrow_mut(); - depth = match monomorphizing.get(&fn_id) { - Some(&d) => d, None => 0 - }; - - debug!("monomorphic_fn: depth for fn_id={:?} is {:?}", fn_id, depth+1); - - // Random cut-off -- code that needs to instantiate the same function - // recursively more than thirty times can probably safely be assumed - // to be causing an infinite expansion. - if depth > ccx.sess().recursion_limit.get() { - let error = format!("reached the recursion limit while instantiating `{}`", - instance); - if let Some(id) = ccx.tcx().map.as_local_node_id(fn_id) { - ccx.sess().span_fatal(ccx.tcx().map.span(id), &error); - } else { - ccx.sess().fatal(&error); - } - } - - monomorphizing.insert(fn_id, depth + 1); - } - - let symbol = ccx.symbol_map().get_or_compute(ccx.shared(), - TransItem::Fn(instance)); - - debug!("monomorphize_fn mangled to {}", &symbol); - assert!(declare::get_defined_value(ccx, &symbol).is_none()); - - // FIXME(nagisa): perhaps needs a more fine grained selection? - let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty); - // FIXME(eddyb) Doubt all extern fn should allow unwinding. - attributes::unwind(lldecl, true); - - ccx.instances().borrow_mut().insert(instance, lldecl); - - // we can only monomorphize things in this crate (or inlined into it) - let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap(); - let map_node = errors::expect( - ccx.sess().diagnostic(), - ccx.tcx().map.find(fn_node_id), - || { - format!("while instantiating `{}`, couldn't find it in \ - the item map (may have attempted to monomorphize \ - an item defined in a different crate?)", - instance) - }); - match map_node { - hir_map::NodeItem(&hir::Item { - ref attrs, - node: hir::ItemFn(..), .. - }) | - hir_map::NodeImplItem(&hir::ImplItem { - ref attrs, node: hir::ImplItemKind::Method( - hir::MethodSig { .. }, _), .. - }) | - hir_map::NodeTraitItem(&hir::TraitItem { - ref attrs, node: hir::MethodTraitItem( - hir::MethodSig { .. }, Some(_)), .. - }) => { - let trans_item = TransItem::Fn(instance); - - if ccx.shared().translation_items().borrow().contains(&trans_item) { - attributes::from_fn_attrs(ccx, attrs, lldecl); - unsafe { - llvm::LLVMSetLinkage(lldecl, llvm::ExternalLinkage); - } - } else { - // FIXME: #34151 - // Normally, getting here would indicate a bug in trans::collector, - // since it seems to have missed a translation item. When we are - // translating with non-MIR based trans, however, the results of - // the collector are not entirely reliable since it bases its - // analysis on MIR. Thus, we'll instantiate the missing function - // privately in this codegen unit, so that things keep working. - ccx.stats().n_fallback_instantiations.set(ccx.stats() - .n_fallback_instantiations - .get() + 1); - trans_item.predefine(ccx, llvm::InternalLinkage); - trans_item.define(ccx); - } - } - - hir_map::NodeVariant(_) | hir_map::NodeStructCtor(_) => { - let disr = match map_node { - hir_map::NodeVariant(_) => { - Disr::from(inlined_variant_def(ccx, fn_node_id).disr_val) - } - hir_map::NodeStructCtor(_) => Disr(0), - _ => bug!() - }; - attributes::inline(lldecl, attributes::InlineAttr::Hint); - attributes::set_frame_pointer_elimination(ccx, lldecl); - base::trans_ctor_shim(ccx, fn_node_id, disr, psubsts, lldecl); - } - - _ => bug!("can't monomorphize a {:?}", map_node) - }; - - ccx.monomorphizing().borrow_mut().insert(fn_id, depth); - - debug!("leaving monomorphic fn {}", ccx.tcx().item_path_str(fn_id)); - (lldecl, mono_ty) -} #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 66ea5264dd28e..90dcc3a61fd7e 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -22,17 +22,15 @@ use declare; use glue::DropGlueKind; use llvm; use monomorphize::{self, Instance}; -use inline; use rustc::dep_graph::DepNode; use rustc::hir; -use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; -use syntax::{attr,errors}; +use syntax::attr; use type_of; use glue; use abi::{Abi, FnType}; @@ -157,20 +155,16 @@ impl<'a, 'tcx> TransItem<'tcx> { let ty = ccx.tcx().lookup_item_type(def_id).ty; let llty = type_of::type_of(ccx, ty); - match ccx.tcx().map.get(node_id) { - hir::map::NodeItem(&hir::Item { - span, node: hir::ItemStatic(..), .. - }) => { - let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { - ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", symbol_name)) - }); + let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { + ccx.sess().span_fatal(ccx.tcx().map.span(node_id), + &format!("symbol `{}` is already defined", symbol_name)) + }); - unsafe { llvm::LLVMSetLinkage(g, linkage) }; - } + unsafe { llvm::LLVMSetLinkage(g, linkage) }; - item => bug!("predefine_static: expected static, found {:?}", item) - } + let instance = Instance::mono(ccx.shared(), def_id); + ccx.instances().borrow_mut().insert(instance, g); + ccx.statics().borrow_mut().insert(g, def_id); } fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, @@ -180,47 +174,22 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(!instance.substs.types.needs_infer() && !instance.substs.types.has_param_types()); - let instance = inline::maybe_inline_instance(ccx, instance); - let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; let item_ty = ccx.tcx().erase_regions(&item_ty); let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty); - let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); - let map_node = errors::expect( - ccx.sess().diagnostic(), - ccx.tcx().map.find(fn_node_id), - || { - format!("while instantiating `{}`, couldn't find it in \ - the item map (may have attempted to monomorphize \ - an item defined in a different crate?)", - instance) - }); - - match map_node { - hir_map::NodeItem(&hir::Item { - ref attrs, node: hir::ItemFn(..), .. - }) | - hir_map::NodeTraitItem(&hir::TraitItem { - ref attrs, node: hir::MethodTraitItem(..), .. - }) | - hir_map::NodeImplItem(&hir::ImplItem { - ref attrs, node: hir::ImplItemKind::Method(..), .. - }) => { - let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); - unsafe { llvm::LLVMSetLinkage(lldecl, linkage) }; - base::set_link_section(ccx, lldecl, attrs); - if linkage == llvm::LinkOnceODRLinkage || - linkage == llvm::WeakODRLinkage { - llvm::SetUniqueComdat(ccx.llmod(), lldecl); - } + let attrs = ccx.tcx().get_attrs(instance.def); + let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); + unsafe { llvm::LLVMSetLinkage(lldecl, linkage) }; + base::set_link_section(ccx, lldecl, &attrs); + if linkage == llvm::LinkOnceODRLinkage || + linkage == llvm::WeakODRLinkage { + llvm::SetUniqueComdat(ccx.llmod(), lldecl); + } - attributes::from_fn_attrs(ccx, attrs, lldecl); - ccx.instances().borrow_mut().insert(instance, lldecl); - } - _ => bug!("Invalid item for TransItem::Fn: `{:?}`", map_node) - }; + attributes::from_fn_attrs(ccx, &attrs, lldecl); + ccx.instances().borrow_mut().insert(instance, lldecl); } fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>, From 11e9b8de7db8d5500cbee2252f6afd870f186104 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Wed, 24 Aug 2016 17:43:51 +0530 Subject: [PATCH 253/768] Update E0445 and E0454 to new error format Fixes #35922. Fixes #35930. Part of #35233. r? @GuillaumeGomez --- src/librustc_metadata/creader.rs | 6 ++++-- src/librustc_privacy/lib.rs | 7 +++++-- src/test/compile-fail/E0445.rs | 12 +++++++++--- src/test/compile-fail/E0454.rs | 4 +++- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4a656b180f259..46469efea6bc8 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -101,8 +101,10 @@ fn register_native_lib(sess: &Session, if name.is_empty() { match span { Some(span) => { - span_err!(sess, span, E0454, - "#[link(name = \"\")] given with empty name"); + struct_span_err!(sess, span, E0454, + "#[link(name = \"\")] given with empty name") + .span_label(span, &format!("empty name given")) + .emit(); } None => { sess.err("empty library name given via `-l`"); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index de9ddcd934216..028632ad7c006 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -964,8 +964,11 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, if !vis.is_at_least(self.required_visibility, &self.tcx.map) { if self.tcx.sess.features.borrow().pub_restricted || self.old_error_set.contains(&trait_ref.ref_id) { - span_err!(self.tcx.sess, trait_ref.path.span, E0445, - "private trait in public interface"); + struct_span_err!(self.tcx.sess, trait_ref.path.span, E0445, + "private trait in public interface") + .span_label(trait_ref.path.span, &format!( + "private trait can't be public")) + .emit(); } else { self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, node_id, diff --git a/src/test/compile-fail/E0445.rs b/src/test/compile-fail/E0445.rs index 6b360c60a0f90..7c5c862a6f812 100644 --- a/src/test/compile-fail/E0445.rs +++ b/src/test/compile-fail/E0445.rs @@ -12,8 +12,14 @@ trait Foo { fn dummy(&self) { } } -pub trait Bar : Foo {} //~ ERROR E0445 -pub struct Bar2(pub T); //~ ERROR E0445 -pub fn foo (t: T) {} //~ ERROR E0445 +pub trait Bar : Foo {} +//~^ ERROR private trait in public interface [E0445] +//~| NOTE private trait can't be public +pub struct Bar2(pub T); +//~^ ERROR private trait in public interface [E0445] +//~| NOTE private trait can't be public +pub fn foo (t: T) {} +//~^ ERROR private trait in public interface [E0445] +//~| NOTE private trait can't be public fn main() {} diff --git a/src/test/compile-fail/E0454.rs b/src/test/compile-fail/E0454.rs index 1439c3133d9ca..39887927c885f 100644 --- a/src/test/compile-fail/E0454.rs +++ b/src/test/compile-fail/E0454.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "")] extern {} //~ ERROR E0454 +#[link(name = "")] extern {} +//~^ ERROR E0454 +//~| NOTE empty name given fn main() { } From bf22a7a71ab47a7d2074134b02b02df1d6ce497e Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Wed, 24 Aug 2016 15:43:28 +0200 Subject: [PATCH 254/768] Updated code sample in chapter on syntax extensions. The affected API apparently had changed with commit d59accfb065843d12db9180a4f504664e3d23ef1. --- src/doc/book/compiler-plugins.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/compiler-plugins.md b/src/doc/book/compiler-plugins.md index 8426d5a626549..a9a81843ab199 100644 --- a/src/doc/book/compiler-plugins.md +++ b/src/doc/book/compiler-plugins.md @@ -46,10 +46,10 @@ extern crate rustc; extern crate rustc_plugin; use syntax::parse::token; -use syntax::ast::TokenTree; +use syntax::tokenstream::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax::ext::build::AstBuilder; // trait for expr_usize -use syntax_pos::Span; +use syntax::ext::quote::rt::Span; use rustc_plugin::Registry; fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) @@ -69,7 +69,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) } let text = match args[0] { - TokenTree::Token(_, token::Ident(s, _)) => s.to_string(), + TokenTree::Token(_, token::Ident(s)) => s.to_string(), _ => { cx.span_err(sp, "argument should be a single identifier"); return DummyResult::any(sp); From d1ecee96bfb7fb52b67358302c524a8c0193dc23 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 24 Aug 2016 18:57:45 +0200 Subject: [PATCH 255/768] memrchr: Correct aligned offset computation The memrchr fallback did not compute the offset correctly. It was intentioned to land on usize-aligned addresses but did not. This was suspected to resulted in a crash on ARMv7 platform! This bug affected non-linux platforms. I think like this, if we have a slice with pointer `ptr` and length `len`, we want to find the last usize-aligned offset in the slice. The correct computation should be: For example if ptr = 1 and len = 6, and size_of::() is 4: [ x x x x x x ] 1 2 3 4 5 6 ^-- last aligned address at offset 3 from the start. The last aligned address is ptr + len - (ptr + len) % usize_size. Compute offset from the start as: offset = len - (ptr + len) % usize_size = 6 - (1 + 6) % 4 = 6 - 3 = 3. I believe the function's return value was always correct previously, if the platform supported unaligned addresses. --- src/libstd/memchr.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/libstd/memchr.rs b/src/libstd/memchr.rs index a408b4378e19e..89b77a7d6614e 100644 --- a/src/libstd/memchr.rs +++ b/src/libstd/memchr.rs @@ -209,7 +209,7 @@ mod fallback { let end_align = (ptr as usize + len) & (usize_bytes - 1); let mut offset; if end_align > 0 { - offset = len - cmp::min(usize_bytes - end_align, len); + offset = len - cmp::min(end_align, len); if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { return Some(offset + index); } @@ -309,6 +309,17 @@ mod fallback { fn no_match_reversed() { assert_eq!(None, memrchr(b'a', b"xyz")); } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } } #[cfg(test)] @@ -385,4 +396,15 @@ mod tests { fn no_match_reversed() { assert_eq!(None, memrchr(b'a', b"xyz")); } + + #[test] + fn each_alignment() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memchr(needle, &data[start..])); + } + } } From 07e6e81e082b94999b0df99f661de610353008f4 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 22 Aug 2016 01:59:18 -0700 Subject: [PATCH 256/768] Extract error reporting into its own fn --- src/librustc_typeck/check/compare_method.rs | 148 +++++++++++--------- 1 file changed, 85 insertions(+), 63 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 0e42990a337d4..582cce3d3d808 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -299,11 +299,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span, impl_m_body_id, &impl_sig); - let impl_args = impl_sig.inputs.clone(); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety, abi: impl_m.fty.abi, - sig: ty::Binder(impl_sig) + sig: ty::Binder(impl_sig.clone()) })); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -318,11 +317,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span, impl_m_body_id, &trait_sig); - let trait_args = trait_sig.inputs.clone(); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety, abi: trait_m.fty.abi, - sig: ty::Binder(trait_sig) + sig: ty::Binder(trait_sig.clone()) })); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -332,65 +330,9 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_fty, trait_fty); - let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node { - ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(), - _ => bug!("{:?} is not a method", impl_m) - }; - - let (impl_err_span, trait_err_span) = match terr { - TypeError::Mutability => { - if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { - let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { - TraitItem_::MethodTraitItem(ref trait_m_sig, _) => - trait_m_sig.decl.inputs.iter(), - _ => bug!("{:?} is not a MethodTraitItem", trait_m) - }; - - impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| { - match (&impl_arg.ty.node, &trait_arg.ty.node) { - (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | - (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => - impl_mt.mutbl != trait_mt.mutbl, - _ => false - } - }).map(|(ref impl_arg, ref trait_arg)| { - match (impl_arg.to_self(), trait_arg.to_self()) { - (Some(impl_self), Some(trait_self)) => - (impl_self.span, Some(trait_self.span)), - (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), - _ => bug!("impl and trait fns have different first args, \ - impl: {:?}, trait: {:?}", impl_arg, trait_arg) - } - }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) - } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - } - } - TypeError::Sorts(ExpectedFound { expected, found }) => { - if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { - let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { - TraitItem_::MethodTraitItem(ref trait_m_sig, _) => - trait_m_sig.decl.inputs.iter(), - _ => bug!("{:?} is not a MethodTraitItem", trait_m) - }; - let impl_iter = impl_args.iter(); - let trait_iter = trait_args.iter(); - let arg_idx = impl_iter.zip(trait_iter) - .position(|(impl_arg_ty, trait_arg_ty)| { - *impl_arg_ty == found && *trait_arg_ty == expected - }).unwrap(); - impl_m_iter.zip(trait_m_iter) - .nth(arg_idx) - .map(|(impl_arg, trait_arg)| - (impl_arg.ty.span, Some(trait_arg.ty.span))) - .unwrap_or( - (origin.span(), tcx.map.span_if_local(trait_m.def_id))) - } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - } - } - _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - }; + let (impl_err_span, trait_err_span) = + extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m, + impl_sig, trait_m, trait_sig); let origin = TypeOrigin::MethodCompatCheck(impl_err_span); @@ -478,6 +420,86 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return true; } + + fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, + terr: &TypeError, + origin: TypeOrigin, + impl_m: &ty::Method, + impl_sig: ty::FnSig<'tcx>, + trait_m: &ty::Method, + trait_sig: ty::FnSig<'tcx>) + -> (Span, Option) { + let tcx = infcx.tcx; + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => + (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()), + _ => bug!("{:?} is not a method", impl_m) + }; + + match *terr { + TypeError::Mutability => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => + trait_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a MethodTraitItem", trait_m) + }; + + impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| { + match (&impl_arg.ty.node, &trait_arg.ty.node) { + (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | + (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => + impl_mt.mutbl != trait_mt.mutbl, + _ => false + } + }).map(|(ref impl_arg, ref trait_arg)| { + match (impl_arg.to_self(), trait_arg.to_self()) { + (Some(impl_self), Some(trait_self)) => + (impl_self.span, Some(trait_self.span)), + (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), + _ => bug!("impl and trait fns have different first args, \ + impl: {:?}, trait: {:?}", impl_arg, trait_arg) + } + }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + TypeError::Sorts(ExpectedFound { .. }) => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let (trait_m_output, trait_m_iter) = + match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => + (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()), + _ => bug!("{:?} is not a MethodTraitItem", trait_m) + }; + + let impl_iter = impl_sig.inputs.iter(); + let trait_iter = trait_sig.inputs.iter(); + impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter) + .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { + match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { + Ok(_) => None, + Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))) + } + }) + .next() + .unwrap_or_else(|| { + if infcx.sub_types(false, origin, impl_sig.output, + trait_sig.output).is_err() { + (impl_m_output.span(), Some(trait_m_output.span())) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + }) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } } pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, From 3d9cf30ddf83f4f5df327b0cbacfced7150296ee Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 22 Aug 2016 01:59:31 -0700 Subject: [PATCH 257/768] More robust testing --- src/test/compile-fail/issue-35869.rs | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/test/compile-fail/issue-35869.rs diff --git a/src/test/compile-fail/issue-35869.rs b/src/test/compile-fail/issue-35869.rs new file mode 100644 index 0000000000000..8b7fc80bdb6b7 --- /dev/null +++ b/src/test/compile-fail/issue-35869.rs @@ -0,0 +1,37 @@ +// 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. + +#![feature(conservative_impl_trait)] + +trait Foo { + fn foo(fn(u8) -> ()); //~ NOTE type in trait + fn bar(Option); //~ NOTE type in trait + fn baz((u8, u16)); //~ NOTE type in trait + fn qux() -> u8; //~ NOTE type in trait +} + +struct Bar; + +impl Foo for Bar { + fn foo(_: fn(u16) -> ()) {} + //~^ ERROR method `foo` has an incompatible type for trait + //~| NOTE expected u8 + fn bar(_: Option) {} + //~^ ERROR method `bar` has an incompatible type for trait + //~| NOTE expected u8 + fn baz(_: (u16, u16)) {} + //~^ ERROR method `baz` has an incompatible type for trait + //~| NOTE expected u8 + fn qux() -> u16 { 5u16 } + //~^ ERROR method `qux` has an incompatible type for trait + //~| NOTE expected u8 +} + +fn main() {} From 1fd85b1a80429a5d217424b2e7f51d0082713b9d Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 24 Aug 2016 21:19:39 +0200 Subject: [PATCH 258/768] fixed compile-fail test --- src/test/compile-fail/rfc1623.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 840307ea456e5..963459b27bf1f 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -14,7 +14,7 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } // the boundaries of elision static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//^ERROR: missing lifetime specifier +//~^ ERROR: missing lifetime specifier &(non_elidable as fn(&u8, &u8) -> &u8); type Baz<'a> = fn(&'a [u8]) -> Option; @@ -25,7 +25,8 @@ static STATIC_BAZ : &Baz<'static> = &(baz as Baz); const CONST_BAZ : &Baz<'static> = &(baz as Baz); fn main() { - let y = [1u8, 2, 3]; + let x = &[1u8, 2, 3]; + let y = x; //surprisingly this appears to work, so lifetime < `'static` is valid assert_eq!(Some(1), STATIC_BAZ(y)); From 8295c5056da0be355c86b29d1d4eed469920e73c Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 24 Aug 2016 21:41:23 +0200 Subject: [PATCH 259/768] memrchr: Use a conditional instead of subtracting a complicated min This makes the critical calculation easier to understand. --- src/libstd/memchr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/memchr.rs b/src/libstd/memchr.rs index 89b77a7d6614e..03f55f7ad6186 100644 --- a/src/libstd/memchr.rs +++ b/src/libstd/memchr.rs @@ -209,7 +209,7 @@ mod fallback { let end_align = (ptr as usize + len) & (usize_bytes - 1); let mut offset; if end_align > 0 { - offset = len - cmp::min(end_align, len); + offset = if end_align >= len { 0 } else { len - end_align }; if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { return Some(offset + index); } From e2ad3be1787cdd36d52fcd2355225156f5460dc4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 10:02:28 +0000 Subject: [PATCH 260/768] Use `#[prelude_import]` in `libcore`. --- src/libcore/any.rs | 4 +--- src/libcore/array.rs | 11 +++-------- src/libcore/borrow.rs | 2 -- src/libcore/cell.rs | 13 +++---------- src/libcore/char.rs | 2 -- src/libcore/char_private.rs | 2 -- src/libcore/clone.rs | 2 -- src/libcore/cmp.rs | 9 +-------- src/libcore/convert.rs | 3 --- src/libcore/default.rs | 2 -- src/libcore/fmt/builders.rs | 1 - src/libcore/fmt/mod.rs | 5 ----- src/libcore/fmt/num.rs | 2 -- src/libcore/hash/mod.rs | 4 ---- src/libcore/hash/sip.rs | 2 -- src/libcore/intrinsics.rs | 2 -- src/libcore/iter/iterator.rs | 11 ++--------- src/libcore/iter/mod.rs | 4 ---- src/libcore/iter/range.rs | 6 +----- src/libcore/iter/sources.rs | 5 +---- src/libcore/iter/traits.rs | 5 ----- src/libcore/iter_private.rs | 2 -- src/libcore/lib.rs | 5 +++++ src/libcore/marker.rs | 5 ----- src/libcore/mem.rs | 1 - src/libcore/nonzero.rs | 1 - src/libcore/num/bignum.rs | 3 --- src/libcore/num/dec2flt/algorithm.rs | 2 -- src/libcore/num/dec2flt/mod.rs | 1 - src/libcore/num/dec2flt/num.rs | 1 - src/libcore/num/dec2flt/parse.rs | 1 - src/libcore/num/dec2flt/rawfp.rs | 1 - src/libcore/num/flt2dec/decoder.rs | 2 -- src/libcore/num/flt2dec/mod.rs | 1 - src/libcore/num/flt2dec/strategy/dragon.rs | 2 -- src/libcore/num/flt2dec/strategy/grisu.rs | 2 -- src/libcore/num/mod.rs | 10 ++-------- src/libcore/ops.rs | 7 +------ src/libcore/option.rs | 11 +---------- src/libcore/ptr.rs | 5 +---- src/libcore/result.rs | 8 +------- src/libcore/slice.rs | 15 +++------------ src/libcore/str/mod.rs | 18 ++++-------------- src/libcore/str/pattern.rs | 2 -- src/libcore/sync/atomic.rs | 6 ------ src/libcore/tuple.rs | 4 ---- 46 files changed, 30 insertions(+), 183 deletions(-) diff --git a/src/libcore/any.rs b/src/libcore/any.rs index a452be2565b65..4f486ad7cb8b2 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -72,12 +72,10 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use marker::Send; use mem::transmute; -use option::Option::{self, Some, None}; use raw::TraitObject; use intrinsics; -use marker::{Reflect, Sized}; +use marker::Reflect; /////////////////////////////////////////////////////////////////////////////// // Any trait diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 45fc5ff80093a..9866a39619a82 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -20,16 +20,11 @@ issue = "27778")] use borrow::{Borrow, BorrowMut}; -use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; -use convert::{AsRef, AsMut}; -use default::Default; +use cmp::Ordering; use fmt; use hash::{Hash, self}; -use iter::IntoIterator; -use marker::{Copy, Sized, Unsize}; -use option::Option; -use slice::{Iter, IterMut, SliceExt}; +use marker::Unsize; +use slice::{Iter, IterMut}; /// Utility trait implemented only on arrays of fixed size /// diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 79330d3a61ea7..3d223465c88a0 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,8 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; - /// A trait for borrowing data. /// /// In general, there may be several ways to "borrow" a piece of data. The diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 2af48ef2fabe3..ec35198b68517 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -144,17 +144,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; -use convert::From; -use default::Default; +use cmp::Ordering; use fmt::{self, Debug, Display}; -use marker::{Copy, PhantomData, Send, Sync, Sized, Unsize}; -use ops::{Deref, DerefMut, Drop, FnOnce, CoerceUnsized}; -use option::Option; -use option::Option::{None, Some}; -use result::Result; -use result::Result::{Ok, Err}; +use marker::{PhantomData, Unsize}; +use ops::{Deref, DerefMut, CoerceUnsized}; /// A mutable memory location that admits only `Copy` data. /// diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 98b7632a220dd..64cb6dc23147d 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -15,8 +15,6 @@ #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] -use prelude::v1::*; - use char_private::is_printable; use iter::FusedIterator; use mem::transmute; diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs index 1d8f95cd4b81c..708e7cc15e7c9 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -11,8 +11,6 @@ // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { for &s in singletons { if x == s { diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index e8cd36f3cd70b..748bb62a1f3eb 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -44,8 +44,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; - /// A common trait for the ability to explicitly duplicate an object. /// /// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 9bba6cd38e556..907dd1508d8be 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -34,9 +34,6 @@ use self::Ordering::*; -use marker::Sized; -use option::Option::{self, Some}; - /// Trait for equality comparisons which are [partial equivalence /// relations](http://en.wikipedia.org/wiki/Partial_equivalence_relation). /// @@ -571,11 +568,7 @@ pub fn max(v1: T, v2: T) -> T { // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { - use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering}; - use cmp::Ordering::{Less, Greater, Equal}; - use marker::Sized; - use option::Option; - use option::Option::{Some, None}; + use cmp::Ordering::{self, Less, Greater, Equal}; macro_rules! partial_eq_impl { ($($t:ty)*) => ($( diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index e68f973d8d940..8e7e2abfc1e17 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -40,9 +40,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; -use result::Result; - /// A cheap, reference-to-reference conversion. /// /// `AsRef` is very similar to, but different than, `Borrow`. See diff --git a/src/libcore/default.rs b/src/libcore/default.rs index a0dd38c983b89..85e4b2a006769 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -12,8 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; - /// A trait for giving a type a useful default value. /// /// Sometimes, you want to fall back to some kind of default value, and diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 6cac80ab6245f..102e3c0bd7b95 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use fmt::{self, FlagV1}; struct PadAdapter<'a, 'b: 'a> { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 7688da971eb1d..66ef92928eb06 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -12,8 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use prelude::v1::*; - use cell::{UnsafeCell, Cell, RefCell, Ref, RefMut, BorrowState}; use marker::PhantomData; use mem; @@ -905,8 +903,6 @@ impl<'a> Formatter<'a> { prefix: &str, buf: &str) -> Result { - use char::CharExt; - let mut width = buf.len(); let mut sign = None; @@ -1020,7 +1016,6 @@ impl<'a> Formatter<'a> { f: F) -> Result where F: FnOnce(&mut Formatter) -> Result, { - use char::CharExt; let align = match self.align { rt::v1::Alignment::Unknown => default, _ => self.align diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index d55e0317a9492..0145897d8f690 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -14,8 +14,6 @@ // FIXME: #6220 Implement floating point formatting -use prelude::v1::*; - use fmt; use num::Zero; use ops::{Div, Rem, Sub}; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 27fdbd383017f..081f0c14ec30c 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -71,8 +71,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use prelude::v1::*; - use fmt; use marker; use mem; @@ -288,8 +286,6 @@ impl Default for BuildHasherDefault { ////////////////////////////////////////////////////////////////////////////// mod impls { - use prelude::v1::*; - use mem; use slice; use super::*; diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 4a806a3c98602..bd6cae92b050c 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -10,8 +10,6 @@ //! An implementation of SipHash. -use prelude::v1::*; - use marker::PhantomData; use ptr; diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index c645608dda790..b70bf43ac353b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -46,8 +46,6 @@ issue = "0")] #![allow(missing_docs)] -use marker::Sized; - extern "rust-intrinsic" { // NB: These intrinsics take raw pointers because they mutate aliased diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6b01ccaceea2f..ea97c87efbb41 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -8,19 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use clone::Clone; -use cmp::{Ord, PartialOrd, PartialEq, Ordering}; -use default::Default; -use ops::FnMut; -use option::Option::{self, Some, None}; -use marker::Sized; +use cmp::Ordering; use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse}; use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile, Rev}; use super::{Zip, Sum, Product}; -use super::ChainState; -use super::{DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator}; -use super::{IntoIterator, ZipImpl}; +use super::{ChainState, FromIterator, ZipImpl}; fn _assert_is_object_safe(_: &Iterator) {} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index cfe117c0b1d69..b1d3ab1d1febc 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -299,13 +299,9 @@ #![stable(feature = "rust1", since = "1.0.0")] -use clone::Clone; use cmp; -use default::Default; use fmt; use iter_private::TrustedRandomAccess; -use ops::FnMut; -use option::Option::{self, Some, None}; use usize; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 48816bf66bbb7..8408e5d88b4cb 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -8,15 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use clone::Clone; -use cmp::PartialOrd; use mem; use ops::{self, Add, Sub}; -use option::Option::{self, Some, None}; -use marker::Sized; use usize; -use super::{DoubleEndedIterator, ExactSizeIterator, Iterator, FusedIterator}; +use super::FusedIterator; /// Objects that can be stepped over in both directions. /// diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index a2a019a07dcf1..da346eaf1db96 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -8,14 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use clone::Clone; -use default::Default; use fmt; use marker; -use option::Option::{self, Some, None}; use usize; -use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator, FusedIterator}; +use super::FusedIterator; /// An iterator that repeats an element endlessly. /// diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 6f80a02468174..59e23c4d96056 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -8,11 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::Option::{self, Some}; -use marker::Sized; - -use super::Iterator; - /// Conversion from an `Iterator`. /// /// By implementing `FromIterator` for a type, you define how it will be diff --git a/src/libcore/iter_private.rs b/src/libcore/iter_private.rs index effe43cc67cea..83eeef31ab054 100644 --- a/src/libcore/iter_private.rs +++ b/src/libcore/iter_private.rs @@ -9,8 +9,6 @@ // except according to those terms. -use iter::ExactSizeIterator; - /// An iterator whose items are random accessible efficiently /// /// # Safety diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fbeddf26b939a..1ae4cf8e5ef5f 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,11 @@ #![feature(unboxed_closures)] #![feature(question_mark)] #![feature(never_type)] +#![feature(prelude_import)] + +#[prelude_import] +#[allow(unused)] +use prelude::v1::*; #[macro_use] mod macros; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 894982abaa939..0a46813df7eb8 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -16,10 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use clone::Clone; use cmp; -use default::Default; -use option::Option; use hash::Hash; use hash::Hasher; @@ -414,8 +411,6 @@ pub struct PhantomData; impls! { PhantomData } mod impls { - use super::{Send, Sync, Sized}; - #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 5c2179ccf33a1..3526e555b0ec8 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -15,7 +15,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::Sized; use intrinsics; use ptr; diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 92bbc4efb7cc1..47afaf77353ee 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -13,7 +13,6 @@ reason = "needs an RFC to flesh out the design", issue = "27730")] -use marker::Sized; use ops::{CoerceUnsized, Deref}; /// Unsafe trait to indicate what types are usable with the NonZero struct diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index a881b539cedeb..bc503ba3e46ae 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -27,8 +27,6 @@ issue = "0")] #![macro_use] -use prelude::v1::*; - use mem; use intrinsics; @@ -494,6 +492,5 @@ define_bignum!(Big32x40: type=Digit32, n=40); // this one is used for testing only. #[doc(hidden)] pub mod tests { - use prelude::v1::*; define_bignum!(Big8x3: type=u8, n=3); } diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 4761727cec03f..604bc7c10dea0 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -10,7 +10,6 @@ //! The various algorithms from the paper. -use prelude::v1::*; use cmp::min; use cmp::Ordering::{Less, Equal, Greater}; use num::diy_float::Fp; @@ -47,7 +46,6 @@ mod fpu_precision { #[cfg(all(target_arch="x86", not(target_feature="sse2")))] mod fpu_precision { use mem::size_of; - use ops::Drop; /// A structure used to preserve the original value of the FPU control word, so that it can be /// restored when the structure is dropped. diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs index ff2d85307b106..cd40e399ab95e 100644 --- a/src/libcore/num/dec2flt/mod.rs +++ b/src/libcore/num/dec2flt/mod.rs @@ -92,7 +92,6 @@ reason = "internal routines only exposed for testing", issue = "0")] -use prelude::v1::*; use fmt; use str::FromStr; diff --git a/src/libcore/num/dec2flt/num.rs b/src/libcore/num/dec2flt/num.rs index 81e7856633b25..34b41fa9decd2 100644 --- a/src/libcore/num/dec2flt/num.rs +++ b/src/libcore/num/dec2flt/num.rs @@ -12,7 +12,6 @@ // FIXME This module's name is a bit unfortunate, since other modules also import `core::num`. -use prelude::v1::*; use cmp::Ordering::{self, Less, Equal, Greater}; pub use num::bignum::Big32x40 as Big; diff --git a/src/libcore/num/dec2flt/parse.rs b/src/libcore/num/dec2flt/parse.rs index fce1c250a022e..d20986faa0fc2 100644 --- a/src/libcore/num/dec2flt/parse.rs +++ b/src/libcore/num/dec2flt/parse.rs @@ -20,7 +20,6 @@ //! modules rely on to not panic (or overflow) in turn. //! To make matters worse, all that happens in a single pass over the input. //! So, be careful when modifying anything, and double-check with the other modules. -use prelude::v1::*; use super::num; use self::ParseResult::{Valid, ShortcutToInf, ShortcutToZero, Invalid}; diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 68e4dc4b359ef..e3b58b6cc7ce9 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -27,7 +27,6 @@ //! Many functions in this module only handle normal numbers. The dec2flt routines conservatively //! take the universally-correct slow path (Algorithm M) for very small and very large numbers. //! That algorithm needs only next_float() which does handle subnormals and zeros. -use prelude::v1::*; use u32; use cmp::Ordering::{Less, Equal, Greater}; use ops::{Mul, Div, Neg}; diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index 5420e7bdd2a5a..276667e44aae1 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -10,8 +10,6 @@ //! Decodes a floating-point value into individual parts and error ranges. -use prelude::v1::*; - use {f32, f64}; use num::FpCategory; use num::dec2flt::rawfp::RawFloat; diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index b549f33424264..f6c03a59f81e4 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -130,7 +130,6 @@ functions. reason = "internal routines only exposed for testing", issue = "0")] -use prelude::v1::*; use i16; pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded}; diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs index 2d68c3a6d026e..6aa4f297e75ba 100644 --- a/src/libcore/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -15,8 +15,6 @@ Almost direct (but slightly optimized) Rust translation of Figure 3 of [1]. quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. */ -use prelude::v1::*; - use cmp::Ordering; use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs index 13e01d9a7f7ab..cf70a1978f5e6 100644 --- a/src/libcore/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -16,8 +16,6 @@ Rust adaptation of Grisu3 algorithm described in [1]. It uses about accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. */ -use prelude::v1::*; - use num::diy_float::Fp; use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4636811aa46da..29ee29eb3eb7f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -12,17 +12,11 @@ #![stable(feature = "rust1", since = "1.0.0")] -use char::CharExt; -use cmp::PartialOrd; -use convert::{From, TryFrom}; +use convert::TryFrom; use fmt; use intrinsics; -use marker::{Copy, Sized}; use mem::size_of; -use option::Option::{self, Some, None}; -use result::Result::{self, Ok, Err}; -use str::{FromStr, StrExt}; -use slice::SliceExt; +use str::FromStr; /// Provides intentionally-wrapped arithmetic on `T`. /// diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index c9124249bf503..fd1a7c0827fa6 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -71,10 +71,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -use cmp::PartialOrd; use fmt; -use marker::{Sized, Unsize}; -use result::Result::{self, Ok, Err}; +use marker::Unsize; /// The `Drop` trait is used to run some code when a value goes out of scope. /// This is sometimes called a 'destructor'. @@ -2184,9 +2182,6 @@ pub trait FnOnce { } mod impls { - use marker::Sized; - use super::{Fn, FnMut, FnOnce}; - #[stable(feature = "rust1", since = "1.0.0")] impl<'a,A,F:?Sized> Fn for &'a F where F : Fn diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 51bbad085fba4..cf52849e01972 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -139,17 +139,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -use self::Option::*; - -use clone::Clone; -use convert::From; -use default::Default; -use iter::{Iterator, FromIterator, IntoIterator, ExactSizeIterator, DoubleEndedIterator}; -use iter::FusedIterator; +use iter::{FromIterator, FusedIterator}; use mem; -use ops::FnOnce; -use result::Result::{Ok, Err}; -use result::Result; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 8cb485872b3f3..f23b407bda4c4 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -16,17 +16,14 @@ #![stable(feature = "rust1", since = "1.0.0")] -use clone::Clone; use intrinsics; use ops::{CoerceUnsized, Deref}; use fmt; use hash; -use option::Option::{self, Some, None}; -use marker::{Copy, PhantomData, Send, Sized, Sync, Unsize}; +use marker::{PhantomData, Unsize}; use mem; use nonzero::NonZero; -use cmp::{PartialEq, Eq, Ord, PartialOrd}; use cmp::Ordering::{self, Less, Equal, Greater}; // FIXME #19649: intrinsic docs don't render, so these have no docs :( diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 718fdf865a970..49eb5619bc6ba 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -236,14 +236,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -use self::Result::{Ok, Err}; - -use clone::Clone; use fmt; -use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator}; -use iter::FusedIterator; -use ops::FnOnce; -use option::Option::{self, None, Some}; +use iter::{FromIterator, FusedIterator}; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). /// diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 603f55a6e108e..baa41aa7af5b2 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -33,24 +33,15 @@ // * The `raw` and `bytes` submodules. // * Boilerplate trait implementations. -use clone::Clone; -use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord}; -use cmp::Ordering::{Less, Equal, Greater}; +use cmp::Ordering::{self, Less, Equal, Greater}; use cmp; -use convert::AsRef; -use default::Default; use fmt; use intrinsics::assume; use iter::*; -use ops::{FnMut, self}; -use ops::RangeFull; -use option::Option; -use option::Option::{None, Some}; -use result::Result; -use result::Result::{Ok, Err}; +use ops::{self, RangeFull}; use ptr; use mem; -use marker::{Copy, Send, Sync, self}; +use marker; use iter_private::TrustedRandomAccess; #[repr(C)] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5dc5880e310d0..18e43c02c648f 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -18,18 +18,10 @@ use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char; -use clone::Clone; -use convert::AsRef; -use default::Default; use fmt; -use iter::ExactSizeIterator; -use iter::{Map, Cloned, Iterator, DoubleEndedIterator, FusedIterator}; -use marker::Sized; +use iter::{Map, Cloned, FusedIterator}; use mem; -use ops::{Fn, FnMut, FnOnce}; -use option::Option::{self, None, Some}; -use result::Result::{self, Ok, Err}; -use slice::{self, SliceExt}; +use slice; pub mod pattern; @@ -1338,11 +1330,9 @@ Section: Trait implementations */ mod traits { - use cmp::{Ord, Ordering, PartialEq, PartialOrd, Eq}; - use option::Option; - use option::Option::Some; + use cmp::Ordering; use ops; - use str::{StrExt, eq_slice}; + use str::eq_slice; #[stable(feature = "rust1", since = "1.0.0")] impl Ord for str { diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 53804c611e66e..7dced2ba7514c 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -17,8 +17,6 @@ reason = "API not fully fleshed out and ready to be stabilized", issue = "27721")] -use prelude::v1::*; - use cmp; use fmt; use usize; diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index bd62879c1a572..75ddd2021a8f7 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -79,14 +79,8 @@ use self::Ordering::*; -use marker::{Send, Sync}; - use intrinsics; use cell::UnsafeCell; - -use result::Result::{self, Ok, Err}; - -use default::Default; use fmt; /// A boolean type which can be safely shared between threads. diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index abaabfd129b38..c3608b60a31a7 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -10,12 +10,8 @@ // See src/libstd/primitive_docs.rs for documentation. -use clone::Clone; use cmp::*; use cmp::Ordering::*; -use default::Default; -use option::Option; -use option::Option::Some; // FIXME(#19630) Remove this work-around macro_rules! e { From 9a2c8783d91624261317316f996d8d2d09b7b6a4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 19:47:38 +0000 Subject: [PATCH 261/768] Use `#[prelude_import]` in `libstd`. --- src/libstd/ascii.rs | 3 --- src/libstd/collections/hash/map.rs | 2 -- src/libstd/collections/hash/set.rs | 2 -- src/libstd/env.rs | 3 --- src/libstd/error.rs | 6 ++---- src/libstd/ffi/c_str.rs | 12 ++---------- src/libstd/ffi/os_str.rs | 4 +--- src/libstd/fs.rs | 2 -- src/libstd/io/buffered.rs | 2 -- src/libstd/io/cursor.rs | 2 -- src/libstd/io/error.rs | 5 ----- src/libstd/io/impls.rs | 4 ---- src/libstd/io/lazy.rs | 2 -- src/libstd/io/mod.rs | 8 -------- src/libstd/io/stdio.rs | 1 - src/libstd/io/util.rs | 2 -- src/libstd/lib.rs | 5 +++++ src/libstd/net/addr.rs | 3 --- src/libstd/net/ip.rs | 1 - src/libstd/net/mod.rs | 2 -- src/libstd/net/parser.rs | 2 -- src/libstd/net/tcp.rs | 3 --- src/libstd/net/test.rs | 2 -- src/libstd/net/udp.rs | 2 -- src/libstd/num/mod.rs | 4 ---- src/libstd/panic.rs | 1 - src/libstd/panicking.rs | 1 - src/libstd/path.rs | 6 +----- src/libstd/process.rs | 2 -- src/libstd/rt.rs | 1 - src/libstd/sync/barrier.rs | 2 -- src/libstd/sync/condvar.rs | 4 ---- src/libstd/sync/mpsc/blocking.rs | 2 -- src/libstd/sync/mpsc/mod.rs | 4 ---- src/libstd/sync/mpsc/mpsc_queue.rs | 2 -- src/libstd/sync/mpsc/select.rs | 2 -- src/libstd/sync/mpsc/spsc_queue.rs | 2 -- src/libstd/sync/mpsc/sync.rs | 1 - src/libstd/sync/mutex.rs | 4 ---- src/libstd/sync/once.rs | 2 -- src/libstd/sync/rwlock.rs | 6 ------ src/libstd/sys/common/args.rs | 6 ------ src/libstd/sys/common/at_exit_imp.rs | 2 -- src/libstd/sys/common/backtrace.rs | 1 - src/libstd/sys/common/io.rs | 3 --- src/libstd/sys/common/mod.rs | 1 - src/libstd/sys/common/mutex.rs | 1 - src/libstd/sys/common/net.rs | 4 ---- src/libstd/sys/common/remutex.rs | 3 --- src/libstd/sys/common/thread.rs | 2 -- src/libstd/sys/common/thread_info.rs | 1 - src/libstd/sys/common/thread_local.rs | 1 - src/libstd/sys/common/wtf8.rs | 3 --- src/libstd/sys/unix/ext/ffi.rs | 1 - src/libstd/sys/unix/ext/net.rs | 2 -- src/libstd/sys/unix/ext/process.rs | 2 -- src/libstd/sys/unix/fd.rs | 2 -- src/libstd/sys/unix/fs.rs | 2 -- src/libstd/sys/unix/net.rs | 2 -- src/libstd/sys/unix/os.rs | 1 - src/libstd/sys/unix/os_str.rs | 2 -- src/libstd/sys/unix/pipe.rs | 2 -- src/libstd/sys/unix/process.rs | 2 -- src/libstd/sys/unix/stdio.rs | 2 -- src/libstd/sys/unix/thread.rs | 4 ---- src/libstd/sys/windows/compat.rs | 2 -- src/libstd/sys/windows/dynamic_lib.rs | 1 - src/libstd/sys/windows/fs.rs | 1 - src/libstd/sys/windows/handle.rs | 2 -- src/libstd/sys/windows/mod.rs | 2 -- src/libstd/sys/windows/mutex.rs | 2 -- src/libstd/sys/windows/net.rs | 2 -- src/libstd/sys/windows/os.rs | 1 - src/libstd/sys/windows/os_str.rs | 3 --- src/libstd/sys/windows/pipe.rs | 1 - src/libstd/sys/windows/process.rs | 3 --- src/libstd/sys/windows/stdio.rs | 1 - src/libstd/sys/windows/thread.rs | 2 -- src/libstd/sys/windows/thread_local.rs | 2 -- src/libstd/thread/local.rs | 7 ------- src/libstd/thread/mod.rs | 6 ------ 81 files changed, 11 insertions(+), 205 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 070d7ca1eef0f..a063b85646809 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -12,8 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use prelude::v1::*; - use mem; use ops::Range; use iter::FusedIterator; @@ -454,7 +452,6 @@ static ASCII_UPPERCASE_MAP: [u8; 256] = [ #[cfg(test)] mod tests { - use prelude::v1::*; use super::*; use char::from_u32; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ba27fafa59a3b..14da36ca4834e 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2059,8 +2059,6 @@ fn assert_covariance() { #[cfg(test)] mod test_map { - use prelude::v1::*; - use super::HashMap; use super::Entry::{Occupied, Vacant}; use cell::RefCell; diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 96efff86abf17..ca5137e957362 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1067,8 +1067,6 @@ fn assert_covariance() { #[cfg(test)] mod test_set { - use prelude::v1::*; - use super::HashSet; #[test] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 753411991abea..7a94c39621808 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -16,8 +16,6 @@ #![stable(feature = "env", since = "1.0.0")] -use prelude::v1::*; - use error::Error; use ffi::{OsStr, OsString}; use fmt; @@ -950,7 +948,6 @@ mod arch { #[cfg(test)] mod tests { - use prelude::v1::*; use super::*; use iter::repeat; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 914599271aca2..44595361fb57c 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -48,16 +48,15 @@ // reconsider what crate these items belong in. use any::TypeId; -use boxed::Box; use cell; use char; use fmt::{self, Debug, Display}; -use marker::{Send, Sync, Reflect}; +use marker::Reflect; use mem::transmute; use num; use raw::TraitObject; use str; -use string::{self, String}; +use string; /// Base functionality for all errors in Rust. #[stable(feature = "rust1", since = "1.0.0")] @@ -454,7 +453,6 @@ impl Error + Send + Sync { #[cfg(test)] mod tests { - use prelude::v1::*; use super::Error; use fmt; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 5dae1a09bf410..38222c014f61b 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -9,25 +9,18 @@ // except according to those terms. use ascii; -use borrow::{Cow, ToOwned, Borrow}; -use boxed::Box; -use convert::{Into, From}; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use borrow::{Cow, Borrow}; +use cmp::Ordering; use error::Error; use fmt::{self, Write}; use io; -use iter::Iterator; use libc; use mem; use memchr; use ops; -use option::Option::{self, Some, None}; use os::raw::c_char; -use result::Result::{self, Ok, Err}; use slice; use str::{self, Utf8Error}; -use string::String; -use vec::Vec; /// A type representing an owned C-compatible string /// @@ -700,7 +693,6 @@ impl AsRef for CString { #[cfg(test)] mod tests { - use prelude::v1::*; use super::*; use os::raw::c_char; use borrow::Cow::{Borrowed, Owned}; diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 3d23a9a2383ff..36cf4ef758d8e 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use borrow::{Borrow, Cow, ToOwned}; +use borrow::{Borrow, Cow}; use fmt::{self, Debug}; use mem; -use string::String; use ops; use cmp; use hash::{Hash, Hasher}; -use vec::Vec; use sys::os_str::{Buf, Slice}; use sys_common::{AsInner, IntoInner, FromInner}; diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index b78db24e44b70..f2374e722c1e3 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -23,7 +23,6 @@ use io::{self, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; -use vec::Vec; use time::SystemTime; /// A reference to an open file on the filesystem. @@ -1677,7 +1676,6 @@ impl AsInnerMut for DirBuilder { #[cfg(test)] mod tests { - use prelude::v1::*; use io::prelude::*; use fs::{self, File, OpenOptions}; diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a92ca95f4ee7e..a26a932ad2de6 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -10,7 +10,6 @@ //! Buffering wrappers for I/O traits -use prelude::v1::*; use io::prelude::*; use marker::Reflect; @@ -788,7 +787,6 @@ impl fmt::Debug for LineWriter where W: fmt::Debug { #[cfg(test)] mod tests { - use prelude::v1::*; use io::prelude::*; use io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; use sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 2d780559db122..1b836b745372f 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use io::prelude::*; use cmp; @@ -284,7 +283,6 @@ impl Write for Cursor> { mod tests { use io::prelude::*; use io::{Cursor, SeekFrom}; - use vec::Vec; #[test] fn test_vec_writer() { diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 5333b0a531eae..d90be2e08a9fc 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -8,12 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use boxed::Box; -use convert::Into; use error; use fmt; -use marker::{Send, Sync}; -use option::Option::{self, Some, None}; use result; use sys; @@ -522,7 +518,6 @@ fn _assert_error_is_sync_send() { #[cfg(test)] mod test { - use prelude::v1::*; use super::{Error, ErrorKind}; use error; use fmt; diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index 317993815630b..cd05e6b5de9d2 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use boxed::Box; use cmp; use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind}; use fmt; use mem; -use string::String; -use vec::Vec; // ============================================================================= // Forwarding implementations @@ -228,7 +225,6 @@ impl Write for Vec { #[cfg(test)] mod tests { use io::prelude::*; - use vec::Vec; use test; #[bench] diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 1155160120750..ce205c3b11ca5 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use cell::Cell; use ptr; use sync::Arc; diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 307d014fd68c6..1053792cd439b 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -253,15 +253,8 @@ use cmp; use rustc_unicode::str as core_str; use error as std_error; use fmt; -use iter::{Iterator}; -use marker::Sized; -use ops::{Drop, FnOnce}; -use option::Option::{self, Some, None}; -use result::Result::{Ok, Err}; use result; -use string::String; use str; -use vec::Vec; use memchr; #[stable(feature = "rust1", since = "1.0.0")] @@ -1734,7 +1727,6 @@ impl Iterator for Lines { #[cfg(test)] mod tests { - use prelude::v1::*; use io::prelude::*; use io; use super::Cursor; diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index b8b66a58359e7..9a782e95f6e5f 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use io::prelude::*; use cell::{RefCell, BorrowState}; diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index c8b52fc046769..2c6880281b5e6 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -167,8 +167,6 @@ impl Write for Sink { #[cfg(test)] mod tests { - use prelude::v1::*; - use io::prelude::*; use io::{copy, sink, empty, repeat}; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d4644a190f4d9..9a8cd0c712f06 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,6 +252,7 @@ #![feature(optin_builtin_traits)] #![feature(panic_unwind)] #![feature(placement_in_syntax)] +#![feature(prelude_import)] #![feature(question_mark)] #![feature(rand)] #![feature(raw)] @@ -292,6 +293,10 @@ #![allow(unused_features)] // std may use features in a platform-specific way #![cfg_attr(not(stage0), deny(warnings))] +#[prelude_import] +#[allow(unused)] +use prelude::v1::*; + #[cfg(test)] extern crate test; // We want to reexport a few macros from core but libcore has already been diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index b93ca8277e636..d0b59b42c1798 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use fmt; use hash; use io; @@ -523,7 +521,6 @@ impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T { #[cfg(test)] mod tests { - use prelude::v1::*; use net::*; use net::test::{tsa, sa6, sa4}; diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 4c3b993497cf5..c6a7a77e68a6b 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -653,7 +653,6 @@ impl From<[u8; 16]> for Ipv6Addr { // Tests for this module #[cfg(test)] mod tests { - use prelude::v1::*; use net::*; use net::Ipv6MulticastScope::*; use net::test::{tsa, sa6, sa4}; diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 11a16b271133b..2a78afa85f7f0 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -12,8 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use prelude::v1::*; - use io::{self, Error, ErrorKind}; use sys_common::net as net_imp; diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 5851ce7135d27..854d87c4cbead 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -13,8 +13,6 @@ //! This module is "publicly exported" through the `FromStr` implementations //! below. -use prelude::v1::*; - use error::Error; use fmt; use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 76617f159707d..dcd3652af876b 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use io::prelude::*; use fmt; @@ -438,8 +437,6 @@ impl fmt::Debug for TcpListener { #[cfg(test)] mod tests { - use prelude::v1::*; - use io::ErrorKind; use io::prelude::*; use net::*; diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs index 9665fd722872f..98ac61f646113 100644 --- a/src/libstd/net/test.rs +++ b/src/libstd/net/test.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use env; use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 9d0279deb1bcb..781f026c12c77 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -355,8 +355,6 @@ impl fmt::Debug for UdpSocket { #[cfg(test)] mod tests { - use prelude::v1::*; - use io::ErrorKind; use net::*; use net::test::{next_test_ip4, next_test_ip6}; diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 20804d62dfab6..d1c2fc3d3fce9 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -24,9 +24,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; -#[cfg(test)] use cmp::PartialEq; #[cfg(test)] use fmt; -#[cfg(test)] use marker::Copy; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; /// Helper function for testing numeric operations @@ -52,7 +50,6 @@ mod tests { use u32; use u64; use usize; - use string::ToString; use ops::Mul; #[test] @@ -287,7 +284,6 @@ mod tests { mod bench { extern crate test; use self::test::Bencher; - use prelude::v1::*; #[bench] fn bench_pow_function(b: &mut Bencher) { diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 2f67081e0d710..47f594a9b0c1e 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -13,7 +13,6 @@ #![stable(feature = "std_panic", since = "1.9.0")] use any::Any; -use boxed::Box; use cell::UnsafeCell; use ops::{Deref, DerefMut}; use panicking; diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 5961fd59699c1..0c10dcbdad646 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -17,7 +17,6 @@ //! * Executing a panic up to doing the actual implementation //! * Shims around "try" -use prelude::v1::*; use io::prelude::*; use any::Any; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index bc8fd66a438f5..67219b6fd1b9c 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -100,7 +100,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use ascii::*; -use borrow::{Borrow, ToOwned, Cow}; +use borrow::{Borrow, Cow}; use cmp; use error::Error; use fmt; @@ -110,8 +110,6 @@ use io; use iter::{self, FusedIterator}; use mem; use ops::{self, Deref}; -use string::String; -use vec::Vec; use ffi::{OsStr, OsString}; @@ -2152,8 +2150,6 @@ impl Error for StripPrefixError { #[cfg(test)] mod tests { use super::*; - use string::{ToString, String}; - use vec::Vec; macro_rules! t( ($path:expr, iter: $iter:expr) => ( diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 660c098d30bc2..f0c4443070074 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -12,7 +12,6 @@ #![stable(feature = "process", since = "1.0.0")] -use prelude::v1::*; use io::prelude::*; use ffi::OsStr; @@ -810,7 +809,6 @@ pub fn exit(code: i32) -> ! { #[cfg(test)] mod tests { - use prelude::v1::*; use io::prelude::*; use io::ErrorKind; diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index a3d9e4db7d19a..e3de1efaa31e3 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -30,7 +30,6 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; #[cfg(not(test))] #[lang = "start"] fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { - use borrow::ToOwned; use mem; use panic; use sys; diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index b1267acdee61a..ac0f400379e3c 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -113,8 +113,6 @@ impl BarrierWaitResult { #[cfg(test)] mod tests { - use prelude::v1::*; - use sync::{Arc, Barrier}; use sync::mpsc::{channel, TryRecvError}; use thread; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 3c52ebc72f2cb..1f480f6d4a987 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use sync::atomic::{AtomicUsize, Ordering}; use sync::{mutex, MutexGuard, PoisonError}; use sys_common::condvar as sys; @@ -245,8 +243,6 @@ impl Drop for Condvar { #[cfg(test)] mod tests { - use prelude::v1::*; - use sync::mpsc::channel; use sync::{Condvar, Mutex, Arc}; use thread; diff --git a/src/libstd/sync/mpsc/blocking.rs b/src/libstd/sync/mpsc/blocking.rs index 4a70de0e7d8fc..0f9ef6fabb005 100644 --- a/src/libstd/sync/mpsc/blocking.rs +++ b/src/libstd/sync/mpsc/blocking.rs @@ -13,9 +13,7 @@ use thread::{self, Thread}; use sync::atomic::{AtomicBool, Ordering}; use sync::Arc; -use marker::{Sync, Send}; use mem; -use clone::Clone; use time::Instant; struct Inner { diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index d8b8c6a77a266..3d9f81413dc73 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1270,8 +1270,6 @@ impl error::Error for TryRecvError { #[cfg(test)] mod tests { - use prelude::v1::*; - use env; use super::*; use thread; @@ -1946,8 +1944,6 @@ mod tests { #[cfg(test)] mod sync_tests { - use prelude::v1::*; - use env; use thread; use super::*; diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 6a6c19cfcc308..d926043fbbcd0 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -148,8 +148,6 @@ impl Drop for Queue { #[cfg(test)] mod tests { - use prelude::v1::*; - use sync::mpsc::channel; use super::{Queue, Data, Empty, Inconsistent}; use sync::Arc; diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 5aa4ce81b8ae4..677544d335e7a 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -369,8 +369,6 @@ impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> { #[cfg(test)] #[allow(unused_imports)] mod tests { - use prelude::v1::*; - use thread; use sync::mpsc::*; diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 02506e7c2f3d9..724d7b1be730d 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -233,8 +233,6 @@ impl Drop for Queue { #[cfg(test)] mod tests { - use prelude::v1::*; - use sync::Arc; use super::Queue; use thread; diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 9d13a71ff95ee..9985daaba8f69 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -36,7 +36,6 @@ pub use self::Failure::*; use self::Blocker::*; -use vec::Vec; use core::mem; use core::ptr; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 6bc458397f163..c8ae88c233106 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use cell::UnsafeCell; use fmt; use marker; @@ -355,8 +353,6 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla #[cfg(test)] mod tests { - use prelude::v1::*; - use sync::mpsc::channel; use sync::{Arc, Mutex, Condvar}; use sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 54c1fe6c5640c..86d2986959c99 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -369,8 +369,6 @@ impl OnceState { #[cfg(test)] mod tests { - use prelude::v1::*; - use panic; use sync::mpsc::channel; use thread; diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 65b5686de869c..4801bcffd081c 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use cell::UnsafeCell; use fmt; use marker; @@ -385,8 +383,6 @@ impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { mod tests { #![allow(deprecated)] // rand - use prelude::v1::*; - use rand::{self, Rng}; use sync::mpsc::channel; use thread; @@ -552,8 +548,6 @@ mod tests { #[test] fn test_rwlock_try_write() { - use mem::drop; - let lock = RwLock::new(0isize); let read_guard = lock.read().unwrap(); diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs index e877391fb8b56..fad2c277da417 100644 --- a/src/libstd/sys/common/args.rs +++ b/src/libstd/sys/common/args.rs @@ -21,8 +21,6 @@ #![allow(dead_code)] // different code on OSX/linux/etc -use vec::Vec; - /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } @@ -42,8 +40,6 @@ pub fn clone() -> Option>> { imp::clone() } target_os = "solaris", target_os = "emscripten"))] mod imp { - use prelude::v1::*; - use libc::c_char; use mem; use ffi::CStr; @@ -91,8 +87,6 @@ mod imp { target_os = "ios", target_os = "windows"))] mod imp { - use vec::Vec; - pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } diff --git a/src/libstd/sys/common/at_exit_imp.rs b/src/libstd/sys/common/at_exit_imp.rs index b2683750d67e2..ce6fd4cb0754b 100644 --- a/src/libstd/sys/common/at_exit_imp.rs +++ b/src/libstd/sys/common/at_exit_imp.rs @@ -13,10 +13,8 @@ //! Documentation can be found on the `rt::at_exit` function. use alloc::boxed::FnBox; -use boxed::Box; use ptr; use sys_common::mutex::Mutex; -use vec::Vec; type Queue = Vec>; diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index 4c23ceb63f287..c1d1792363d70 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -191,7 +191,6 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { #[cfg(test)] mod tests { - use prelude::v1::*; use sys_common; macro_rules! t { ($a:expr, $b:expr) => ({ let mut m = Vec::new(); diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys/common/io.rs index 7b08852ba51d1..3cd70eddb858c 100644 --- a/src/libstd/sys/common/io.rs +++ b/src/libstd/sys/common/io.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use io; use io::ErrorKind; use io::Read; @@ -53,7 +52,6 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec) -> io:: #[cfg(test)] pub mod test { - use prelude::v1::*; use path::{Path, PathBuf}; use env; use rand::{self, Rng}; @@ -93,7 +91,6 @@ pub mod test { #[cfg(test)] mod tests { - use prelude::v1::*; use io::prelude::*; use super::*; use io; diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index a1f3f477b3ab7..d1ca676510714 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -10,7 +10,6 @@ #![allow(missing_docs)] -use boxed::Box; use sync::Once; use sys; diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 7a2183c522f5b..d1a738770d389 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use marker::Sync; use sys::mutex as imp; /// An OS-based mutual exclusion lock. diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 442618c55b337..a777cfe35e56d 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use cmp; use ffi::CString; use fmt; @@ -608,8 +606,6 @@ impl fmt::Debug for UdpSocket { #[cfg(test)] mod tests { - use prelude::v1::*; - use super::*; use collections::HashMap; diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys/common/remutex.rs index 39d4104246732..cbdeaad7f6bd3 100644 --- a/src/libstd/sys/common/remutex.rs +++ b/src/libstd/sys/common/remutex.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use fmt; use marker; use ops::Deref; @@ -160,7 +158,6 @@ impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { #[cfg(test)] mod tests { - use prelude::v1::*; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use cell::RefCell; use sync::Arc; diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs index 16f4f01bf39fe..3ee160da5fa5b 100644 --- a/src/libstd/sys/common/thread.rs +++ b/src/libstd/sys/common/thread.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use alloc::boxed::FnBox; use libc; use sys::stack_overflow; diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index 0467c67167bd5..95d8b6cc9516d 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -11,7 +11,6 @@ #![allow(dead_code)] // stack_guard isn't used right now on all platforms use cell::RefCell; -use string::String; use thread::Thread; use thread::LocalKeyState; diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 56885cdd56d99..25a9d5720d933 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -233,7 +233,6 @@ impl Drop for Key { #[cfg(test)] mod tests { - use prelude::v1::*; use super::{Key, StaticKey}; fn assert_sync() {} diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index c1b4f8a8c88c5..8d357aa78c9e9 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -37,9 +37,7 @@ use mem; use ops; use slice; use str; -use string::String; use sys_common::AsInner; -use vec::Vec; const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD"; @@ -807,7 +805,6 @@ impl AsciiExt for Wtf8 { #[cfg(test)] mod tests { - use prelude::v1::*; use borrow::Cow; use super::*; diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index 825e74cabdebb..d59b4fc0b70b8 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -14,7 +14,6 @@ use ffi::{OsStr, OsString}; use mem; -use prelude::v1::*; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index a4564b9543b34..3f93fce193561 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -14,7 +14,6 @@ use libc; -use prelude::v1::*; use ascii; use ffi::OsStr; use fmt; @@ -789,7 +788,6 @@ impl IntoRawFd for UnixDatagram { #[cfg(test)] mod test { - use prelude::v1::*; use thread; use io; use io::prelude::*; diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index dd70ba2e490ad..5bd92f2eb574d 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -12,8 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use prelude::v1::*; - use io; use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; use process; diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index b99f4a2eacde5..b2b1f16f20a9a 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -10,8 +10,6 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] -use prelude::v1::*; - use io::{self, Read}; use libc::{self, c_int, size_t, c_void}; use mem; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 3b132744f7055..e6fe3eb112a60 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use os::unix::prelude::*; use ffi::{CString, CStr, OsString, OsStr}; @@ -534,7 +533,6 @@ impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[cfg(target_os = "linux")] fn get_path(fd: c_int) -> Option { - use string::ToString; let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); readlink(&p).ok() diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 6f1b70acb60bc..3f77abd7f44d8 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use ffi::CStr; use io; use libc::{self, c_int, size_t, sockaddr, socklen_t}; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index c29e87f91c9a7..e61804efd50f6 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -12,7 +12,6 @@ #![allow(unused_imports)] // lots of cfg code here -use prelude::v1::*; use os::unix::prelude::*; use error::Error as StdError; diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index d5eea5d1f3be5..5a733c0cb8763 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -13,9 +13,7 @@ use borrow::Cow; use fmt::{self, Debug}; -use vec::Vec; use str; -use string::String; use mem; use sys_common::{AsInner, IntoInner}; diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 010594133387a..ffe8032e46055 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use cmp; use io; use libc::{self, c_int}; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index d68867fb3d2ce..50014f51f6cf4 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use os::unix::prelude::*; use collections::hash_map::{HashMap, Entry}; @@ -593,7 +592,6 @@ impl Process { #[cfg(test)] mod tests { use super::*; - use prelude::v1::*; use ffi::OsStr; use mem; diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 37d1d9a969ed8..972bdbc38186b 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use io; use libc; use sys::fd::FileDesc; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 75e10d2585308..5db7086e42752 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use alloc::boxed::FnBox; use cmp; use ffi::CStr; @@ -193,8 +191,6 @@ pub mod guard { target_os = "solaris"))] #[cfg_attr(test, allow(dead_code))] pub mod guard { - use prelude::v1::*; - use libc; use libc::mmap; use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; diff --git a/src/libstd/sys/windows/compat.rs b/src/libstd/sys/windows/compat.rs index acbfacce8bd7f..cd42b7d05ee38 100644 --- a/src/libstd/sys/windows/compat.rs +++ b/src/libstd/sys/windows/compat.rs @@ -21,8 +21,6 @@ //! manner we pay a semi-large one-time cost up front for detecting whether a //! function is available but afterwards it's just a load and a jump. -use prelude::v1::*; - use ffi::CString; use sync::atomic::{AtomicUsize, Ordering}; use sys::c; diff --git a/src/libstd/sys/windows/dynamic_lib.rs b/src/libstd/sys/windows/dynamic_lib.rs index dde13ec8364b6..5227280808f5b 100644 --- a/src/libstd/sys/windows/dynamic_lib.rs +++ b/src/libstd/sys/windows/dynamic_lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use os::windows::prelude::*; use ffi::{CString, OsStr}; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 4e6cef9a28d8f..fe448cdd78feb 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use os::windows::prelude::*; use ffi::OsString; diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index d10abae286527..97e746ee34576 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -10,8 +10,6 @@ #![unstable(issue = "0", feature = "windows_handle")] -use prelude::v1::*; - use cmp; use io::{ErrorKind, Read}; use io; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 12219c1e9d42b..9741a704e8fe5 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -10,8 +10,6 @@ #![allow(missing_docs, bad_style)] -use prelude::v1::*; - use ffi::{OsStr, OsString}; use io::{self, ErrorKind}; use os::windows::ffi::{OsStrExt, OsStringExt}; diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 8762b34e3da48..8556036859059 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -29,8 +29,6 @@ //! CriticalSection is used and we keep track of who's holding the mutex to //! detect recursive locks. -use prelude::v1::*; - use cell::UnsafeCell; use mem; use sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index 71e164f012f1f..aca6994503ff8 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -10,8 +10,6 @@ #![unstable(issue = "0", feature = "windows_net")] -use prelude::v1::*; - use cmp; use io::{self, Read}; use libc::{c_int, c_void, c_ulong}; diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 0cea7f81e3632..260fc3c4db62e 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -12,7 +12,6 @@ #![allow(bad_style)] -use prelude::v1::*; use os::windows::prelude::*; use error::Error as StdError; diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 26767a1349e6f..a065c7a7fd013 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -14,9 +14,6 @@ use borrow::Cow; use fmt::{self, Debug}; use sys_common::wtf8::{Wtf8, Wtf8Buf}; -use string::String; -use result::Result; -use option::Option; use mem; use sys_common::{AsInner, IntoInner}; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 6e9c67051a6eb..ed7e88e72cd56 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; use os::windows::prelude::*; use ffi::OsStr; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 3ca75cf364376..d371714ff0e69 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use ascii::*; use collections::HashMap; use collections; @@ -491,7 +489,6 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { #[cfg(test)] mod tests { - use prelude::v1::*; use ffi::{OsStr, OsString}; use super::make_command_line; diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index fa3cab2191edd..01249f05f6202 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -10,7 +10,6 @@ #![unstable(issue = "0", feature = "windows_stdio")] -use prelude::v1::*; use io::prelude::*; use cmp; diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 0383e92c79ec7..5a376a867ee64 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use alloc::boxed::FnBox; use io; use ffi::CStr; diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 59da74b728797..5d3084094fbdd 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::v1::*; - use ptr; use sys::c; use sys_common::mutex::Mutex; diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 152b9771086b8..c44dee49f14a6 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -369,7 +369,6 @@ pub mod elf { // Due to rust-lang/rust#18804, make sure this is not generic! #[cfg(target_os = "linux")] unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use prelude::v1::*; use mem; use libc; use sys_common::thread_local as os; @@ -460,8 +459,6 @@ pub mod elf { #[doc(hidden)] pub mod os { - use prelude::v1::*; - use cell::{Cell, UnsafeCell}; use marker; use ptr; @@ -529,8 +526,6 @@ pub mod os { #[cfg(test)] mod tests { - use prelude::v1::*; - use sync::mpsc::{channel, Sender}; use cell::{Cell, UnsafeCell}; use super::LocalKeyState; @@ -693,8 +688,6 @@ mod tests { #[cfg(test)] mod dynamic_tests { - use prelude::v1::*; - use cell::RefCell; use collections::HashMap; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index f06c105d30e65..f3e1710f50b0d 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -161,8 +161,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use prelude::v1::*; - use any::Any; use cell::UnsafeCell; use ffi::{CStr, CString}; @@ -732,8 +730,6 @@ fn _assert_sync_and_send() { #[cfg(test)] mod tests { - use prelude::v1::*; - use any::Any; use sync::mpsc::{channel, Sender}; use result; @@ -786,8 +782,6 @@ mod tests { #[test] fn test_spawn_sched() { - use clone::Clone; - let (tx, rx) = channel(); fn f(i: i32, tx: Sender<()>) { From a9a2979dbaddc540673cf66da52e8eb45e66b055 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 20:16:36 +0000 Subject: [PATCH 262/768] Remove needless imports in `libcollections`. --- src/libcollections/binary_heap.rs | 2 +- src/libcollections/borrow.rs | 7 +------ src/libcollections/linked_list.rs | 4 ---- src/libcollections/range.rs | 1 - src/libcollections/vec_deque.rs | 3 --- 5 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index c062ae62b0049..5ece27372e130 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -151,7 +151,7 @@ #![allow(missing_docs)] #![stable(feature = "rust1", since = "1.0.0")] -use core::ops::{Drop, Deref, DerefMut}; +use core::ops::{Deref, DerefMut}; use core::iter::{FromIterator, FusedIterator}; use core::mem::swap; use core::mem::size_of; diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 37dbeb4eae17d..3ad1d08298581 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -12,14 +12,9 @@ #![stable(feature = "rust1", since = "1.0.0")] -use core::clone::Clone; -use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; -use core::convert::AsRef; -use core::default::Default; +use core::cmp::Ordering; use core::hash::{Hash, Hasher}; -use core::marker::Sized; use core::ops::Deref; -use core::option::Option; use fmt; diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 8b8bea0ca45a1..769c5162a4560 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -1159,9 +1159,6 @@ unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} #[cfg(test)] mod tests { - use std::clone::Clone; - use std::iter::{Iterator, IntoIterator, Extend}; - use std::option::Option::{self, Some, None}; use std::__rand::{thread_rng, Rng}; use std::thread; use std::vec::Vec; @@ -1319,7 +1316,6 @@ mod tests { #[test] fn test_26021() { - use std::iter::ExactSizeIterator; // There was a bug in split_off that failed to null out the RHS's head's prev ptr. // This caused the RHS's dtor to walk up into the LHS at drop and delete all of // its nodes. diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 1badc72aed07c..d331ead2c5ee6 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -14,7 +14,6 @@ //! Range syntax. -use core::option::Option::{self, None, Some}; use core::ops::{RangeFull, Range, RangeTo, RangeFrom}; /// **RangeArgument** is implemented by Rust's built-in range types, produced diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 6f220c1d472a6..96624f121b2af 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -2332,9 +2332,6 @@ impl From> for Vec { #[cfg(test)] mod tests { - use core::iter::Iterator; - use core::option::Option::Some; - use test; use super::VecDeque; From 28ecfb691d4690ac8f3f6a2fb7d390a1f4abbbb0 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 13:36:52 -0400 Subject: [PATCH 263/768] =?UTF-8?q?Move=20ItemEnum=20=E2=86=92=20Generics?= =?UTF-8?q?=20logic=20into=20method=20on=20ItemEnum.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustdoc/clean/mod.rs | 17 +++++++++++++++++ src/librustdoc/html/render.rs | 13 ++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 39b1a04e98e69..7a4558d7b79e4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -380,6 +380,23 @@ pub enum ItemEnum { StrippedItem(Box), } +impl ItemEnum { + pub fn generics(&self) -> Option<&Generics> { + Some(match *self { + ItemEnum::StructItem(ref s) => &s.generics, + ItemEnum::EnumItem(ref e) => &e.generics, + ItemEnum::FunctionItem(ref f) => &f.generics, + ItemEnum::TypedefItem(ref t, _) => &t.generics, + ItemEnum::TraitItem(ref t) => &t.generics, + ItemEnum::ImplItem(ref i) => &i.generics, + ItemEnum::TyMethodItem(ref i) => &i.generics, + ItemEnum::MethodItem(ref i) => &i.generics, + ItemEnum::ForeignFunctionItem(ref f) => &f.generics, + _ => return None, + }) + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Module { pub items: Vec, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e02cfb96dddf1..289b967333573 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -997,17 +997,8 @@ impl DocFolder for Cache { // Register any generics to their corresponding string. This is used // when pretty-printing types - match item.inner { - clean::StructItem(ref s) => self.generics(&s.generics), - clean::EnumItem(ref e) => self.generics(&e.generics), - clean::FunctionItem(ref f) => self.generics(&f.generics), - clean::TypedefItem(ref t, _) => self.generics(&t.generics), - clean::TraitItem(ref t) => self.generics(&t.generics), - clean::ImplItem(ref i) => self.generics(&i.generics), - clean::TyMethodItem(ref i) => self.generics(&i.generics), - clean::MethodItem(ref i) => self.generics(&i.generics), - clean::ForeignFunctionItem(ref f) => self.generics(&f.generics), - _ => {} + if let Some(generics) = item.inner.generics() { + self.generics(generics); } if !self.seen_mod { From 7dc411667a313f438f9edecb0b19b58d17596915 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 14:22:08 -0400 Subject: [PATCH 264/768] Migrate Context::maybe_ignore_item method to standalone function. The method wasn't using any `self` data from Context, so it seemed miseading to implement it as a method. --- src/librustdoc/html/render.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 289b967333573..5b878c22e79b4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1353,7 +1353,7 @@ impl Context { // these modules are recursed into, but not rendered normally // (a flag on the context). if !self.render_redirect_pages { - self.render_redirect_pages = self.maybe_ignore_item(&item); + self.render_redirect_pages = maybe_ignore_item(&item); } if item.is_mod() { @@ -1436,7 +1436,7 @@ impl Context { // BTreeMap instead of HashMap to get a sorted output let mut map = BTreeMap::new(); for item in &m.items { - if self.maybe_ignore_item(item) { continue } + if maybe_ignore_item(item) { continue } let short = item_type(item).css_class(); let myname = match item.name { @@ -1453,17 +1453,6 @@ impl Context { } return map; } - - fn maybe_ignore_item(&self, it: &clean::Item) -> bool { - match it.inner { - clean::StrippedItem(..) => true, - clean::ModuleItem(ref m) => { - it.doc_value().is_none() && m.items.is_empty() - && it.visibility != Some(clean::Public) - }, - _ => false, - } - } } impl<'a> Item<'a> { @@ -1706,7 +1695,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, if let clean::DefaultImplItem(..) = items[*i].inner { return false; } - !cx.maybe_ignore_item(&items[*i]) + !maybe_ignore_item(&items[*i]) }).collect::>(); // the order of item types in the listing @@ -1854,6 +1843,17 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, Ok(()) } +fn maybe_ignore_item(it: &clean::Item) -> bool { + match it.inner { + clean::StrippedItem(..) => true, + clean::ModuleItem(ref m) => { + it.doc_value().is_none() && m.items.is_empty() + && it.visibility != Some(clean::Public) + }, + _ => false, + } +} + fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec { let mut stability = vec![]; From 30397aee0ddb1a835aefa7e786810acadde53388 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 14:22:16 -0400 Subject: [PATCH 265/768] Migrate ItemType::from_item to convert::From. --- src/librustdoc/clean/mod.rs | 20 ++++++++++---------- src/librustdoc/html/item_type.rs | 6 ++++-- src/librustdoc/html/render.rs | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7a4558d7b79e4..d5149293e099a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -287,34 +287,34 @@ impl Item { } } pub fn is_mod(&self) -> bool { - ItemType::from_item(self) == ItemType::Module + ItemType::from(self) == ItemType::Module } pub fn is_trait(&self) -> bool { - ItemType::from_item(self) == ItemType::Trait + ItemType::from(self) == ItemType::Trait } pub fn is_struct(&self) -> bool { - ItemType::from_item(self) == ItemType::Struct + ItemType::from(self) == ItemType::Struct } pub fn is_enum(&self) -> bool { - ItemType::from_item(self) == ItemType::Module + ItemType::from(self) == ItemType::Module } pub fn is_fn(&self) -> bool { - ItemType::from_item(self) == ItemType::Function + ItemType::from(self) == ItemType::Function } pub fn is_associated_type(&self) -> bool { - ItemType::from_item(self) == ItemType::AssociatedType + ItemType::from(self) == ItemType::AssociatedType } pub fn is_associated_const(&self) -> bool { - ItemType::from_item(self) == ItemType::AssociatedConst + ItemType::from(self) == ItemType::AssociatedConst } pub fn is_method(&self) -> bool { - ItemType::from_item(self) == ItemType::Method + ItemType::from(self) == ItemType::Method } pub fn is_ty_method(&self) -> bool { - ItemType::from_item(self) == ItemType::TyMethod + ItemType::from(self) == ItemType::TyMethod } pub fn is_primitive(&self) -> bool { - ItemType::from_item(self) == ItemType::Primitive + ItemType::from(self) == ItemType::Primitive } pub fn is_stripped(&self) -> bool { match self.inner { StrippedItem(..) => true, _ => false } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 6b462a76f04ed..31d965fccc2c0 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -50,8 +50,8 @@ pub enum NameSpace { Macro, } -impl ItemType { - pub fn from_item(item: &clean::Item) -> ItemType { +impl<'a> From<&'a clean::Item> for ItemType { + fn from(item: &'a clean::Item) -> ItemType { let inner = match item.inner { clean::StrippedItem(box ref item) => item, ref inner@_ => inner, @@ -83,7 +83,9 @@ impl ItemType { clean::StrippedItem(..) => unreachable!(), } } +} +impl ItemType { pub fn from_type_kind(kind: clean::TypeKind) -> ItemType { match kind { clean::TypeStruct => ItemType::Struct, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5b878c22e79b4..66f54587e6b32 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -833,7 +833,7 @@ fn mkdir(path: &Path) -> io::Result<()> { /// Returns a documentation-level item type from the item. fn item_type(item: &clean::Item) -> ItemType { - ItemType::from_item(item) + ItemType::from(item) } /// Takes a path to a source file and cleans the path to it. This canonicalizes From 0c9ff541396285ac441c5029ae4f0869edc97044 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 15:55:43 -0400 Subject: [PATCH 266/768] Migrate ItemType::from_type_kind to convert::From. --- src/librustdoc/html/item_type.rs | 6 ++++-- src/librustdoc/html/render.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 31d965fccc2c0..be19217928467 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -85,8 +85,8 @@ impl<'a> From<&'a clean::Item> for ItemType { } } -impl ItemType { - pub fn from_type_kind(kind: clean::TypeKind) -> ItemType { +impl From for ItemType { + fn from(kind: clean::TypeKind) -> ItemType { match kind { clean::TypeStruct => ItemType::Struct, clean::TypeEnum => ItemType::Enum, @@ -99,7 +99,9 @@ impl ItemType { clean::TypeTypedef => ItemType::Typedef, } } +} +impl ItemType { pub fn css_class(&self) -> &'static str { match *self { ItemType::Module => "mod", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 66f54587e6b32..6993f85c3d9a4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -509,7 +509,7 @@ pub fn run(mut krate: clean::Crate, } = renderinfo; let external_paths = external_paths.into_iter() - .map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))) + .map(|(k, (v, t))| (k, (v, ItemType::from(t)))) .collect(); let mut cache = Cache { From 9dde5639908263bb3348616438c59d184fb29530 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 18:48:10 -0400 Subject: [PATCH 267/768] Stop reexporting `PrimitiveType` enum in librustdoc. --- src/librustdoc/clean/mod.rs | 183 +++++++++++++++++----------------- src/librustdoc/html/format.rs | 27 ++--- 2 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d5149293e099a..7e599569a282e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -12,7 +12,6 @@ //! that clean them. pub use self::Type::*; -pub use self::PrimitiveType::*; pub use self::TypeKind::*; pub use self::VariantKind::*; pub use self::Mutability::*; @@ -1517,12 +1516,12 @@ impl Type { pub fn primitive_type(&self) -> Option { match *self { Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p), - Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice), + Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(PrimitiveType::Slice), FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => { - Some(Array) + Some(PrimitiveType::Array) } - Tuple(..) => Some(PrimitiveTuple), - RawPointer(..) => Some(PrimitiveRawPointer), + Tuple(..) => Some(PrimitiveType::PrimitiveTuple), + RawPointer(..) => Some(PrimitiveType::PrimitiveRawPointer), _ => None, } } @@ -1547,25 +1546,25 @@ impl GetDefId for Type { impl PrimitiveType { fn from_str(s: &str) -> Option { match s { - "isize" => Some(Isize), - "i8" => Some(I8), - "i16" => Some(I16), - "i32" => Some(I32), - "i64" => Some(I64), - "usize" => Some(Usize), - "u8" => Some(U8), - "u16" => Some(U16), - "u32" => Some(U32), - "u64" => Some(U64), - "bool" => Some(Bool), - "char" => Some(Char), - "str" => Some(Str), - "f32" => Some(F32), - "f64" => Some(F64), - "array" => Some(Array), - "slice" => Some(Slice), - "tuple" => Some(PrimitiveTuple), - "pointer" => Some(PrimitiveRawPointer), + "isize" => Some(PrimitiveType::Isize), + "i8" => Some(PrimitiveType::I8), + "i16" => Some(PrimitiveType::I16), + "i32" => Some(PrimitiveType::I32), + "i64" => Some(PrimitiveType::I64), + "usize" => Some(PrimitiveType::Usize), + "u8" => Some(PrimitiveType::U8), + "u16" => Some(PrimitiveType::U16), + "u32" => Some(PrimitiveType::U32), + "u64" => Some(PrimitiveType::U64), + "bool" => Some(PrimitiveType::Bool), + "char" => Some(PrimitiveType::Char), + "str" => Some(PrimitiveType::Str), + "f32" => Some(PrimitiveType::F32), + "f64" => Some(PrimitiveType::F64), + "array" => Some(PrimitiveType::Array), + "slice" => Some(PrimitiveType::Slice), + "tuple" => Some(PrimitiveType::PrimitiveTuple), + "pointer" => Some(PrimitiveType::PrimitiveRawPointer), _ => None, } } @@ -1585,25 +1584,25 @@ impl PrimitiveType { pub fn to_string(&self) -> &'static str { match *self { - Isize => "isize", - I8 => "i8", - I16 => "i16", - I32 => "i32", - I64 => "i64", - Usize => "usize", - U8 => "u8", - U16 => "u16", - U32 => "u32", - U64 => "u64", - F32 => "f32", - F64 => "f64", - Str => "str", - Bool => "bool", - Char => "char", - Array => "array", - Slice => "slice", - PrimitiveTuple => "tuple", - PrimitiveRawPointer => "pointer", + PrimitiveType::Isize => "isize", + PrimitiveType::I8 => "i8", + PrimitiveType::I16 => "i16", + PrimitiveType::I32 => "i32", + PrimitiveType::I64 => "i64", + PrimitiveType::Usize => "usize", + PrimitiveType::U8 => "u8", + PrimitiveType::U16 => "u16", + PrimitiveType::U32 => "u32", + PrimitiveType::U64 => "u64", + PrimitiveType::F32 => "f32", + PrimitiveType::F64 => "f64", + PrimitiveType::Str => "str", + PrimitiveType::Bool => "bool", + PrimitiveType::Char => "char", + PrimitiveType::Array => "array", + PrimitiveType::Slice => "slice", + PrimitiveType::PrimitiveTuple => "tuple", + PrimitiveType::PrimitiveRawPointer => "pointer", } } @@ -1771,21 +1770,21 @@ impl<'tcx> Clean for ty::Ty<'tcx> { fn clean(&self, cx: &DocContext) -> Type { match self.sty { ty::TyNever => Never, - ty::TyBool => Primitive(Bool), - ty::TyChar => Primitive(Char), - ty::TyInt(ast::IntTy::Is) => Primitive(Isize), - ty::TyInt(ast::IntTy::I8) => Primitive(I8), - ty::TyInt(ast::IntTy::I16) => Primitive(I16), - ty::TyInt(ast::IntTy::I32) => Primitive(I32), - ty::TyInt(ast::IntTy::I64) => Primitive(I64), - ty::TyUint(ast::UintTy::Us) => Primitive(Usize), - ty::TyUint(ast::UintTy::U8) => Primitive(U8), - ty::TyUint(ast::UintTy::U16) => Primitive(U16), - ty::TyUint(ast::UintTy::U32) => Primitive(U32), - ty::TyUint(ast::UintTy::U64) => Primitive(U64), - ty::TyFloat(ast::FloatTy::F32) => Primitive(F32), - ty::TyFloat(ast::FloatTy::F64) => Primitive(F64), - ty::TyStr => Primitive(Str), + ty::TyBool => Primitive(PrimitiveType::Bool), + ty::TyChar => Primitive(PrimitiveType::Char), + ty::TyInt(ast::IntTy::Is) => Primitive(PrimitiveType::Isize), + ty::TyInt(ast::IntTy::I8) => Primitive(PrimitiveType::I8), + ty::TyInt(ast::IntTy::I16) => Primitive(PrimitiveType::I16), + ty::TyInt(ast::IntTy::I32) => Primitive(PrimitiveType::I32), + ty::TyInt(ast::IntTy::I64) => Primitive(PrimitiveType::I64), + ty::TyUint(ast::UintTy::Us) => Primitive(PrimitiveType::Usize), + ty::TyUint(ast::UintTy::U8) => Primitive(PrimitiveType::U8), + ty::TyUint(ast::UintTy::U16) => Primitive(PrimitiveType::U16), + ty::TyUint(ast::UintTy::U32) => Primitive(PrimitiveType::U32), + ty::TyUint(ast::UintTy::U64) => Primitive(PrimitiveType::U64), + ty::TyFloat(ast::FloatTy::F32) => Primitive(PrimitiveType::F32), + ty::TyFloat(ast::FloatTy::F64) => Primitive(PrimitiveType::F64), + ty::TyStr => Primitive(PrimitiveType::Str), ty::TyBox(t) => { let box_did = cx.tcx_opt().and_then(|tcx| { tcx.lang_items.owned_box() @@ -2438,25 +2437,25 @@ fn build_deref_target_impls(cx: &DocContext, } }; let did = match primitive { - Isize => tcx.lang_items.isize_impl(), - I8 => tcx.lang_items.i8_impl(), - I16 => tcx.lang_items.i16_impl(), - I32 => tcx.lang_items.i32_impl(), - I64 => tcx.lang_items.i64_impl(), - Usize => tcx.lang_items.usize_impl(), - U8 => tcx.lang_items.u8_impl(), - U16 => tcx.lang_items.u16_impl(), - U32 => tcx.lang_items.u32_impl(), - U64 => tcx.lang_items.u64_impl(), - F32 => tcx.lang_items.f32_impl(), - F64 => tcx.lang_items.f64_impl(), - Char => tcx.lang_items.char_impl(), - Bool => None, - Str => tcx.lang_items.str_impl(), - Slice => tcx.lang_items.slice_impl(), - Array => tcx.lang_items.slice_impl(), - PrimitiveTuple => None, - PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), + PrimitiveType::Isize => tcx.lang_items.isize_impl(), + PrimitiveType::I8 => tcx.lang_items.i8_impl(), + PrimitiveType::I16 => tcx.lang_items.i16_impl(), + PrimitiveType::I32 => tcx.lang_items.i32_impl(), + PrimitiveType::I64 => tcx.lang_items.i64_impl(), + PrimitiveType::Usize => tcx.lang_items.usize_impl(), + PrimitiveType::U8 => tcx.lang_items.u8_impl(), + PrimitiveType::U16 => tcx.lang_items.u16_impl(), + PrimitiveType::U32 => tcx.lang_items.u32_impl(), + PrimitiveType::U64 => tcx.lang_items.u64_impl(), + PrimitiveType::F32 => tcx.lang_items.f32_impl(), + PrimitiveType::F64 => tcx.lang_items.f64_impl(), + PrimitiveType::Char => tcx.lang_items.char_impl(), + PrimitiveType::Bool => None, + PrimitiveType::Str => tcx.lang_items.str_impl(), + PrimitiveType::Slice => tcx.lang_items.slice_impl(), + PrimitiveType::Array => tcx.lang_items.slice_impl(), + PrimitiveType::PrimitiveTuple => None, + PrimitiveType::PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), }; if let Some(did) = did { if !did.is_local() { @@ -2739,21 +2738,21 @@ fn resolve_type(cx: &DocContext, let is_generic = match def { Def::PrimTy(p) => match p { - hir::TyStr => return Primitive(Str), - hir::TyBool => return Primitive(Bool), - hir::TyChar => return Primitive(Char), - hir::TyInt(ast::IntTy::Is) => return Primitive(Isize), - hir::TyInt(ast::IntTy::I8) => return Primitive(I8), - hir::TyInt(ast::IntTy::I16) => return Primitive(I16), - hir::TyInt(ast::IntTy::I32) => return Primitive(I32), - hir::TyInt(ast::IntTy::I64) => return Primitive(I64), - hir::TyUint(ast::UintTy::Us) => return Primitive(Usize), - hir::TyUint(ast::UintTy::U8) => return Primitive(U8), - hir::TyUint(ast::UintTy::U16) => return Primitive(U16), - hir::TyUint(ast::UintTy::U32) => return Primitive(U32), - hir::TyUint(ast::UintTy::U64) => return Primitive(U64), - hir::TyFloat(ast::FloatTy::F32) => return Primitive(F32), - hir::TyFloat(ast::FloatTy::F64) => return Primitive(F64), + hir::TyStr => return Primitive(PrimitiveType::Str), + hir::TyBool => return Primitive(PrimitiveType::Bool), + hir::TyChar => return Primitive(PrimitiveType::Char), + hir::TyInt(ast::IntTy::Is) => return Primitive(PrimitiveType::Isize), + hir::TyInt(ast::IntTy::I8) => return Primitive(PrimitiveType::I8), + hir::TyInt(ast::IntTy::I16) => return Primitive(PrimitiveType::I16), + hir::TyInt(ast::IntTy::I32) => return Primitive(PrimitiveType::I32), + hir::TyInt(ast::IntTy::I64) => return Primitive(PrimitiveType::I64), + hir::TyUint(ast::UintTy::Us) => return Primitive(PrimitiveType::Usize), + hir::TyUint(ast::UintTy::U8) => return Primitive(PrimitiveType::U8), + hir::TyUint(ast::UintTy::U16) => return Primitive(PrimitiveType::U16), + hir::TyUint(ast::UintTy::U32) => return Primitive(PrimitiveType::U32), + hir::TyUint(ast::UintTy::U64) => return Primitive(PrimitiveType::U64), + hir::TyFloat(ast::FloatTy::F32) => return Primitive(PrimitiveType::F32), + hir::TyFloat(ast::FloatTy::F64) => return Primitive(PrimitiveType::F64), }, Def::SelfTy(..) if path.segments.len() == 1 => { return Generic(keywords::SelfType.name().to_string()); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f8b852074dd2b..2b8db6975f135 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -23,7 +23,7 @@ use rustc::hir::def_id::DefId; use syntax::abi::Abi; use rustc::hir; -use clean; +use clean::{self, PrimitiveType}; use core::DocAccessLevels; use html::item_type::ItemType; use html::escape::Escape; @@ -468,28 +468,28 @@ impl fmt::Display for clean::Type { } clean::Tuple(ref typs) => { match &typs[..] { - &[] => primitive_link(f, clean::PrimitiveTuple, "()"), + &[] => primitive_link(f, PrimitiveType::PrimitiveTuple, "()"), &[ref one] => { - primitive_link(f, clean::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; write!(f, "{},", one)?; - primitive_link(f, clean::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::PrimitiveTuple, ")") } many => { - primitive_link(f, clean::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; write!(f, "{}", CommaSep(&many))?; - primitive_link(f, clean::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::PrimitiveTuple, ")") } } } clean::Vector(ref t) => { - primitive_link(f, clean::Slice, &format!("["))?; + primitive_link(f, PrimitiveType::Slice, &format!("["))?; write!(f, "{}", t)?; - primitive_link(f, clean::Slice, &format!("]")) + primitive_link(f, PrimitiveType::Slice, &format!("]")) } clean::FixedVector(ref t, ref s) => { - primitive_link(f, clean::PrimitiveType::Array, "[")?; + primitive_link(f, PrimitiveType::Array, "[")?; write!(f, "{}", t)?; - primitive_link(f, clean::PrimitiveType::Array, + primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(s))) } clean::Never => f.write_str("!"), @@ -516,12 +516,13 @@ impl fmt::Display for clean::Type { clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T] match **bt { clean::Generic(_) => - primitive_link(f, clean::Slice, + primitive_link(f, PrimitiveType::Slice, &format!("&{}{}[{}]", lt, m, **bt)), _ => { - primitive_link(f, clean::Slice, &format!("&{}{}[", lt, m))?; + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[", lt, m))?; write!(f, "{}", **bt)?; - primitive_link(f, clean::Slice, "]") + primitive_link(f, PrimitiveType::Slice, "]") } } } From 5c849f4a50a6e6d42776847144e06d1405cb4189 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 18:51:56 -0400 Subject: [PATCH 268/768] Remove unnecessary 'Primitive' prefix on `PrimitiveType` enum variants. --- src/librustdoc/clean/mod.rs | 20 ++++++++++---------- src/librustdoc/html/format.rs | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7e599569a282e..093e6a2adadae 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1485,8 +1485,8 @@ pub enum PrimitiveType { Str, Slice, Array, - PrimitiveTuple, - PrimitiveRawPointer, + Tuple, + RawPointer, } #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] @@ -1520,8 +1520,8 @@ impl Type { FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => { Some(PrimitiveType::Array) } - Tuple(..) => Some(PrimitiveType::PrimitiveTuple), - RawPointer(..) => Some(PrimitiveType::PrimitiveRawPointer), + Tuple(..) => Some(PrimitiveType::Tuple), + RawPointer(..) => Some(PrimitiveType::RawPointer), _ => None, } } @@ -1563,8 +1563,8 @@ impl PrimitiveType { "f64" => Some(PrimitiveType::F64), "array" => Some(PrimitiveType::Array), "slice" => Some(PrimitiveType::Slice), - "tuple" => Some(PrimitiveType::PrimitiveTuple), - "pointer" => Some(PrimitiveType::PrimitiveRawPointer), + "tuple" => Some(PrimitiveType::Tuple), + "pointer" => Some(PrimitiveType::RawPointer), _ => None, } } @@ -1601,8 +1601,8 @@ impl PrimitiveType { PrimitiveType::Char => "char", PrimitiveType::Array => "array", PrimitiveType::Slice => "slice", - PrimitiveType::PrimitiveTuple => "tuple", - PrimitiveType::PrimitiveRawPointer => "pointer", + PrimitiveType::Tuple => "tuple", + PrimitiveType::RawPointer => "pointer", } } @@ -2454,8 +2454,8 @@ fn build_deref_target_impls(cx: &DocContext, PrimitiveType::Str => tcx.lang_items.str_impl(), PrimitiveType::Slice => tcx.lang_items.slice_impl(), PrimitiveType::Array => tcx.lang_items.slice_impl(), - PrimitiveType::PrimitiveTuple => None, - PrimitiveType::PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), + PrimitiveType::Tuple => None, + PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(), }; if let Some(did) = did { if !did.is_local() { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2b8db6975f135..65992798ab099 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -468,16 +468,16 @@ impl fmt::Display for clean::Type { } clean::Tuple(ref typs) => { match &typs[..] { - &[] => primitive_link(f, PrimitiveType::PrimitiveTuple, "()"), + &[] => primitive_link(f, PrimitiveType::Tuple, "()"), &[ref one] => { - primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::Tuple, "(")?; write!(f, "{},", one)?; - primitive_link(f, PrimitiveType::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::Tuple, ")") } many => { - primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::Tuple, "(")?; write!(f, "{}", CommaSep(&many))?; - primitive_link(f, PrimitiveType::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::Tuple, ")") } } } @@ -496,11 +496,11 @@ impl fmt::Display for clean::Type { clean::RawPointer(m, ref t) => { match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { - primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer, + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{}{}", RawMutableSpace(m), t)) } _ => { - primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer, + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{}", RawMutableSpace(m)))?; write!(f, "{}", t) } From 8a6f7a5ced0217344f2f8a8c6a98aefb08b10fa7 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 19:12:24 -0400 Subject: [PATCH 269/768] Implement `From` for `PrimitiveType`. --- src/librustdoc/clean/mod.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 093e6a2adadae..3abc7e985366a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1619,6 +1619,17 @@ impl PrimitiveType { } } +impl From for PrimitiveType { + fn from(int_ty: ast::IntTy) -> PrimitiveType { + match int_ty { + ast::IntTy::Is => PrimitiveType::Isize, + ast::IntTy::I8 => PrimitiveType::I8, + ast::IntTy::I16 => PrimitiveType::I16, + ast::IntTy::I32 => PrimitiveType::I32, + ast::IntTy::I64 => PrimitiveType::I64, + } + } +} // Poor man's type parameter substitution at HIR level. // Used to replace private type aliases in public signatures with their aliased types. @@ -1772,11 +1783,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyNever => Never, ty::TyBool => Primitive(PrimitiveType::Bool), ty::TyChar => Primitive(PrimitiveType::Char), - ty::TyInt(ast::IntTy::Is) => Primitive(PrimitiveType::Isize), - ty::TyInt(ast::IntTy::I8) => Primitive(PrimitiveType::I8), - ty::TyInt(ast::IntTy::I16) => Primitive(PrimitiveType::I16), - ty::TyInt(ast::IntTy::I32) => Primitive(PrimitiveType::I32), - ty::TyInt(ast::IntTy::I64) => Primitive(PrimitiveType::I64), + ty::TyInt(int_ty) => Primitive(int_ty.into()), ty::TyUint(ast::UintTy::Us) => Primitive(PrimitiveType::Usize), ty::TyUint(ast::UintTy::U8) => Primitive(PrimitiveType::U8), ty::TyUint(ast::UintTy::U16) => Primitive(PrimitiveType::U16), @@ -2741,11 +2748,7 @@ fn resolve_type(cx: &DocContext, hir::TyStr => return Primitive(PrimitiveType::Str), hir::TyBool => return Primitive(PrimitiveType::Bool), hir::TyChar => return Primitive(PrimitiveType::Char), - hir::TyInt(ast::IntTy::Is) => return Primitive(PrimitiveType::Isize), - hir::TyInt(ast::IntTy::I8) => return Primitive(PrimitiveType::I8), - hir::TyInt(ast::IntTy::I16) => return Primitive(PrimitiveType::I16), - hir::TyInt(ast::IntTy::I32) => return Primitive(PrimitiveType::I32), - hir::TyInt(ast::IntTy::I64) => return Primitive(PrimitiveType::I64), + hir::TyInt(int_ty) => return Primitive(int_ty.into()), hir::TyUint(ast::UintTy::Us) => return Primitive(PrimitiveType::Usize), hir::TyUint(ast::UintTy::U8) => return Primitive(PrimitiveType::U8), hir::TyUint(ast::UintTy::U16) => return Primitive(PrimitiveType::U16), From 168cfea8afaf2dddae3d848a7f49ecb63d130b47 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 19:22:18 -0400 Subject: [PATCH 270/768] Implement `From` for `PrimitiveType`. --- src/librustdoc/clean/mod.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3abc7e985366a..4f455e7d073de 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1631,6 +1631,18 @@ impl From for PrimitiveType { } } +impl From for PrimitiveType { + fn from(uint_ty: ast::UintTy) -> PrimitiveType { + match uint_ty { + ast::UintTy::Us => PrimitiveType::Usize, + ast::UintTy::U8 => PrimitiveType::U8, + ast::UintTy::U16 => PrimitiveType::U16, + ast::UintTy::U32 => PrimitiveType::U32, + ast::UintTy::U64 => PrimitiveType::U64, + } + } +} + // Poor man's type parameter substitution at HIR level. // Used to replace private type aliases in public signatures with their aliased types. struct SubstAlias<'a, 'tcx: 'a> { @@ -1784,11 +1796,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyBool => Primitive(PrimitiveType::Bool), ty::TyChar => Primitive(PrimitiveType::Char), ty::TyInt(int_ty) => Primitive(int_ty.into()), - ty::TyUint(ast::UintTy::Us) => Primitive(PrimitiveType::Usize), - ty::TyUint(ast::UintTy::U8) => Primitive(PrimitiveType::U8), - ty::TyUint(ast::UintTy::U16) => Primitive(PrimitiveType::U16), - ty::TyUint(ast::UintTy::U32) => Primitive(PrimitiveType::U32), - ty::TyUint(ast::UintTy::U64) => Primitive(PrimitiveType::U64), + ty::TyUint(uint_ty) => Primitive(uint_ty.into()), ty::TyFloat(ast::FloatTy::F32) => Primitive(PrimitiveType::F32), ty::TyFloat(ast::FloatTy::F64) => Primitive(PrimitiveType::F64), ty::TyStr => Primitive(PrimitiveType::Str), @@ -2749,11 +2757,7 @@ fn resolve_type(cx: &DocContext, hir::TyBool => return Primitive(PrimitiveType::Bool), hir::TyChar => return Primitive(PrimitiveType::Char), hir::TyInt(int_ty) => return Primitive(int_ty.into()), - hir::TyUint(ast::UintTy::Us) => return Primitive(PrimitiveType::Usize), - hir::TyUint(ast::UintTy::U8) => return Primitive(PrimitiveType::U8), - hir::TyUint(ast::UintTy::U16) => return Primitive(PrimitiveType::U16), - hir::TyUint(ast::UintTy::U32) => return Primitive(PrimitiveType::U32), - hir::TyUint(ast::UintTy::U64) => return Primitive(PrimitiveType::U64), + hir::TyUint(uint_ty) => return Primitive(uint_ty.into()), hir::TyFloat(ast::FloatTy::F32) => return Primitive(PrimitiveType::F32), hir::TyFloat(ast::FloatTy::F64) => return Primitive(PrimitiveType::F64), }, From 42e8ac87eb013f34db5739bf154a383424595077 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 19:41:14 -0400 Subject: [PATCH 271/768] Implement `From` for `PrimitiveType`. --- src/librustdoc/clean/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4f455e7d073de..e2e655ce38bcc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1643,6 +1643,15 @@ impl From for PrimitiveType { } } +impl From for PrimitiveType { + fn from(float_ty: ast::FloatTy) -> PrimitiveType { + match float_ty { + ast::FloatTy::F32 => PrimitiveType::F32, + ast::FloatTy::F64 => PrimitiveType::F64, + } + } +} + // Poor man's type parameter substitution at HIR level. // Used to replace private type aliases in public signatures with their aliased types. struct SubstAlias<'a, 'tcx: 'a> { @@ -1797,8 +1806,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyChar => Primitive(PrimitiveType::Char), ty::TyInt(int_ty) => Primitive(int_ty.into()), ty::TyUint(uint_ty) => Primitive(uint_ty.into()), - ty::TyFloat(ast::FloatTy::F32) => Primitive(PrimitiveType::F32), - ty::TyFloat(ast::FloatTy::F64) => Primitive(PrimitiveType::F64), + ty::TyFloat(float_ty) => Primitive(float_ty.into()), ty::TyStr => Primitive(PrimitiveType::Str), ty::TyBox(t) => { let box_did = cx.tcx_opt().and_then(|tcx| { @@ -2758,8 +2766,7 @@ fn resolve_type(cx: &DocContext, hir::TyChar => return Primitive(PrimitiveType::Char), hir::TyInt(int_ty) => return Primitive(int_ty.into()), hir::TyUint(uint_ty) => return Primitive(uint_ty.into()), - hir::TyFloat(ast::FloatTy::F32) => return Primitive(PrimitiveType::F32), - hir::TyFloat(ast::FloatTy::F64) => return Primitive(PrimitiveType::F64), + hir::TyFloat(float_ty) => return Primitive(float_ty.into()), }, Def::SelfTy(..) if path.segments.len() == 1 => { return Generic(keywords::SelfType.name().to_string()); From cf6461168f5a784c996ffd6618d23f33113d2819 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 24 Aug 2016 19:34:31 -0700 Subject: [PATCH 272/768] Fix debug line info for macro expansions. Macro expansions produce code tagged with debug locations that are completely different from the surrounding expressions. This wrecks havoc on debugger's ability the step over source lines. In order to have a good line stepping behavior in debugger, we overwrite debug locations of macro expansions with that of the outermost expansion site. --- src/librustc/middle/region.rs | 2 +- src/librustc/session/config.rs | 2 + src/librustc_llvm/ffi.rs | 5 + .../debuginfo/create_scope_map.rs | 48 +++++- src/librustc_trans/debuginfo/metadata.rs | 16 +- src/librustc_trans/debuginfo/mod.rs | 3 +- src/librustc_trans/mir/mod.rs | 141 +++++++++++++----- src/rustllvm/RustWrapper.cpp | 9 ++ .../debuginfo/auxiliary/macro-stepping.rs | 20 +++ .../debuginfo/lexical-scope-with-macro.rs | 2 +- src/test/debuginfo/macro-stepping.rs | 103 +++++++++++++ 11 files changed, 298 insertions(+), 53 deletions(-) create mode 100644 src/test/debuginfo/auxiliary/macro-stepping.rs create mode 100644 src/test/debuginfo/macro-stepping.rs diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 6f0ad087dc589..faf2f7dae08c5 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -237,7 +237,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, ..blk.span }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a991a1a9ba4b5..8a32797dbd75a 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -891,6 +891,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "force overflow checks on or off"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments"), + debug_macros: bool = (false, parse_bool, [TRACKED], + "emit line numbers debug info inside macros"), enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED], "force nonzeroing move optimization on"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b2ffcac365bad..754910c246d6f 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1796,6 +1796,11 @@ extern { Col: c_uint) -> DILexicalBlock; + pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: DIBuilderRef, + Scope: DIScope, + File: DIFile) + -> DILexicalBlock; + pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef, Context: DIScope, Name: *const c_char, diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 58cf85747374a..21716d55ac6fa 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -25,11 +25,33 @@ use syntax_pos::Pos; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use syntax_pos::BytePos; + +#[derive(Clone, Copy, Debug)] +pub struct MirDebugScope { + pub scope_metadata: DIScope, + // Start and end offsets of the file to which this DIScope belongs. + // These are used to quickly determine whether some span refers to the same file. + pub file_start_pos: BytePos, + pub file_end_pos: BytePos, +} + +impl MirDebugScope { + pub fn is_valid(&self) -> bool { + !self.scope_metadata.is_null() + } +} + /// Produce DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. -pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec { +pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec { let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn"); - let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes); + let null_scope = MirDebugScope { + scope_metadata: ptr::null_mut(), + file_start_pos: BytePos(0), + file_end_pos: BytePos(0) + }; + let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes); let fn_metadata = match fcx.debug_context { FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata, @@ -59,8 +81,8 @@ fn make_mir_scope(ccx: &CrateContext, has_variables: &BitVector, fn_metadata: DISubprogram, scope: VisibilityScope, - scopes: &mut IndexVec) { - if !scopes[scope].is_null() { + scopes: &mut IndexVec) { + if scopes[scope].is_valid() { return; } @@ -70,7 +92,12 @@ fn make_mir_scope(ccx: &CrateContext, scopes[parent] } else { // The root is the function itself. - scopes[scope] = fn_metadata; + let loc = span_start(ccx, mir.span); + scopes[scope] = MirDebugScope { + scope_metadata: fn_metadata, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_pos, + }; return; }; @@ -81,20 +108,25 @@ fn make_mir_scope(ccx: &CrateContext, // However, we don't skip creating a nested scope if // our parent is the root, because we might want to // put arguments in the root and not have shadowing. - if parent_scope != fn_metadata { + if parent_scope.scope_metadata != fn_metadata { scopes[scope] = parent_scope; return; } } let loc = span_start(ccx, scope_data.span); - scopes[scope] = unsafe { let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path); + let scope_metadata = unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(ccx), - parent_scope, + parent_scope.scope_metadata, file_metadata, loc.line as c_uint, loc.col.to_usize() as c_uint) }; + scopes[scope] = MirDebugScope { + scope_metadata: scope_metadata, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_pos, + }; } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ba91b44343868..fccb326b23221 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -22,7 +22,7 @@ use context::SharedCrateContext; use session::Session; use llvm::{self, ValueRef}; -use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; +use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; @@ -1839,3 +1839,17 @@ pub fn create_global_var_metadata(cx: &CrateContext, ptr::null_mut()); } } + +// Creates an "extension" of an existing DIScope into another file. +pub fn extend_scope_to_file(ccx: &CrateContext, + scope_metadata: DIScope, + file: &syntax_pos::FileMap) + -> DILexicalBlock { + let file_metadata = file_metadata(ccx, &file.name, &file.abs_path); + unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlockFile( + DIB(ccx), + scope_metadata, + file_metadata) + } +} \ No newline at end of file diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index cbf423b0739a3..58425cf60d550 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -53,9 +53,10 @@ pub mod metadata; mod create_scope_map; mod source_loc; -pub use self::create_scope_map::create_mir_scopes; +pub use self::create_scope_map::{create_mir_scopes, MirDebugScope}; pub use self::source_loc::start_emitting_source_locations; pub use self::metadata::create_global_var_metadata; +pub use self::metadata::extend_scope_to_file; #[allow(non_upper_case_globals)] const DW_TAG_auto_variable: c_uint = 0x100; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 474b2552e7079..1934f7b870d18 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -10,18 +10,17 @@ use libc::c_uint; use llvm::{self, ValueRef}; -use llvm::debuginfo::DIScope; use rustc::ty; use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; use session::config::FullDebugInfo; use base; use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext, C_null}; -use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind}; +use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind, FunctionDebugContext}; use machine; use type_of; -use syntax_pos::DUMMY_SP; +use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use syntax::parse::token::keywords; use std::ops::Deref; @@ -103,12 +102,67 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { locals: IndexVec>, /// Debug information for MIR scopes. - scopes: IndexVec + scopes: IndexVec, } impl<'blk, 'tcx> MirContext<'blk, 'tcx> { - pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc { - DebugLoc::ScopeAt(self.scopes[source_info.scope], source_info.span) + pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> DebugLoc { + // Bail out if debug info emission is not enabled. + match self.fcx.debug_context { + FunctionDebugContext::DebugInfoDisabled | + FunctionDebugContext::FunctionWithoutDebugInfo => { + // Can't return DebugLoc::None here because intrinsic::trans_intrinsic_call() + // relies on debug location to obtain span of the call site. + return DebugLoc::ScopeAt(self.scopes[source_info.scope].scope_metadata, + source_info.span); + } + FunctionDebugContext::RegularContext(_) =>{} + } + + // In order to have a good line stepping behavior in debugger, we overwrite debug + // locations of macro expansions with that of the outermost expansion site + // (unless the crate is being compiled with `-Z debug-macros`). + if source_info.span.expn_id == NO_EXPANSION || + source_info.span.expn_id == COMMAND_LINE_EXPN || + self.fcx.ccx.sess().opts.debugging_opts.debug_macros { + + let scope_metadata = self.scope_metadata_for_loc(source_info.scope, + source_info.span.lo); + DebugLoc::ScopeAt(scope_metadata, source_info.span) + } else { + let cm = self.fcx.ccx.sess().codemap(); + // Walk up the macro expansion chain until we reach a non-expanded span. + let mut span = source_info.span; + while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { + if let Some(callsite_span) = cm.with_expn_info(span.expn_id, + |ei| ei.map(|ei| ei.call_site.clone())) { + span = callsite_span; + } else { + break; + } + } + let scope_metadata = self.scope_metadata_for_loc(source_info.scope, span.lo); + // Use span of the outermost call site, while keeping the original lexical scope + DebugLoc::ScopeAt(scope_metadata, span) + } + } + + // DILocations inherit source file name from the parent DIScope. Due to macro expansions + // it may so happen that the current span belongs to a different file than the DIScope + // corresponding to span's containing visibility scope. If so, we need to create a DIScope + // "extension" into that file. + fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos) + -> llvm::debuginfo::DIScope { + let scope_metadata = self.scopes[scope_id].scope_metadata; + if pos < self.scopes[scope_id].file_start_pos || + pos >= self.scopes[scope_id].file_end_pos { + let cm = self.fcx.ccx.sess().codemap(); + debuginfo::extend_scope_to_file(self.fcx.ccx, + scope_metadata, + &cm.lookup_char_pos(pos).file) + } else { + scope_metadata + } } } @@ -155,16 +209,38 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { analyze::cleanup_kinds(bcx, &mir)) }); + // Allocate a `Block` for every basic block + let block_bcxs: IndexVec> = + mir.basic_blocks().indices().map(|bb| { + if bb == mir::START_BLOCK { + fcx.new_block("start") + } else { + fcx.new_block(&format!("{:?}", bb)) + } + }).collect(); + // Compute debuginfo scopes from MIR scopes. let scopes = debuginfo::create_mir_scopes(fcx); + let mut mircx = MirContext { + mir: mir.clone(), + fcx: fcx, + llpersonalityslot: None, + blocks: block_bcxs, + unreachable_block: None, + cleanup_kinds: cleanup_kinds, + landing_pads: IndexVec::from_elem(None, mir.basic_blocks()), + scopes: scopes, + locals: IndexVec::new(), + }; + // Allocate variable and temp allocas - let locals = { - let args = arg_local_refs(&bcx, &mir, &scopes, &lvalue_locals); + mircx.locals = { + let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals); let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| { let ty = bcx.monomorphize(&decl.ty); - let scope = scopes[decl.source_info.scope]; - let dbg = !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo; + let debug_scope = mircx.scopes[decl.source_info.scope]; + let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap(); if !lvalue_locals.contains(local.index()) && !dbg { @@ -173,11 +249,16 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str()); if dbg { - bcx.with_block(|bcx| { - declare_local(bcx, decl.name, ty, scope, - VariableAccess::DirectVariable { alloca: lvalue.llval }, - VariableKind::LocalVariable, decl.source_info.span); - }); + let dbg_loc = mircx.debug_loc(decl.source_info); + if let DebugLoc::ScopeAt(scope, span) = dbg_loc { + bcx.with_block(|bcx| { + declare_local(bcx, decl.name, ty, scope, + VariableAccess::DirectVariable { alloca: lvalue.llval }, + VariableKind::LocalVariable, span); + }); + } else { + panic!("Unexpected"); + } } LocalRef::Lvalue(lvalue) }); @@ -203,18 +284,8 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { })).collect() }; - // Allocate a `Block` for every basic block - let block_bcxs: IndexVec> = - mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - fcx.new_block("start") - } else { - fcx.new_block(&format!("{:?}", bb)) - } - }).collect(); - // Branch to the START block - let start_bcx = block_bcxs[mir::START_BLOCK]; + let start_bcx = mircx.blocks[mir::START_BLOCK]; bcx.br(start_bcx.llbb); // Up until here, IR instructions for this function have explicitly not been annotated with @@ -222,18 +293,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { // emitting should be enabled. debuginfo::start_emitting_source_locations(fcx); - let mut mircx = MirContext { - mir: mir.clone(), - fcx: fcx, - llpersonalityslot: None, - blocks: block_bcxs, - unreachable_block: None, - cleanup_kinds: cleanup_kinds, - landing_pads: IndexVec::from_elem(None, mir.basic_blocks()), - locals: locals, - scopes: scopes - }; - let mut visited = BitVector::new(mir.basic_blocks().len()); let mut rpo = traversal::reverse_postorder(&mir); @@ -271,7 +330,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { /// indirect. fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, mir: &mir::Mir<'tcx>, - scopes: &IndexVec, + scopes: &IndexVec, lvalue_locals: &BitVector) -> Vec> { let fcx = bcx.fcx(); @@ -281,8 +340,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, // Get the argument scope, if it exists and if we need it. let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE]; - let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo { - Some(arg_scope) + let arg_scope = if arg_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo { + Some(arg_scope.scope_metadata) } else { None }; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 0da25e7ac57b7..82fb2b0918f79 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -521,6 +521,15 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock( )); } +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, + LLVMRustMetadataRef File) { + return wrap(Builder->createLexicalBlockFile( + unwrapDI(Scope), + unwrapDI(File))); +} + extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Context, diff --git a/src/test/debuginfo/auxiliary/macro-stepping.rs b/src/test/debuginfo/auxiliary/macro-stepping.rs new file mode 100644 index 0000000000000..1006b684a8c22 --- /dev/null +++ b/src/test/debuginfo/auxiliary/macro-stepping.rs @@ -0,0 +1,20 @@ +// Copyright 2013-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. + +// compile-flags:-g + +#![crate_type = "rlib"] + +#[macro_export] +macro_rules! new_scope { + () => { + let x = 1; + } +} diff --git a/src/test/debuginfo/lexical-scope-with-macro.rs b/src/test/debuginfo/lexical-scope-with-macro.rs index a00d0f74f1e4e..eb5798dc7cc48 100644 --- a/src/test/debuginfo/lexical-scope-with-macro.rs +++ b/src/test/debuginfo/lexical-scope-with-macro.rs @@ -10,7 +10,7 @@ // min-lldb-version: 310 -// compile-flags:-g +// compile-flags:-g -Zdebug-macros // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/macro-stepping.rs b/src/test/debuginfo/macro-stepping.rs new file mode 100644 index 0000000000000..52a2a58ed7d27 --- /dev/null +++ b/src/test/debuginfo/macro-stepping.rs @@ -0,0 +1,103 @@ +// Copyright 2013-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. + +// ignore-windows +// ignore-android +// min-lldb-version: 310 + +// aux-build:macro-stepping.rs + +#![allow(unused)] + +#[macro_use] +extern crate macro_stepping; // exports new_scope!() + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc4[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc5[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc6[...] + +// === LLDB TESTS ================================================================================== + +// lldb-command:set set stop-line-count-before 0 +// lldb-command:set set stop-line-count-after 1 +// Can't set both to zero or lldb will stop printing source at all. So it will output the current +// line and the next. We deal with this by having at least 2 lines between the #loc's + +// lldb-command:run +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc1[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc2[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc3[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc4[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc5[...] + +macro_rules! foo { + () => { + let a = 1; + let b = 2; + let c = 3; + } +} + +macro_rules! foo2 { + () => { + foo!(); + let x = 1; + foo!(); + } +} + +fn main() { + zzz(); // #break + + foo!(); // #loc1 + + foo2!(); // #loc2 + + let x = vec![42]; // #loc3 + + new_scope!(); // #loc4 + + println!("Hello {}", // #loc5 + "world"); + + zzz(); // #loc6 +} + +fn zzz() {()} From 6f93d3ce46d157b97da1b9ddbbd72f4bd40fbc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Thu, 25 Aug 2016 01:24:49 +0200 Subject: [PATCH 273/768] Make E0094 underline better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #35966. Signed-off-by: Johannes Löthberg --- src/librustc_typeck/check/intrinsic.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 7f9e715b7fafc..616c99a6b9bc3 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -51,12 +51,17 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, })); let i_n_tps = i_ty.generics.types.len(); if i_n_tps != n_tps { - struct_span_err!(tcx.sess, it.span, E0094, - "intrinsic has wrong number of type \ - parameters: found {}, expected {}", - i_n_tps, n_tps) - .span_label(it.span, &format!("expected {} type parameter", n_tps)) - .emit(); + let span = match it.node { + hir::ForeignItemFn(_, ref generics) => generics.span().unwrap_or(it.span), + hir::ForeignItemStatic(_, _) => it.span + }; + + struct_span_err!(tcx.sess, span, E0094, + "intrinsic has wrong number of type \ + parameters: found {}, expected {}", + i_n_tps, n_tps) + .span_label(span, &format!("expected {} type parameter", n_tps)) + .emit(); } else { require_same_types(ccx, TypeOrigin::IntrinsicType(it.span), From 874a20d01d1c075b3f9a9c60562d78761ed08bc4 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Thu, 25 Aug 2016 18:26:04 +0530 Subject: [PATCH 274/768] Update E0277 to new error format Fixes #35311. Part of #35233. r? @jonathandturner --- src/librustc/traits/error_reporting.rs | 5 +++-- src/test/compile-fail/E0277.rs | 5 ++++- .../associated-types-ICE-when-projecting-out-of-err.rs | 3 ++- src/test/compile-fail/cast-rfc0401.rs | 2 ++ src/test/compile-fail/const-unsized.rs | 4 ++++ src/test/compile-fail/impl-trait/auto-trait-leak.rs | 4 ++++ src/test/compile-fail/on-unimplemented/multiple-impls.rs | 3 +++ src/test/compile-fail/on-unimplemented/on-impl.rs | 1 + src/test/compile-fail/on-unimplemented/on-trait.rs | 2 ++ src/test/compile-fail/on-unimplemented/slice-index.rs | 2 ++ src/test/compile-fail/trait-suggest-where-clause.rs | 7 +++++++ 11 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6f263fcebeb0..adffc38b0befa 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -477,10 +477,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } - let mut err = struct_span_err!( - self.tcx.sess, span, E0277, + let mut err = struct_span_err!(self.tcx.sess, span, E0277, "the trait bound `{}` is not satisfied", trait_ref.to_predicate()); + err.span_label(span, &format!("trait `{}` not satisfied", + trait_ref.to_predicate())); // Try to report a help message diff --git a/src/test/compile-fail/E0277.rs b/src/test/compile-fail/E0277.rs index 7737f12ac3714..12f9417f944cd 100644 --- a/src/test/compile-fail/E0277.rs +++ b/src/test/compile-fail/E0277.rs @@ -17,5 +17,8 @@ fn some_func(foo: T) { } fn main() { - some_func(5i32); //~ ERROR E0277 + some_func(5i32); + //~^ ERROR the trait bound `i32: Foo` is not satisfied + //~| NOTE trait `i32: Foo` not satisfied + //~| NOTE required by `some_func` } diff --git a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs index 48bfa84fa8666..084616964674f 100644 --- a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs +++ b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs @@ -31,5 +31,6 @@ trait Add { fn ice(a: A) { let r = loop {}; r = r + a; - //~^ ERROR E0277 + //~^ ERROR the trait bound `(): Add` is not satisfied + //~| NOTE trait `(): Add` not satisfied } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 7839fb45d1c34..b6e81504a9d24 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -92,6 +92,7 @@ fn main() let _ = v as *const [u8]; //~ ERROR cannot cast let _ = fat_v as *const Foo; //~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied + //~| NOTE trait `[u8]: std::marker::Sized` not satisfied //~| NOTE `[u8]` does not have a constant size known at compile-time //~| NOTE required for the cast to the object type `Foo` let _ = foo as *const str; //~ ERROR casting @@ -106,6 +107,7 @@ fn main() let a : *const str = "hello"; let _ = a as *const Foo; //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied + //~| NOTE trait `str: std::marker::Sized` not satisfied //~| NOTE `str` does not have a constant size known at compile-time //~| NOTE required for the cast to the object type `Foo` diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index 72a5c5fff6084..a73164b957c83 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -12,21 +12,25 @@ use std::fmt::Debug; const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied +//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied +//~| NOTE `str: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied +//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied +//~| NOTE `str: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size diff --git a/src/test/compile-fail/impl-trait/auto-trait-leak.rs b/src/test/compile-fail/impl-trait/auto-trait-leak.rs index 2c78ce2db29af..60ad266e7f7da 100644 --- a/src/test/compile-fail/impl-trait/auto-trait-leak.rs +++ b/src/test/compile-fail/impl-trait/auto-trait-leak.rs @@ -26,6 +26,7 @@ fn send(_: T) {} fn main() { send(before()); //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~| NOTE trait `std::rc::Rc>: std::marker::Send` not satisfied //~| NOTE `std::rc::Rc>` cannot be sent between threads safely //~| NOTE required because it appears within the type `[closure //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>` @@ -33,6 +34,7 @@ fn main() { send(after()); //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~| NOTE trait `std::rc::Rc>: std::marker::Send` not satisfied //~| NOTE `std::rc::Rc>` cannot be sent between threads safely //~| NOTE required because it appears within the type `[closure //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>` @@ -52,6 +54,7 @@ fn after() -> impl Fn(i32) { fn cycle1() -> impl Clone { send(cycle2().clone()); //~^ ERROR the trait bound `std::rc::Rc: std::marker::Send` is not satisfied + //~| NOTE trait `std::rc::Rc: std::marker::Send` not satisfied //~| NOTE `std::rc::Rc` cannot be sent between threads safely //~| NOTE required because it appears within the type `impl std::clone::Clone` //~| NOTE required by `send` @@ -62,6 +65,7 @@ fn cycle1() -> impl Clone { fn cycle2() -> impl Clone { send(cycle1().clone()); //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~| NOTE trait `std::rc::Rc>: std::marker::Send` not satisfied //~| NOTE `std::rc::Rc>` cannot be sent between threads safely //~| NOTE required because it appears within the type `impl std::clone::Clone` //~| NOTE required by `send` diff --git a/src/test/compile-fail/on-unimplemented/multiple-impls.rs b/src/test/compile-fail/on-unimplemented/multiple-impls.rs index 0df8c41ffe1a8..cc7c2f4f796d9 100644 --- a/src/test/compile-fail/on-unimplemented/multiple-impls.rs +++ b/src/test/compile-fail/on-unimplemented/multiple-impls.rs @@ -42,14 +42,17 @@ impl Index> for [i32] { fn main() { Index::index(&[] as &[i32], 2u32); //~^ ERROR E0277 + //~| NOTE not satisfied //~| NOTE trait message //~| NOTE required by Index::index(&[] as &[i32], Foo(2u32)); //~^ ERROR E0277 + //~| NOTE not satisfied //~| NOTE on impl for Foo //~| NOTE required by Index::index(&[] as &[i32], Bar(2u32)); //~^ ERROR E0277 + //~| NOTE not satisfied //~| NOTE on impl for Bar //~| NOTE required by } diff --git a/src/test/compile-fail/on-unimplemented/on-impl.rs b/src/test/compile-fail/on-unimplemented/on-impl.rs index 4471b625d7912..c22e48bede4ef 100644 --- a/src/test/compile-fail/on-unimplemented/on-impl.rs +++ b/src/test/compile-fail/on-unimplemented/on-impl.rs @@ -30,6 +30,7 @@ impl Index for [i32] { #[rustc_error] fn main() { Index::::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277 + //~| NOTE not satisfied //~| NOTE a usize is required //~| NOTE required by } diff --git a/src/test/compile-fail/on-unimplemented/on-trait.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs index 39ce1b33ca131..9ea2809374cd8 100644 --- a/src/test/compile-fail/on-unimplemented/on-trait.rs +++ b/src/test/compile-fail/on-unimplemented/on-trait.rs @@ -35,7 +35,9 @@ pub fn main() { //~^ ERROR //~^^ NOTE a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` //~^^^ NOTE required by `collect` + //~| NOTE trait `std::option::Option>: MyFromIterator<&u8>` not satisfied let x: String = foobar(); //~ ERROR //~^ NOTE test error `std::string::String` with `u8` `_` `u32` //~^^ NOTE required by `foobar` + //~| NOTE trait `std::string::String: Foo` not satisfied } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index 6a8f9d471e169..5c548b5d5bf20 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -18,7 +18,9 @@ use std::ops::Index; fn main() { let x = &[1, 2, 3] as &[i32]; x[1i32]; //~ ERROR E0277 + //~| NOTE trait `[i32]: std::ops::Index` not satisfied //~| NOTE slice indices are of type `usize` x[..1i32]; //~ ERROR E0277 + //~| NOTE trait `[i32]: std::ops::Index>` not satisfied //~| NOTE slice indices are of type `usize` } diff --git a/src/test/compile-fail/trait-suggest-where-clause.rs b/src/test/compile-fail/trait-suggest-where-clause.rs index a8ff1bae7a71a..d15e3536d60ca 100644 --- a/src/test/compile-fail/trait-suggest-where-clause.rs +++ b/src/test/compile-fail/trait-suggest-where-clause.rs @@ -16,11 +16,13 @@ fn check() { // suggest a where-clause, if needed mem::size_of::(); //~^ ERROR `U: std::marker::Sized` is not satisfied + //~| NOTE trait `U: std::marker::Sized` not satisfied //~| HELP consider adding a `where U: std::marker::Sized` bound //~| NOTE required by `std::mem::size_of` mem::size_of::>(); //~^ ERROR `U: std::marker::Sized` is not satisfied + //~| NOTE trait `U: std::marker::Sized` not satisfied //~| HELP consider adding a `where U: std::marker::Sized` bound //~| NOTE required because it appears within the type `Misc` //~| NOTE required by `std::mem::size_of` @@ -29,11 +31,13 @@ fn check() { >::from; //~^ ERROR `u64: std::convert::From` is not satisfied + //~| NOTE trait `u64: std::convert::From` not satisfied //~| HELP consider adding a `where u64: std::convert::From` bound //~| NOTE required by `std::convert::From::from` ::Item>>::from; //~^ ERROR `u64: std::convert::From<::Item>` is not satisfied + //~| NOTE trait `u64: std::convert::From<::Item>` not satisfied //~| HELP consider adding a `where u64: //~| NOTE required by `std::convert::From::from` @@ -41,17 +45,20 @@ fn check() { as From>::from; //~^ ERROR `Misc<_>: std::convert::From` is not satisfied + //~| NOTE trait `Misc<_>: std::convert::From` not satisfied //~| NOTE required by `std::convert::From::from` // ... and also not if the error is not related to the type mem::size_of::<[T]>(); //~^ ERROR `[T]: std::marker::Sized` is not satisfied + //~| NOTE `[T]: std::marker::Sized` not satisfied //~| NOTE `[T]` does not have a constant size //~| NOTE required by `std::mem::size_of` mem::size_of::<[&U]>(); //~^ ERROR `[&U]: std::marker::Sized` is not satisfied + //~| NOTE `[&U]: std::marker::Sized` not satisfied //~| NOTE `[&U]` does not have a constant size //~| NOTE required by `std::mem::size_of` } From b2cd3e59b88e6d69e92b28f7cfb8502f62bba94d Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 25 Aug 2016 12:39:25 -0400 Subject: [PATCH 275/768] use file!() even though it shouldn't be necessary --- src/test/run-pass/fds-are-cloexec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs index b7ce622bf563e..7d49bd25309f5 100644 --- a/src/test/run-pass/fds-are-cloexec.rs +++ b/src/test/run-pass/fds-are-cloexec.rs @@ -34,7 +34,7 @@ fn main() { } fn parent() { - let file = File::open("src/test/run-pass/fds-are-cloexec.rs").unwrap(); + let file = File::open(file!()).unwrap(); let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap(); let tcp2 = tcp1.try_clone().unwrap(); let addr = tcp1.local_addr().unwrap(); From 905644de5db7f73fab275345795562330d007315 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 24 Aug 2016 02:20:51 -0400 Subject: [PATCH 276/768] Rename {uint,int} methods to {usize,isize}. --- src/librbml/lib.rs | 8 ++++---- src/librbml/opaque.rs | 26 +++++++++++++------------- src/libserialize/collection_impls.rs | 4 ++-- src/libserialize/json.rs | 12 ++++++------ src/libserialize/serialize.rs | 16 ++++++++-------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 4edbeab5dfb11..adbdc9af9cc8d 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -726,7 +726,7 @@ pub mod reader { fn read_u8(&mut self) -> DecodeResult { Ok(doc_as_u8(self.next_doc(EsU8)?)) } - fn read_uint(&mut self) -> DecodeResult { + fn read_usize(&mut self) -> DecodeResult { let v = self._next_int(EsU8, EsU64)?; if v > (::std::usize::MAX as u64) { Err(IntTooBig(v as usize)) @@ -747,7 +747,7 @@ pub mod reader { fn read_i8(&mut self) -> DecodeResult { Ok(doc_as_u8(self.next_doc(EsI8)?) as i8) } - fn read_int(&mut self) -> DecodeResult { + fn read_isize(&mut self) -> DecodeResult { let v = self._next_int(EsI8, EsI64)? as i64; if v > (isize::MAX as i64) || v < (isize::MIN as i64) { debug!("FIXME \\#6122: Removing this makes this function miscompile"); @@ -1219,7 +1219,7 @@ pub mod writer { Ok(()) } - fn emit_uint(&mut self, v: usize) -> EncodeResult { + fn emit_usize(&mut self, v: usize) -> EncodeResult { self.emit_u64(v as u64) } fn emit_u64(&mut self, v: u64) -> EncodeResult { @@ -1247,7 +1247,7 @@ pub mod writer { self.wr_tagged_raw_u8(EsU8 as usize, v) } - fn emit_int(&mut self, v: isize) -> EncodeResult { + fn emit_isize(&mut self, v: isize) -> EncodeResult { self.emit_i64(v as i64) } fn emit_i64(&mut self, v: i64) -> EncodeResult { diff --git a/src/librbml/opaque.rs b/src/librbml/opaque.rs index 10f419d169181..6dc7a72b1b1bb 100644 --- a/src/librbml/opaque.rs +++ b/src/librbml/opaque.rs @@ -54,7 +54,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { Ok(()) } - fn emit_uint(&mut self, v: usize) -> EncodeResult { + fn emit_usize(&mut self, v: usize) -> EncodeResult { write_uleb128!(self, v) } @@ -75,7 +75,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { Ok(()) } - fn emit_int(&mut self, v: isize) -> EncodeResult { + fn emit_isize(&mut self, v: isize) -> EncodeResult { write_sleb128!(self, v) } @@ -120,7 +120,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_str(&mut self, v: &str) -> EncodeResult { - self.emit_uint(v.len())?; + self.emit_usize(v.len())?; let _ = self.cursor.write_all(v.as_bytes()); Ok(()) } @@ -139,7 +139,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { -> EncodeResult where F: FnOnce(&mut Self) -> EncodeResult { - self.emit_uint(v_id)?; + self.emit_usize(v_id)?; f(self) } @@ -221,7 +221,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult { - self.emit_uint(len)?; + self.emit_usize(len)?; f(self) } @@ -234,7 +234,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { fn emit_map(&mut self, len: usize, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult { - self.emit_uint(len)?; + self.emit_usize(len)?; f(self) } @@ -329,7 +329,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(value) } - fn read_uint(&mut self) -> Result { + fn read_usize(&mut self) -> Result { read_uleb128!(self, usize) } @@ -351,7 +351,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { unsafe { Ok(::std::mem::transmute(as_u8)) } } - fn read_int(&mut self) -> Result { + fn read_isize(&mut self) -> Result { read_sleb128!(self, isize) } @@ -376,7 +376,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { } fn read_str(&mut self) -> Result { - let len = self.read_uint()?; + let len = self.read_usize()?; let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); self.position += len; Ok(s.to_string()) @@ -391,7 +391,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { fn read_enum_variant(&mut self, _: &[&str], mut f: F) -> Result where F: FnMut(&mut Decoder<'a>, usize) -> Result { - let disr = self.read_uint()?; + let disr = self.read_usize()?; f(self, disr) } @@ -404,7 +404,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { fn read_enum_struct_variant(&mut self, _: &[&str], mut f: F) -> Result where F: FnMut(&mut Decoder<'a>, usize) -> Result { - let disr = self.read_uint()?; + let disr = self.read_usize()?; f(self, disr) } @@ -483,7 +483,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { fn read_seq(&mut self, f: F) -> Result where F: FnOnce(&mut Decoder<'a>, usize) -> Result { - let len = self.read_uint()?; + let len = self.read_usize()?; f(self, len) } @@ -496,7 +496,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { fn read_map(&mut self, f: F) -> Result where F: FnOnce(&mut Decoder<'a>, usize) -> Result { - let len = self.read_uint()?; + let len = self.read_usize()?; f(self, len) } diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 5d652ba2f55bb..7b5092e8848e4 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -136,7 +136,7 @@ impl< for item in self { bits |= item.to_usize(); } - s.emit_uint(bits) + s.emit_usize(bits) } } @@ -144,7 +144,7 @@ impl< T: Decodable + CLike > Decodable for EnumSet { fn decode(d: &mut D) -> Result, D::Error> { - let bits = d.read_uint()?; + let bits = d.read_usize()?; let mut set = EnumSet::new(); for bit in 0..(mem::size_of::()*8) { if bits & (1 << bit) != 0 { diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 6c4b6c4506b81..34df594e84756 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -495,13 +495,13 @@ impl<'a> ::Encoder for Encoder<'a> { Ok(()) } - fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -743,13 +743,13 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { Ok(()) } - fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -2137,12 +2137,12 @@ impl ::Decoder for Decoder { expect!(self.pop(), Null) } - read_primitive! { read_uint, usize } + read_primitive! { read_usize, usize } read_primitive! { read_u8, u8 } read_primitive! { read_u16, u16 } read_primitive! { read_u32, u32 } read_primitive! { read_u64, u64 } - read_primitive! { read_int, isize } + read_primitive! { read_isize, isize } read_primitive! { read_i8, i8 } read_primitive! { read_i16, i16 } read_primitive! { read_i32, i32 } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 0fcab1347d160..b75ec5dad8ddd 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -24,12 +24,12 @@ pub trait Encoder { // Primitive types: fn emit_nil(&mut self) -> Result<(), Self::Error>; - fn emit_uint(&mut self, v: usize) -> Result<(), Self::Error>; + fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>; fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; - fn emit_int(&mut self, v: isize) -> Result<(), Self::Error>; + fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error>; fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; @@ -108,12 +108,12 @@ pub trait Decoder { // Primitive types: fn read_nil(&mut self) -> Result<(), Self::Error>; - fn read_uint(&mut self) -> Result; + fn read_usize(&mut self) -> Result; fn read_u64(&mut self) -> Result; fn read_u32(&mut self) -> Result; fn read_u16(&mut self) -> Result; fn read_u8(&mut self) -> Result; - fn read_int(&mut self) -> Result; + fn read_isize(&mut self) -> Result; fn read_i64(&mut self) -> Result; fn read_i32(&mut self) -> Result; fn read_i16(&mut self) -> Result; @@ -200,13 +200,13 @@ pub trait Decodable: Sized { impl Encodable for usize { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_uint(*self) + s.emit_usize(*self) } } impl Decodable for usize { fn decode(d: &mut D) -> Result { - d.read_uint() + d.read_usize() } } @@ -260,13 +260,13 @@ impl Decodable for u64 { impl Encodable for isize { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_int(*self) + s.emit_isize(*self) } } impl Decodable for isize { fn decode(d: &mut D) -> Result { - d.read_int() + d.read_isize() } } From 00d4a43d84d5979332dbbbc4329211b007f7fe45 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 29 Jul 2016 18:56:09 -0400 Subject: [PATCH 277/768] Remove style guide. We originally imported this into the repository with the intent of fixing it up. Instead, nothing happened. Its appearance on rust-lang.org makes it seem semi-official, but it's not. The rustfmt strike team will end up producing something like this anyway, and leaving it around does nothing but mislead people. --- src/doc/style/README.md | 64 ------ src/doc/style/SUMMARY.md | 50 ----- src/doc/style/errors/README.md | 3 - src/doc/style/errors/ergonomics.md | 66 ------ src/doc/style/errors/handling.md | 7 - src/doc/style/errors/propagation.md | 8 - src/doc/style/errors/signaling.md | 125 ----------- src/doc/style/features/README.md | 9 - src/doc/style/features/crates.md | 6 - .../features/functions-and-methods/README.md | 44 ---- .../functions-and-methods/convenience.md | 43 ---- .../features/functions-and-methods/input.md | 203 ------------------ .../features/functions-and-methods/output.md | 56 ----- src/doc/style/features/let.md | 103 --------- src/doc/style/features/loops.md | 13 -- src/doc/style/features/match.md | 26 --- src/doc/style/features/modules.md | 133 ------------ src/doc/style/features/traits/README.md | 22 -- src/doc/style/features/traits/common.md | 71 ------ src/doc/style/features/traits/extensions.md | 7 - src/doc/style/features/traits/generics.md | 67 ------ src/doc/style/features/traits/objects.md | 49 ----- src/doc/style/features/traits/overloading.md | 7 - src/doc/style/features/traits/reuse.md | 30 --- src/doc/style/features/types/README.md | 68 ------ src/doc/style/features/types/conversions.md | 22 -- src/doc/style/features/types/newtype.md | 69 ------ src/doc/style/ownership/README.md | 3 - src/doc/style/ownership/builders.md | 176 --------------- src/doc/style/ownership/cell-smart.md | 4 - src/doc/style/ownership/constructors.md | 62 ------ src/doc/style/ownership/destructors.md | 22 -- src/doc/style/ownership/raii.md | 12 -- src/doc/style/platform.md | 7 - src/doc/style/safety/README.md | 19 -- src/doc/style/safety/lib-guarantees.md | 81 ------- src/doc/style/safety/unsafe.md | 22 -- src/doc/style/style/README.md | 5 - src/doc/style/style/braces.md | 77 ------- src/doc/style/style/comments.md | 122 ----------- src/doc/style/style/features.md | 13 -- src/doc/style/style/imports.md | 50 ----- src/doc/style/style/naming/README.md | 115 ---------- src/doc/style/style/naming/containers.md | 69 ------ src/doc/style/style/naming/conversions.md | 32 --- src/doc/style/style/naming/iterators.md | 32 --- src/doc/style/style/naming/ownership.md | 34 --- src/doc/style/style/optional.md | 3 - src/doc/style/style/organization.md | 14 -- src/doc/style/style/whitespace.md | 133 ------------ src/doc/style/testing/README.md | 5 - src/doc/style/testing/unit.md | 30 --- src/doc/style/todo.md | 5 - 53 files changed, 2518 deletions(-) delete mode 100644 src/doc/style/README.md delete mode 100644 src/doc/style/SUMMARY.md delete mode 100644 src/doc/style/errors/README.md delete mode 100644 src/doc/style/errors/ergonomics.md delete mode 100644 src/doc/style/errors/handling.md delete mode 100644 src/doc/style/errors/propagation.md delete mode 100644 src/doc/style/errors/signaling.md delete mode 100644 src/doc/style/features/README.md delete mode 100644 src/doc/style/features/crates.md delete mode 100644 src/doc/style/features/functions-and-methods/README.md delete mode 100644 src/doc/style/features/functions-and-methods/convenience.md delete mode 100644 src/doc/style/features/functions-and-methods/input.md delete mode 100644 src/doc/style/features/functions-and-methods/output.md delete mode 100644 src/doc/style/features/let.md delete mode 100644 src/doc/style/features/loops.md delete mode 100644 src/doc/style/features/match.md delete mode 100644 src/doc/style/features/modules.md delete mode 100644 src/doc/style/features/traits/README.md delete mode 100644 src/doc/style/features/traits/common.md delete mode 100644 src/doc/style/features/traits/extensions.md delete mode 100644 src/doc/style/features/traits/generics.md delete mode 100644 src/doc/style/features/traits/objects.md delete mode 100644 src/doc/style/features/traits/overloading.md delete mode 100644 src/doc/style/features/traits/reuse.md delete mode 100644 src/doc/style/features/types/README.md delete mode 100644 src/doc/style/features/types/conversions.md delete mode 100644 src/doc/style/features/types/newtype.md delete mode 100644 src/doc/style/ownership/README.md delete mode 100644 src/doc/style/ownership/builders.md delete mode 100644 src/doc/style/ownership/cell-smart.md delete mode 100644 src/doc/style/ownership/constructors.md delete mode 100644 src/doc/style/ownership/destructors.md delete mode 100644 src/doc/style/ownership/raii.md delete mode 100644 src/doc/style/platform.md delete mode 100644 src/doc/style/safety/README.md delete mode 100644 src/doc/style/safety/lib-guarantees.md delete mode 100644 src/doc/style/safety/unsafe.md delete mode 100644 src/doc/style/style/README.md delete mode 100644 src/doc/style/style/braces.md delete mode 100644 src/doc/style/style/comments.md delete mode 100644 src/doc/style/style/features.md delete mode 100644 src/doc/style/style/imports.md delete mode 100644 src/doc/style/style/naming/README.md delete mode 100644 src/doc/style/style/naming/containers.md delete mode 100644 src/doc/style/style/naming/conversions.md delete mode 100644 src/doc/style/style/naming/iterators.md delete mode 100644 src/doc/style/style/naming/ownership.md delete mode 100644 src/doc/style/style/optional.md delete mode 100644 src/doc/style/style/organization.md delete mode 100644 src/doc/style/style/whitespace.md delete mode 100644 src/doc/style/testing/README.md delete mode 100644 src/doc/style/testing/unit.md delete mode 100644 src/doc/style/todo.md diff --git a/src/doc/style/README.md b/src/doc/style/README.md deleted file mode 100644 index 8d837d1a1a916..0000000000000 --- a/src/doc/style/README.md +++ /dev/null @@ -1,64 +0,0 @@ -% Style Guidelines - -This document collects the emerging principles, conventions, abstractions, and -best practices for writing Rust code. - -Since Rust is evolving at a rapid pace, these guidelines are -preliminary. The hope is that writing them down explicitly will help -drive discussion, consensus and adoption. - -Whenever feasible, guidelines provide specific examples from Rust's standard -libraries. - -### Guideline statuses - -Every guideline has a status: - -* **[FIXME]**: Marks places where there is more work to be done. In - some cases, that just means going through the RFC process. - -* **[FIXME #NNNNN]**: Like **[FIXME]**, but links to the issue tracker. - -* **[RFC #NNNN]**: Marks accepted guidelines, linking to the rust-lang - RFC establishing them. - -### Guideline stabilization - -One purpose of these guidelines is to reach decisions on a number of -cross-cutting API and stylistic choices. Discussion and development of -the guidelines will happen primarily on https://internals.rust-lang.org/, -using the Guidelines category. Discussion can also occur on the -[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines). - -Guidelines that are under development or discussion will be marked with the -status **[FIXME]**, with a link to the issue tracker when appropriate. - -Once a concrete guideline is ready to be proposed, it should be filed -as an [FIXME: needs RFC](https://github.com/rust-lang/rfcs). If the RFC is -accepted, the official guidelines will be updated to match, and will -include the tag **[RFC #NNNN]** linking to the RFC document. - -### What's in this document - -This document is broken into four parts: - -* **[Style](style/README.md)** provides a set of rules governing naming conventions, - whitespace, and other stylistic issues. - -* **[Guidelines by Rust feature](features/README.md)** places the focus on each of - Rust's features, starting from expressions and working the way out toward - crates, dispensing guidelines relevant to each. - -* **Topical guidelines and patterns**. The rest of the document proceeds by - cross-cutting topic, starting with - [Ownership and resources](ownership/README.md). - -* **APIs for a changing Rust** - discusses the forward-compatibility hazards, especially those that interact - with the pre-1.0 library stabilization process. - -> **[FIXME]** Add cross-references throughout this document to the tutorial, -> reference manual, and other guides. - -> **[FIXME]** What are some _non_-goals, _non_-principles, or _anti_-patterns that -> we should document? diff --git a/src/doc/style/SUMMARY.md b/src/doc/style/SUMMARY.md deleted file mode 100644 index 508ede6c4a0ac..0000000000000 --- a/src/doc/style/SUMMARY.md +++ /dev/null @@ -1,50 +0,0 @@ -# Summary - -* [Style](style/README.md) - * [Whitespace](style/whitespace.md) - * [Comments](style/comments.md) - * [Braces, semicolons, commas](style/braces.md) - * [Naming](style/naming/README.md) - * [Ownership variants](style/naming/ownership.md) - * [Containers/wrappers](style/naming/containers.md) - * [Conversions](style/naming/conversions.md) - * [Iterators](style/naming/iterators.md) - * [Imports](style/imports.md) - * [Organization](style/organization.md) -* [Guidelines by Rust feature](features/README.md) - * [Let binding](features/let.md) - * [Pattern matching](features/match.md) - * [Loops](features/loops.md) - * [Functions and methods](features/functions-and-methods/README.md) - * [Input](features/functions-and-methods/input.md) - * [Output](features/functions-and-methods/output.md) - * [For convenience](features/functions-and-methods/convenience.md) - * [Types](features/types/README.md) - * [Conversions](features/types/conversions.md) - * [The newtype pattern](features/types/newtype.md) - * [Traits](features/traits/README.md) - * [For generics](features/traits/generics.md) - * [For objects](features/traits/objects.md) - * [For overloading](features/traits/overloading.md) - * [For extensions](features/traits/extensions.md) - * [For reuse](features/traits/reuse.md) - * [Common traits](features/traits/common.md) - * [Modules](features/modules.md) - * [Crates](features/crates.md) -* [Ownership and resources](ownership/README.md) - * [Constructors](ownership/constructors.md) - * [Builders](ownership/builders.md) - * [Destructors](ownership/destructors.md) - * [RAII](ownership/raii.md) - * [Cells and smart pointers](ownership/cell-smart.md) -* [Errors](errors/README.md) - * [Signaling](errors/signaling.md) - * [Handling](errors/handling.md) - * [Propagation](errors/propagation.md) - * [Ergonomics](errors/ergonomics.md) -* [Safety and guarantees](safety/README.md) - * [Using unsafe](safety/unsafe.md) - * [Library guarantees](safety/lib-guarantees.md) -* [Testing](testing/README.md) - * [Unit testing](testing/unit.md) -* [FFI, platform-specific code](platform.md) diff --git a/src/doc/style/errors/README.md b/src/doc/style/errors/README.md deleted file mode 100644 index 444da26ff8fed..0000000000000 --- a/src/doc/style/errors/README.md +++ /dev/null @@ -1,3 +0,0 @@ -% Errors - -> **[FIXME]** Add some general text here. diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md deleted file mode 100644 index 269f2a289464a..0000000000000 --- a/src/doc/style/errors/ergonomics.md +++ /dev/null @@ -1,66 +0,0 @@ -% Ergonomic error handling - -Error propagation with raw `Result`s can require tedious matching and -repackaging. This tedium is largely alleviated by the `try!` macro, -and can be completely removed (in some cases) by the "`Result`-`impl`" -pattern. - -### The `try!` macro - -Prefer - -```rust,ignore -use std::io::{File, Open, Write, IoError}; - -struct Info { - name: String, - age: i32, - rating: i32 -} - -fn write_info(info: &Info) -> Result<(), IoError> { - let mut file = File::open_mode(&Path::new("my_best_friends.txt"), - Open, Write); - // Early return on error - try!(file.write_line(&format!("name: {}", info.name))); - try!(file.write_line(&format!("age: {}", info.age))); - try!(file.write_line(&format!("rating: {}", info.rating))); - return Ok(()); -} -``` - -over - -```rust,ignore -use std::io::{File, Open, Write, IoError}; - -struct Info { - name: String, - age: i32, - rating: i32 -} - -fn write_info(info: &Info) -> Result<(), IoError> { - let mut file = File::open_mode(&Path::new("my_best_friends.txt"), - Open, Write); - // Early return on error - match file.write_line(&format!("name: {}", info.name)) { - Ok(_) => (), - Err(e) => return Err(e) - } - match file.write_line(&format!("age: {}", info.age)) { - Ok(_) => (), - Err(e) => return Err(e) - } - return file.write_line(&format!("rating: {}", info.rating)); -} -``` - -See -[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro) -for more details. - -### The `Result`-`impl` pattern [FIXME] - -> **[FIXME]** Document the way that the `io` module uses trait impls -> on `std::io::Result` to painlessly propagate errors. diff --git a/src/doc/style/errors/handling.md b/src/doc/style/errors/handling.md deleted file mode 100644 index 9b8a00d73665b..0000000000000 --- a/src/doc/style/errors/handling.md +++ /dev/null @@ -1,7 +0,0 @@ -% Handling errors - -### Use thread isolation to cope with failure. [FIXME] - -> **[FIXME]** Explain how to isolate threads and detect thread failure for recovery. - -### Consuming `Result` [FIXME] diff --git a/src/doc/style/errors/propagation.md b/src/doc/style/errors/propagation.md deleted file mode 100644 index 0a347cd577b90..0000000000000 --- a/src/doc/style/errors/propagation.md +++ /dev/null @@ -1,8 +0,0 @@ -% Propagation - -> **[FIXME]** We need guidelines on how to layer error information up a stack of -> abstractions. - -### Error interoperation [FIXME] - -> **[FIXME]** Document the `FromError` infrastructure. diff --git a/src/doc/style/errors/signaling.md b/src/doc/style/errors/signaling.md deleted file mode 100644 index 4038ec10b9ab5..0000000000000 --- a/src/doc/style/errors/signaling.md +++ /dev/null @@ -1,125 +0,0 @@ -% Signaling errors [RFC #236] - -> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236). - -Errors fall into one of three categories: - -* Catastrophic errors, e.g. out-of-memory. -* Contract violations, e.g. wrong input encoding, index out of bounds. -* Obstructions, e.g. file not found, parse error. - -The basic principle of the convention is that: - -* Catastrophic errors and programming errors (bugs) can and should only be -recovered at a *coarse grain*, i.e. a thread boundary. -* Obstructions preventing an operation should be reported at a maximally *fine -grain* -- to the immediate invoker of the operation. - -## Catastrophic errors - -An error is _catastrophic_ if there is no meaningful way for the current thread to -continue after the error occurs. - -Catastrophic errors are _extremely_ rare, especially outside of `libstd`. - -**Canonical examples**: out of memory, stack overflow. - -### For catastrophic errors, panic - -For errors like stack overflow, Rust currently aborts the process, but -could in principle panic, which (in the best case) would allow -reporting and recovery from a supervisory thread. - -## Contract violations - -An API may define a contract that goes beyond the type checking enforced by the -compiler. For example, slices support an indexing operation, with the contract -that the supplied index must be in bounds. - -Contracts can be complex and involve more than a single function invocation. For -example, the `RefCell` type requires that `borrow_mut` not be called until all -existing borrows have been relinquished. - -### For contract violations, panic - -A contract violation is always a bug, and for bugs we follow the Erlang -philosophy of "let it crash": we assume that software *will* have bugs, and we -design coarse-grained thread boundaries to report, and perhaps recover, from these -bugs. - -### Contract design - -One subtle aspect of these guidelines is that the contract for a function is -chosen by an API designer -- and so the designer also determines what counts as -a violation. - -This RFC does not attempt to give hard-and-fast rules for designing -contracts. However, here are some rough guidelines: - -* Prefer expressing contracts through static types whenever possible. - -* It *must* be possible to write code that uses the API without violating the - contract. - -* Contracts are most justified when violations are *inarguably* bugs -- but this - is surprisingly rare. - -* Consider whether the API client could benefit from the contract-checking - logic. The checks may be expensive. Or there may be useful programming - patterns where the client does not want to check inputs before hand, but would - rather attempt the operation and then find out whether the inputs were invalid. - -* When a contract violation is the *only* kind of error a function may encounter - -- i.e., there are no obstructions to its success other than "bad" inputs -- - using `Result` or `Option` instead is especially warranted. Clients can then use - `unwrap` to assert that they have passed valid input, or re-use the error - checking done by the API for their own purposes. - -* When in doubt, use loose contracts and instead return a `Result` or `Option`. - -## Obstructions - -An operation is *obstructed* if it cannot be completed for some reason, even -though the operation's contract has been satisfied. Obstructed operations may -have (documented!) side effects -- they are not required to roll back after -encountering an obstruction. However, they should leave the data structures in -a "coherent" state (satisfying their invariants, continuing to guarantee safety, -etc.). - -Obstructions may involve external conditions (e.g., I/O), or they may involve -aspects of the input that are not covered by the contract. - -**Canonical examples**: file not found, parse error. - -### For obstructions, use `Result` - -The -[`Result` type](https://doc.rust-lang.org/stable/std/result/index.html) -represents either a success (yielding `T`) or failure (yielding `E`). By -returning a `Result`, a function allows its clients to discover and react to -obstructions in a fine-grained way. - -#### What about `Option`? - -The `Option` type should not be used for "obstructed" operations; it -should only be used when a `None` return value could be considered a -"successful" execution of the operation. - -This is of course a somewhat subjective question, but a good litmus -test is: would a reasonable client ever ignore the result? The -`Result` type provides a lint that ensures the result is actually -inspected, while `Option` does not, and this difference of behavior -can help when deciding between the two types. - -Another litmus test: can the operation be understood as asking a -question (possibly with sideeffects)? Operations like `pop` on a -vector can be viewed as asking for the contents of the first element, -with the side effect of removing it if it exists -- with an `Option` -return value. - -## Do not provide both `Result` and `panic!` variants. - -An API should not provide both `Result`-producing and `panic`king versions of an -operation. It should provide just the `Result` version, allowing clients to use -`try!` or `unwrap` instead as needed. This is part of the general pattern of -cutting down on redundant variants by instead using method chaining. diff --git a/src/doc/style/features/README.md b/src/doc/style/features/README.md deleted file mode 100644 index 09657503d20d1..0000000000000 --- a/src/doc/style/features/README.md +++ /dev/null @@ -1,9 +0,0 @@ -% Guidelines by language feature - -Rust provides a unique combination of language features, some new and some -old. This section gives guidance on when and how to use Rust's features, and -brings attention to some of the tradeoffs between different features. - -Notably missing from this section is an in-depth discussion of Rust's pointer -types (both built-in and in the library). The topic of pointers is discussed at -length in a [separate section on ownership](../ownership/README.md). diff --git a/src/doc/style/features/crates.md b/src/doc/style/features/crates.md deleted file mode 100644 index 4748b05f17f74..0000000000000 --- a/src/doc/style/features/crates.md +++ /dev/null @@ -1,6 +0,0 @@ -% Crates - -> **[FIXME]** What general guidelines should we provide for crate design? - -> Possible topics: facades; per-crate preludes (to be imported as globs); -> "lib.rs" diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md deleted file mode 100644 index a3559ca3e7b6b..0000000000000 --- a/src/doc/style/features/functions-and-methods/README.md +++ /dev/null @@ -1,44 +0,0 @@ -% Functions and methods - -### Prefer methods to functions if there is a clear receiver. **[FIXME: needs RFC]** - -Prefer - -```rust,ignore -impl Foo { - pub fn frob(&self, w: widget) { ... } -} -``` - -over - -```rust,ignore -pub fn frob(foo: &Foo, w: widget) { ... } -``` - -for any operation that is clearly associated with a particular -type. - -Methods have numerous advantages over functions: - -* They do not need to be imported or qualified to be used: all you - need is a value of the appropriate type. -* Their invocation performs autoborrowing (including mutable borrows). -* They make it easy to answer the question "what can I do with a value - of type `T`" (especially when using rustdoc). -* They provide `self` notation, which is more concise and often more - clearly conveys ownership distinctions. - -> **[FIXME]** Revisit these guidelines with -> [UFCS](https://github.com/nick29581/rfcs/blob/ufcs/0000-ufcs.md) and -> conventions developing around it. - - - -### Guidelines for inherent methods. **[FIXME]** - -> **[FIXME]** We need guidelines for when to provide inherent methods on a type, -> versus methods through a trait or functions. - -> **NOTE**: Rules for method resolution around inherent methods are in flux, -> which may impact the guidelines. diff --git a/src/doc/style/features/functions-and-methods/convenience.md b/src/doc/style/features/functions-and-methods/convenience.md deleted file mode 100644 index 69fd3772a761f..0000000000000 --- a/src/doc/style/features/functions-and-methods/convenience.md +++ /dev/null @@ -1,43 +0,0 @@ -% Convenience methods - -### Provide small, coherent sets of convenience methods. **[FIXME: needs RFC]** - -_Convenience methods_ wrap up existing functionality in a more convenient -way. The work done by a convenience method varies widely: - -* _Re-providing functions as methods_. For example, the `std::path::Path` type - provides methods like `stat` on `Path`s that simply invoke the corresponding - function in `std::io::fs`. -* _Skipping through conversions_. For example, the `str` type provides a - `.len()` convenience method which is also expressible as `.as_bytes().len()`. - Sometimes the conversion is more complex: the `str` module also provides - `from_chars`, which encapsulates a simple use of iterators. -* _Encapsulating common arguments_. For example, vectors of `&str`s - provide a `connect` as well as a special case, `concat`, that is expressible - using `connect` with a fixed separator of `""`. -* _Providing more efficient special cases_. The `connect` and `concat` example - also applies here: singling out `concat` as a special case allows for a more - efficient implementation. - - Note, however, that the `connect` method actually detects the special case - internally and invokes `concat`. Usually, it is not necessary to add a public - convenience method just for efficiency gains; there should also be a - _conceptual_ reason to add it, e.g. because it is such a common special case. - -It is tempting to add convenience methods in a one-off, haphazard way as -common use patterns emerge. Avoid this temptation, and instead _design_ small, -coherent sets of convenience methods that are easy to remember: - -* _Small_: Avoid combinatorial explosions of convenience methods. For example, - instead of adding `_str` variants of methods that provide a `str` output, - instead ensure that the normal output type of methods is easily convertible to - `str`. -* _Coherent_: Look for small groups of convenience methods that make sense to - include together. For example, the `Path` API mentioned above includes a small - selection of the most common filesystem operations that take a `Path` - argument. If one convenience method strongly suggests the existence of others, - consider adding the whole group. -* _Memorable_: It is not worth saving a few characters of typing if you have to - look up the name of a convenience method every time you use it. Add - convenience methods with names that are obvious and easy to remember, and add - them for the most common or painful use cases. diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md deleted file mode 100644 index 5b63a4514443c..0000000000000 --- a/src/doc/style/features/functions-and-methods/input.md +++ /dev/null @@ -1,203 +0,0 @@ -% Input to functions and methods - -### Let the client decide when to copy and where to place data. [FIXME: needs RFC] - -#### Copying: - -Prefer - -```rust,ignore -fn foo(b: Bar) { - // use b as owned, directly -} -``` - -over - -```rust,ignore -fn foo(b: &Bar) { - let b = b.clone(); - // use b as owned after cloning -} -``` - -If a function requires ownership of a value of unknown type `T`, but does not -otherwise need to make copies, the function should take ownership of the -argument (pass by value `T`) rather than using `.clone()`. That way, the caller -can decide whether to relinquish ownership or to `clone`. - -Similarly, the `Copy` trait bound should only be demanded it when absolutely -needed, not as a way of signaling that copies should be cheap to make. - -#### Placement: - -Prefer - -```rust,ignore -fn foo(b: Bar) -> Bar { ... } -``` - -over - -```rust,ignore -fn foo(b: Box) -> Box { ... } -``` - -for concrete types `Bar` (as opposed to trait objects). This way, the caller can -decide whether to place data on the stack or heap. No overhead is imposed by -letting the caller determine the placement. - -### Minimize assumptions about parameters. [FIXME: needs RFC] - -The fewer assumptions a function makes about its inputs, the more widely usable -it becomes. - -#### Minimizing assumptions through generics: - -Prefer - -```rust,ignore -fn foo>(c: T) { ... } -``` - -over any of - -```rust,ignore -fn foo(c: &[i32]) { ... } -fn foo(c: &Vec) { ... } -fn foo(c: &SomeOtherCollection) { ... } -``` - -if the function only needs to iterate over the data. - -More generally, consider using generics to pinpoint the assumptions a function -needs to make about its arguments. - -On the other hand, generics can make it more difficult to read and understand a -function's signature. Aim for "natural" parameter types that a neither overly -concrete nor overly abstract. See the discussion on -[traits](../traits/README.md) for more guidance. - - -#### Minimizing ownership assumptions: - -Prefer either of - -```rust,ignore -fn foo(b: &Bar) { ... } -fn foo(b: &mut Bar) { ... } -``` - -over - -```rust,ignore -fn foo(b: Bar) { ... } -``` - -That is, prefer borrowing arguments rather than transferring ownership, unless -ownership is actually needed. - -### Prefer compound return types to out-parameters. [FIXME: needs RFC] - -Prefer - -```rust,ignore -fn foo() -> (Bar, Bar) -``` - -over - -```rust,ignore -fn foo(output: &mut Bar) -> Bar -``` - -for returning multiple `Bar` values. - -Compound return types like tuples and structs are efficiently compiled -and do not require heap allocation. If a function needs to return -multiple values, it should do so via one of these types. - -The primary exception: sometimes a function is meant to modify data -that the caller already owns, for example to re-use a buffer: - -```rust,ignore -fn read(&mut self, buf: &mut [u8]) -> std::io::Result -``` - -(From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).) - -### Consider validating arguments, statically or dynamically. [FIXME: needs RFC] - -_Note: this material is closely related to - [library-level guarantees](../../safety/lib-guarantees.md)._ - -Rust APIs do _not_ generally follow the -[robustness principle](https://en.wikipedia.org/wiki/Robustness_principle): "be -conservative in what you send; be liberal in what you accept". - -Instead, Rust code should _enforce_ the validity of input whenever practical. - -Enforcement can be achieved through the following mechanisms (listed -in order of preference). - -#### Static enforcement: - -Choose an argument type that rules out bad inputs. - -For example, prefer - -```rust,ignore -enum FooMode { - Mode1, - Mode2, - Mode3, -} -fn foo(mode: FooMode) { ... } -``` - -over - -```rust,ignore -fn foo(mode2: bool, mode3: bool) { - assert!(!mode2 || !mode3); - ... -} -``` - -Static enforcement usually comes at little run-time cost: it pushes the -costs to the boundaries. It also catches bugs early, during compilation, -rather than through run-time failures. - -On the other hand, some properties are difficult or impossible to -express using types. - -#### Dynamic enforcement: - -Validate the input as it is processed (or ahead of time, if necessary). Dynamic -checking is often easier to implement than static checking, but has several -downsides: - -1. Runtime overhead (unless checking can be done as part of processing the input). -2. Delayed detection of bugs. -3. Introduces failure cases, either via `panic!` or `Result`/`Option` types (see - the [error handling guidelines](../../errors/README.md)), which must then be - dealt with by client code. - -#### Dynamic enforcement with `debug_assert!`: - -Same as dynamic enforcement, but with the possibility of easily turning off -expensive checks for production builds. - -#### Dynamic enforcement with opt-out: - -Same as dynamic enforcement, but adds sibling functions that opt out of the -checking. - -The convention is to mark these opt-out functions with a suffix like -`_unchecked` or by placing them in a `raw` submodule. - -The unchecked functions can be used judiciously in cases where (1) performance -dictates avoiding checks and (2) the client is otherwise confident that the -inputs are valid. - -> **[FIXME]** Should opt-out functions be marked `unsafe`? diff --git a/src/doc/style/features/functions-and-methods/output.md b/src/doc/style/features/functions-and-methods/output.md deleted file mode 100644 index e26eee53367cf..0000000000000 --- a/src/doc/style/features/functions-and-methods/output.md +++ /dev/null @@ -1,56 +0,0 @@ -% Output from functions and methods - -### Don't overpromise. [FIXME] - -> **[FIXME]** Add discussion of overly-specific return types, -> e.g. returning a compound iterator type rather than hiding it behind -> a use of newtype. - -### Let clients choose what to throw away. [FIXME: needs RFC] - -#### Return useful intermediate results: - -Many functions that answer a question also compute interesting related data. If -this data is potentially of interest to the client, consider exposing it in the -API. - -Prefer - -```rust,ignore -struct SearchResult { - found: bool, // item in container? - expected_index: usize // what would the item's index be? -} - -fn binary_search(&self, k: Key) -> SearchResult -``` -or - -```rust,ignore -fn binary_search(&self, k: Key) -> (bool, usize) -``` - -over - -```rust,ignore -fn binary_search(&self, k: Key) -> bool -``` - -#### Yield back ownership: - -Prefer - -```rust,ignore -fn from_utf8_owned(vv: Vec) -> Result> -``` - -over - -```rust,ignore -fn from_utf8_owned(vv: Vec) -> Option -``` - -The `from_utf8_owned` function gains ownership of a vector. In the successful -case, the function consumes its input, returning an owned string without -allocating or copying. In the unsuccessful case, however, the function returns -back ownership of the original slice. diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md deleted file mode 100644 index ba9787b45f13c..0000000000000 --- a/src/doc/style/features/let.md +++ /dev/null @@ -1,103 +0,0 @@ -% Let binding - -### Always separately bind RAII guards. [FIXME: needs RFC] - -Prefer - -```rust,ignore -fn use_mutex(m: sync::mutex::Mutex) { - let guard = m.lock(); - do_work(guard); - drop(guard); // unlock the lock - // do other work -} -``` - -over - -```rust,ignore -fn use_mutex(m: sync::mutex::Mutex) { - do_work(m.lock()); - // do other work -} -``` - -As explained in the [RAII guide](../ownership/raii.md), RAII guards are values -that represent ownership of some resource and whose destructor releases the -resource. Because the lifetime of guards are significant, they should always be -explicitly `let`-bound to make the lifetime clear. Consider using an explicit -`drop` to release the resource early. - -### Prefer conditional expressions to deferred initialization. [FIXME: needs RFC] - -Prefer - -```rust,ignore -let foo = match bar { - Baz => 0, - Quux => 1 -}; -``` - -over - -```rust,ignore -let foo; -match bar { - Baz => { - foo = 0; - } - Quux => { - foo = 1; - } -} -``` - -unless the conditions for initialization are too complex to fit into a simple -conditional expression. - -### Use type annotations for clarification; prefer explicit generics when inference fails. [FIXME: needs RFC] - -Prefer - -```rust,ignore -let v = s.iter().map(|x| x * 2) - .collect::>(); -``` - -over - -```rust,ignore -let v: Vec<_> = s.iter().map(|x| x * 2) - .collect(); -``` - -When the type of a value might be unclear to the _reader_ of the code, consider -explicitly annotating it in a `let`. - -On the other hand, when the type is unclear to the _compiler_, prefer to specify -the type by explicit generics instantiation, which is usually more clear. - -### Shadowing [FIXME] - -> **[FIXME]** Repeatedly shadowing a binding is somewhat common in Rust code. We -> need to articulate a guideline on when it is appropriate/useful and when not. - -### Prefer immutable bindings. [FIXME: needs RFC] - -Use `mut` bindings to signal the span during which a value is mutated: - -```rust,ignore -let mut v = Vec::new(); -// push things onto v -let v = v; -// use v immutably henceforth -``` - -### Prefer to bind all `struct` or tuple fields. [FIXME: needs RFC] - -When consuming a `struct` or tuple via a `let`, bind all of the fields rather -than using `..` to elide the ones you don't need. The benefit is that when -fields are added, the compiler will pinpoint all of the places where that type -of value was consumed, which will often need to be adjusted to take the new -field properly into account. diff --git a/src/doc/style/features/loops.md b/src/doc/style/features/loops.md deleted file mode 100644 index b144825f98183..0000000000000 --- a/src/doc/style/features/loops.md +++ /dev/null @@ -1,13 +0,0 @@ -% Loops - -### Prefer `for` to `while`. [FIXME: needs RFC] - -A `for` loop is preferable to a `while` loop, unless the loop counts in a -non-uniform way (making it difficult to express using `for`). - -### Guidelines for `loop`. [FIXME] - -> **[FIXME]** When is `loop` recommended? Some possibilities: -> * For optimistic retry algorithms -> * For servers -> * To avoid mutating local variables sometimes needed to fit `while` diff --git a/src/doc/style/features/match.md b/src/doc/style/features/match.md deleted file mode 100644 index 0d5a1184a0e87..0000000000000 --- a/src/doc/style/features/match.md +++ /dev/null @@ -1,26 +0,0 @@ -% Pattern matching - -### Dereference `match` targets when possible. [FIXME: needs RFC] - -Prefer - -~~~~ignore -match *foo { - X(...) => ... - Y(...) => ... -} -~~~~ - -over - -~~~~ignore -match foo { - box X(...) => ... - box Y(...) => ... -} -~~~~ - - - - - diff --git a/src/doc/style/features/modules.md b/src/doc/style/features/modules.md deleted file mode 100644 index 995c5fda8a0aa..0000000000000 --- a/src/doc/style/features/modules.md +++ /dev/null @@ -1,133 +0,0 @@ -% Modules - -> **[FIXME]** What general guidelines should we provide for module design? - -> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns -> around modules. - -### Headers [FIXME: needs RFC] - -Organize module headers as follows: - 1. [Imports](../style/imports.md). - 1. `mod` declarations. - 1. `pub mod` declarations. - -### Avoid `path` directives. [FIXME: needs RFC] - -Avoid using `#[path="..."]` directives; make the file system and -module hierarchy match, instead. - -### Use the module hierarchy to organize APIs into coherent sections. [FIXME] - -> **[FIXME]** Flesh this out with examples; explain what a "coherent -> section" is with examples. -> -> The module hierarchy defines both the public and internal API of your module. -> Breaking related functionality into submodules makes it understandable to both -> users and contributors to the module. - -### Place modules in their own file. [FIXME: needs RFC] - -> **[FIXME]** -> - "<100 lines" is arbitrary, but it's a clearer recommendation -> than "~1 page" or similar suggestions that vary by screen size, etc. - -For all except very short modules (<100 lines) and [tests](../testing/README.md), -place the module `foo` in a separate file, as in: - -```rust,ignore -pub mod foo; - -// in foo.rs or foo/mod.rs -pub fn bar() { println!("..."); } -/* ... */ -``` - -rather than declaring it inline: - -```rust,ignore -pub mod foo { - pub fn bar() { println!("..."); } - /* ... */ -} -``` - -#### Use subdirectories for modules with children. [FIXME: needs RFC] - -For modules that themselves have submodules, place the module in a separate -directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory. - -Note the structure of -[`std::io`](https://doc.rust-lang.org/std/io/). Many of the submodules lack -children, like -[`io::fs`](https://doc.rust-lang.org/std/io/fs/) -and -[`io::stdio`](https://doc.rust-lang.org/std/io/stdio/). -On the other hand, -[`io::net`](https://doc.rust-lang.org/std/io/net/) -contains submodules, so it lives in a separate directory: - -```text -io/mod.rs - io/extensions.rs - io/fs.rs - io/net/mod.rs - io/net/addrinfo.rs - io/net/ip.rs - io/net/tcp.rs - io/net/udp.rs - io/net/unix.rs - io/pipe.rs - ... -``` - -While it is possible to define all of `io` within a single directory, -mirroring the module hierarchy in the directory structure makes -submodules of `io::net` easier to find. - -### Consider top-level definitions or reexports. [FIXME: needs RFC] - -For modules with submodules, -define or [reexport](https://doc.rust-lang.org/std/io/#reexports) commonly used -definitions at the top level: - -* Functionality relevant to the module itself or to many of its - children should be defined in `mod.rs`. -* Functionality specific to a submodule should live in that - submodule. Reexport at the top level for the most important or - common definitions. - -For example, -[`IoError`](https://doc.rust-lang.org/std/io/struct.IoError.html) -is defined in `io/mod.rs`, since it pertains to the entirety of `io`, -while -[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html) -is defined in `io/net/tcp.rs` and reexported in the `io` module. - -### Use internal module hierarchies for organization. [FIXME: needs RFC] - -> **[FIXME]** -> - Referencing internal modules from the standard library is subject to -> becoming outdated. - -Internal module hierarchies (i.e., private submodules) may be used to -hide implementation details that are not part of the module's API. - -For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem` -provides implementations for -[`BufReader`](https://doc.rust-lang.org/std/io/struct.BufReader.html) -and -[`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html), -but these are re-exported in `io/mod.rs` at the top level of the module: - -```rust,ignore -// libstd/io/mod.rs - -pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; -/* ... */ -mod mem; -``` - -This hides the detail that there even exists a `mod mem` in `io`, and -helps keep code organized while offering freedom to change the -implementation. diff --git a/src/doc/style/features/traits/README.md b/src/doc/style/features/traits/README.md deleted file mode 100644 index 1893db24466fa..0000000000000 --- a/src/doc/style/features/traits/README.md +++ /dev/null @@ -1,22 +0,0 @@ -% Traits - -Traits are probably Rust's most complex feature, supporting a wide range of use -cases and design tradeoffs. Patterns of trait usage are still emerging. - -### Know whether a trait will be used as an object. [FIXME: needs RFC] - -Trait objects have some [significant limitations](objects.md): methods -invoked through a trait object cannot use generics, and cannot use -`Self` except in receiver position. - -When designing a trait, decide early on whether the trait will be used -as an [object](objects.md) or as a [bound on generics](generics.md); -the tradeoffs are discussed in each of the linked sections. - -If a trait is meant to be used as an object, its methods should take -and return trait objects rather than use generics. - - -### Default methods [FIXME] - -> **[FIXME]** Guidelines for default methods. diff --git a/src/doc/style/features/traits/common.md b/src/doc/style/features/traits/common.md deleted file mode 100644 index e8699c75229d3..0000000000000 --- a/src/doc/style/features/traits/common.md +++ /dev/null @@ -1,71 +0,0 @@ -% Common traits - -### Eagerly implement common traits. [FIXME: needs RFC] - -Rust's trait system does not allow _orphans_: roughly, every `impl` must live -either in the crate that defines the trait or the implementing -type. Consequently, crates that define new types should eagerly implement all -applicable, common traits. - -To see why, consider the following situation: - -* Crate `std` defines trait `Debug`. -* Crate `url` defines type `Url`, without implementing `Debug`. -* Crate `webapp` imports from both `std` and `url`, - -There is no way for `webapp` to add `Debug` to `url`, since it defines neither. -(Note: the newtype pattern can provide an efficient, but inconvenient -workaround; see [newtype for views](../types/newtype.md)) - -The most important common traits to implement from `std` are: - -```text -Clone, Debug, Hash, Eq -``` - -#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME] - -> **[FIXME]**. This guideline is in flux while the "opt-in" nature of -> built-in traits is being decided. See https://github.com/rust-lang/rfcs/pull/127 - -### Prefer to derive, rather than implement. [FIXME: needs RFC] - -Deriving saves implementation effort, makes correctness trivial, and -automatically adapts to upstream changes. - -### Do not overload operators in surprising ways. [FIXME: needs RFC] - -Operators with built in syntax (`*`, `|`, and so on) can be provided for a type -by implementing the traits in `core::ops`. These operators come with strong -expectations: implement `Mul` only for an operation that bears some resemblance -to multiplication (and shares the expected properties, e.g. associativity), and -so on for the other traits. - -### The `Drop` trait - -The `Drop` trait is treated specially by the compiler as a way of -associating destructors with types. See -[the section on destructors](../../ownership/destructors.md) for -guidance. - -### The `Deref`/`DerefMut` traits - -#### Use `Deref`/`DerefMut` only for smart pointers. [FIXME: needs RFC] - -The `Deref` traits are used implicitly by the compiler in many circumstances, -and interact with method resolution. The relevant rules are designed -specifically to accommodate smart pointers, and so the traits should be used -only for that purpose. - -#### Do not fail within a `Deref`/`DerefMut` implementation. [FIXME: needs RFC] - -Because the `Deref` traits are invoked implicitly by the compiler in sometimes -subtle ways, failure during dereferencing can be extremely confusing. If a -dereference might not succeed, target the `Deref` trait as a `Result` or -`Option` type instead. - -#### Avoid inherent methods when implementing `Deref`/`DerefMut` [FIXME: needs RFC] - -The rules around method resolution and `Deref` are in flux, but inherent methods -on a type implementing `Deref` are likely to shadow any methods of the referent -with the same name. diff --git a/src/doc/style/features/traits/extensions.md b/src/doc/style/features/traits/extensions.md deleted file mode 100644 index fc3a03c01f5a1..0000000000000 --- a/src/doc/style/features/traits/extensions.md +++ /dev/null @@ -1,7 +0,0 @@ -% Using traits to add extension methods - -> **[FIXME]** Elaborate. - -### Consider using default methods rather than extension traits **[FIXME]** - -> **[FIXME]** Elaborate. diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md deleted file mode 100644 index f9dac1272c334..0000000000000 --- a/src/doc/style/features/traits/generics.md +++ /dev/null @@ -1,67 +0,0 @@ -% Using traits for bounds on generics - -The most widespread use of traits is for writing generic functions or types. For -example, the following signature describes a function for consuming any iterator -yielding items of type `A` to produce a collection of `A`: - -```rust,ignore -fn from_iter>(iterator: T) -> SomeCollection -``` - -Here, the `Iterator` trait specifies an interface that a type `T` must -explicitly implement to be used by this generic function. - -**Pros**: - -* _Reusability_. Generic functions can be applied to an open-ended collection of - types, while giving a clear contract for the functionality those types must - provide. -* _Static dispatch and optimization_. Each use of a generic function is - specialized ("monomorphized") to the particular types implementing the trait - bounds, which means that (1) invocations of trait methods are static, direct - calls to the implementation and (2) the compiler can inline and otherwise - optimize these calls. -* _Inline layout_. If a `struct` and `enum` type is generic over some type - parameter `T`, values of type `T` will be laid out _inline_ in the - `struct`/`enum`, without any indirection. -* _Inference_. Since the type parameters to generic functions can usually be - inferred, generic functions can help cut down on verbosity in code where - explicit conversions or other method calls would usually be necessary. See the - overloading/implicits use case below. -* _Precise types_. Because generics give a _name_ to the specific type - implementing a trait, it is possible to be precise about places where that - exact type is required or produced. For example, a function - - ```rust,ignore - fn binary(x: T, y: T) -> T - ``` - - is guaranteed to consume and produce elements of exactly the same type `T`; it - cannot be invoked with parameters of different types that both implement - `Trait`. - -**Cons**: - -* _Code size_. Specializing generic functions means that the function body is - duplicated. The increase in code size must be weighed against the performance - benefits of static dispatch. -* _Homogeneous types_. This is the other side of the "precise types" coin: if - `T` is a type parameter, it stands for a _single_ actual type. So for example - a `Vec` contains elements of a single concrete type (and, indeed, the - vector representation is specialized to lay these out in line). Sometimes - heterogeneous collections are useful; see - trait objects below. -* _Signature verbosity_. Heavy use of generics can bloat function signatures. - **[Ed. note]** This problem may be mitigated by some language improvements; stay tuned. - -### Favor widespread traits. **[FIXME: needs RFC]** - -Generic types are a form of abstraction, which entails a mental indirection: if -a function takes an argument of type `T` bounded by `Trait`, clients must first -think about the concrete types that implement `Trait` to understand how and when -the function is callable. - -To keep the cost of abstraction low, favor widely-known traits. Whenever -possible, implement and use traits provided as part of the standard library. Do -not introduce new traits for generics lightly; wait until there are a wide range -of types that can implement the type. diff --git a/src/doc/style/features/traits/objects.md b/src/doc/style/features/traits/objects.md deleted file mode 100644 index 34712ed1ae7f1..0000000000000 --- a/src/doc/style/features/traits/objects.md +++ /dev/null @@ -1,49 +0,0 @@ -% Using trait objects - -> **[FIXME]** What are uses of trait objects other than heterogeneous collections? - -Trait objects are useful primarily when _heterogeneous_ collections of objects -need to be treated uniformly; it is the closest that Rust comes to -object-oriented programming. - -```rust,ignore -struct Frame { ... } -struct Button { ... } -struct Label { ... } - -trait Widget { ... } - -impl Widget for Frame { ... } -impl Widget for Button { ... } -impl Widget for Label { ... } - -impl Frame { - fn new(contents: &[Box]) -> Frame { - ... - } -} - -fn make_gui() -> Box { - let b: Box = box Button::new(...); - let l: Box = box Label::new(...); - - box Frame::new([b, l]) as Box -} -``` - -By using trait objects, we can set up a GUI framework with a `Frame` widget that -contains a heterogeneous collection of children widgets. - -**Pros**: - -* _Heterogeneity_. When you need it, you really need it. -* _Code size_. Unlike generics, trait objects do not generate specialized - (monomorphized) versions of code, which can greatly reduce code size. - -**Cons**: - -* _No generic methods_. Trait objects cannot currently provide generic methods. -* _Dynamic dispatch and fat pointers_. Trait objects inherently involve - indirection and vtable dispatch, which can carry a performance penalty. -* _No Self_. Except for the method receiver argument, methods on trait objects - cannot use the `Self` type. diff --git a/src/doc/style/features/traits/overloading.md b/src/doc/style/features/traits/overloading.md deleted file mode 100644 index d7482c9619072..0000000000000 --- a/src/doc/style/features/traits/overloading.md +++ /dev/null @@ -1,7 +0,0 @@ -% Using traits for overloading - -> **[FIXME]** Elaborate. - -> **[FIXME]** We need to decide on guidelines for this use case. There are a few -> patterns emerging in current Rust code, but it's not clear how widespread they -> should be. diff --git a/src/doc/style/features/traits/reuse.md b/src/doc/style/features/traits/reuse.md deleted file mode 100644 index feedd3937fc9d..0000000000000 --- a/src/doc/style/features/traits/reuse.md +++ /dev/null @@ -1,30 +0,0 @@ -% Using traits to share implementations - -> **[FIXME]** Elaborate. - -> **[FIXME]** We probably want to discourage this, at least when used in a way -> that is publicly exposed. - -Traits that provide default implementations for function can provide code reuse -across types. For example, a `print` method can be defined across multiple -types as follows: - -``` Rust -trait Printable { - // Default method implementation - fn print(&self) { println!("{:?}", *self) } -} - -impl Printable for i32 {} - -impl Printable for String { - fn print(&self) { println!("{}", *self) } -} - -impl Printable for bool {} - -impl Printable for f32 {} -``` - -This allows the implementation of `print` to be shared across types, yet -overridden where needed, as seen in the `impl` for `String`. diff --git a/src/doc/style/features/types/README.md b/src/doc/style/features/types/README.md deleted file mode 100644 index d3b95d8a6e719..0000000000000 --- a/src/doc/style/features/types/README.md +++ /dev/null @@ -1,68 +0,0 @@ -% Data types - -### Use custom types to imbue meaning; do not abuse `bool`, `Option` or other core types. **[FIXME: needs RFC]** - -Prefer - -```rust,ignore -let w = Widget::new(Small, Round) -``` - -over - -```rust,ignore -let w = Widget::new(true, false) -``` - -Core types like `bool`, `u8` and `Option` have many possible interpretations. - -Use custom types (whether `enum`s, `struct`, or tuples) to convey -interpretation and invariants. In the above example, -it is not immediately clear what `true` and `false` are conveying without -looking up the argument names, but `Small` and `Round` are more suggestive. - -Using custom types makes it easier to expand the -options later on, for example by adding an `ExtraLarge` variant. - -See [the newtype pattern](newtype.md) for a no-cost way to wrap -existing types with a distinguished name. - -### Prefer private fields, except for passive data. **[FIXME: needs RFC]** - -Making a field public is a strong commitment: it pins down a representation -choice, _and_ prevents the type from providing any validation or maintaining any -invariants on the contents of the field, since clients can mutate it arbitrarily. - -Public fields are most appropriate for `struct` types in the C spirit: compound, -passive data structures. Otherwise, consider providing getter/setter methods -and hiding fields instead. - -> **[FIXME]** Cross-reference validation for function arguments. - -### Use custom `enum`s for alternatives, `bitflags` for C-style flags. **[FIXME: needs RFC]** - -Rust supports `enum` types with "custom discriminants": - -~~~~ -enum Color { - Red = 0xff0000, - Green = 0x00ff00, - Blue = 0x0000ff -} -~~~~ - -Custom discriminants are useful when an `enum` type needs to be serialized to an -integer value compatibly with some other system/language. They support -"typesafe" APIs: by taking a `Color`, rather than an integer, a function is -guaranteed to get well-formed inputs, even if it later views those inputs as -integers. - -An `enum` allows an API to request exactly one choice from among many. Sometimes -an API's input is instead the presence or absence of a set of flags. In C code, -this is often done by having each flag correspond to a particular bit, allowing -a single integer to represent, say, 32 or 64 flags. Rust's `std::bitflags` -module provides a typesafe way for doing so. - -### Phantom types. [FIXME] - -> **[FIXME]** Add some material on phantom types (https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/) diff --git a/src/doc/style/features/types/conversions.md b/src/doc/style/features/types/conversions.md deleted file mode 100644 index f0f230f57e557..0000000000000 --- a/src/doc/style/features/types/conversions.md +++ /dev/null @@ -1,22 +0,0 @@ -% Conversions between types - -### Associate conversions with the most specific type involved. **[FIXME: needs RFC]** - -When in doubt, prefer `to_`/`as_`/`into_` to `from_`, because they are -more ergonomic to use (and can be chained with other methods). - -For many conversions between two types, one of the types is clearly more -"specific": it provides some additional invariant or interpretation that is not -present in the other type. For example, `str` is more specific than `&[u8]`, -since it is a utf-8 encoded sequence of bytes. - -Conversions should live with the more specific of the involved types. Thus, -`str` provides both the `as_bytes` method and the `from_utf8` constructor for -converting to and from `&[u8]` values. Besides being intuitive, this convention -avoids polluting concrete types like `&[u8]` with endless conversion methods. - -### Explicitly mark lossy conversions, or do not label them as conversions. **[FIXME: needs RFC]** - -If a function's name implies that it is a conversion (prefix `from_`, `as_`, -`to_` or `into_`), but the function loses information, add a suffix `_lossy` or -otherwise indicate the lossyness. Consider avoiding the conversion name prefix. diff --git a/src/doc/style/features/types/newtype.md b/src/doc/style/features/types/newtype.md deleted file mode 100644 index 9646e3e82aa53..0000000000000 --- a/src/doc/style/features/types/newtype.md +++ /dev/null @@ -1,69 +0,0 @@ -% The newtype pattern - -A "newtype" is a tuple or `struct` with a single field. The terminology is borrowed from Haskell. - -Newtypes are a zero-cost abstraction: they introduce a new, distinct name for an -existing type, with no runtime overhead when converting between the two types. - -### Use newtypes to provide static distinctions. [FIXME: needs RFC] - -Newtypes can statically distinguish between different interpretations of an -underlying type. - -For example, a `f64` value might be used to represent a quantity in miles or in -kilometers. Using newtypes, we can keep track of the intended interpretation: - -```rust,ignore -struct Miles(pub f64); -struct Kilometers(pub f64); - -impl Miles { - fn as_kilometers(&self) -> Kilometers { ... } -} -impl Kilometers { - fn as_miles(&self) -> Miles { ... } -} -``` - -Once we have separated these two types, we can statically ensure that we do not -confuse them. For example, the function - -```rust,ignore -fn are_we_there_yet(distance_travelled: Miles) -> bool { ... } -``` - -cannot accidentally be called with a `Kilometers` value. The compiler will -remind us to perform the conversion, thus averting certain -[catastrophic bugs](http://en.wikipedia.org/wiki/Mars_Climate_Orbiter). - -### Use newtypes with private fields for hiding. [FIXME: needs RFC] - -A newtype can be used to hide representation details while making precise -promises to the client. - -For example, consider a function `my_transform` that returns a compound iterator -type `Enumerate>>`. We wish to hide this type from the -client, so that the client's view of the return type is roughly `Iterator<(usize, -T)>`. We can do so using the newtype pattern: - -```rust,ignore -struct MyTransformResult(Enumerate>>); -impl Iterator<(usize, T)> for MyTransformResult { ... } - -fn my_transform>(iter: Iter) -> MyTransformResult { - ... -} -``` - -Aside from simplifying the signature, this use of newtypes allows us to make a -expose and promise less to the client. The client does not know _how_ the result -iterator is constructed or represented, which means the representation can -change in the future without breaking client code. - -> **[FIXME]** Interaction with auto-deref. - -### Use newtypes to provide cost-free _views_ of another type. **[FIXME]** - -> **[FIXME]** Describe the pattern of using newtypes to provide a new set of -> inherent or trait methods, providing a different perspective on the underlying -> type. diff --git a/src/doc/style/ownership/README.md b/src/doc/style/ownership/README.md deleted file mode 100644 index 11bdb03a3a818..0000000000000 --- a/src/doc/style/ownership/README.md +++ /dev/null @@ -1,3 +0,0 @@ -% Ownership and resource management - -> **[FIXME]** Add general remarks about ownership/resources here. diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md deleted file mode 100644 index 3422591233275..0000000000000 --- a/src/doc/style/ownership/builders.md +++ /dev/null @@ -1,176 +0,0 @@ -% The builder pattern - -Some data structures are complicated to construct, due to their construction needing: - -* a large number of inputs -* compound data (e.g. slices) -* optional configuration data -* choice between several flavors - -which can easily lead to a large number of distinct constructors with -many arguments each. - -If `T` is such a data structure, consider introducing a `T` _builder_: - -1. Introduce a separate data type `TBuilder` for incrementally configuring a `T` - value. When possible, choose a better name: e.g. `Command` is the builder for - `Process`. -2. The builder constructor should take as parameters only the data _required_ to - make a `T`. -3. The builder should offer a suite of convenient methods for configuration, - including setting up compound inputs (like slices) incrementally. - These methods should return `self` to allow chaining. -4. The builder should provide one or more "_terminal_" methods for actually building a `T`. - -The builder pattern is especially appropriate when building a `T` involves side -effects, such as spawning a thread or launching a process. - -In Rust, there are two variants of the builder pattern, differing in the -treatment of ownership, as described below. - -### Non-consuming builders (preferred): - -In some cases, constructing the final `T` does not require the builder itself to -be consumed. The follow variant on -[`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html) -is one example: - -```rust,ignore -// NOTE: the actual Command API does not use owned Strings; -// this is a simplified version. - -pub struct Command { - program: String, - args: Vec, - cwd: Option, - // etc -} - -impl Command { - pub fn new(program: String) -> Command { - Command { - program: program, - args: Vec::new(), - cwd: None, - } - } - - /// Add an argument to pass to the program. - pub fn arg<'a>(&'a mut self, arg: String) -> &'a mut Command { - self.args.push(arg); - self - } - - /// Add multiple arguments to pass to the program. - pub fn args<'a>(&'a mut self, args: &[String]) - -> &'a mut Command { - self.args.push_all(args); - self - } - - /// Set the working directory for the child process. - pub fn cwd<'a>(&'a mut self, dir: String) -> &'a mut Command { - self.cwd = Some(dir); - self - } - - /// Executes the command as a child process, which is returned. - pub fn spawn(&self) -> std::io::Result { - ... - } -} -``` - -Note that the `spawn` method, which actually uses the builder configuration to -spawn a process, takes the builder by immutable reference. This is possible -because spawning the process does not require ownership of the configuration -data. - -Because the terminal `spawn` method only needs a reference, the configuration -methods take and return a mutable borrow of `self`. - -#### The benefit - -By using borrows throughout, `Command` can be used conveniently for both -one-liner and more complex constructions: - -```rust,ignore -// One-liners -Command::new("/bin/cat").arg("file.txt").spawn(); - -// Complex configuration -let mut cmd = Command::new("/bin/ls"); -cmd.arg("."); - -if size_sorted { - cmd.arg("-S"); -} - -cmd.spawn(); -``` - -### Consuming builders: - -Sometimes builders must transfer ownership when constructing the final type -`T`, meaning that the terminal methods must take `self` rather than `&self`: - -```rust,ignore -// A simplified excerpt from std::thread::Builder - -impl ThreadBuilder { - /// Name the thread-to-be. Currently the name is used for identification - /// only in failure messages. - pub fn named(mut self, name: String) -> ThreadBuilder { - self.name = Some(name); - self - } - - /// Redirect thread-local stdout. - pub fn stdout(mut self, stdout: Box) -> ThreadBuilder { - self.stdout = Some(stdout); - // ^~~~~~ this is owned and cannot be cloned/re-used - self - } - - /// Creates and executes a new child thread. - pub fn spawn(self, f: proc():Send) { - // consume self - ... - } -} -``` - -Here, the `stdout` configuration involves passing ownership of a `Writer`, -which must be transferred to the thread upon construction (in `spawn`). - -When the terminal methods of the builder require ownership, there is a basic tradeoff: - -* If the other builder methods take/return a mutable borrow, the complex - configuration case will work well, but one-liner configuration becomes - _impossible_. - -* If the other builder methods take/return an owned `self`, one-liners - continue to work well but complex configuration is less convenient. - -Under the rubric of making easy things easy and hard things possible, _all_ -builder methods for a consuming builder should take and returned an owned -`self`. Then client code works as follows: - -```rust,ignore -// One-liners -ThreadBuilder::new().named("my_thread").spawn(proc() { ... }); - -// Complex configuration -let mut thread = ThreadBuilder::new(); -thread = thread.named("my_thread_2"); // must re-assign to retain ownership - -if reroute { - thread = thread.stdout(mywriter); -} - -thread.spawn(proc() { ... }); -``` - -One-liners work as before, because ownership is threaded through each of the -builder methods until being consumed by `spawn`. Complex configuration, -however, is more verbose: it requires re-assigning the builder at each step. diff --git a/src/doc/style/ownership/cell-smart.md b/src/doc/style/ownership/cell-smart.md deleted file mode 100644 index cd027cc4aaffc..0000000000000 --- a/src/doc/style/ownership/cell-smart.md +++ /dev/null @@ -1,4 +0,0 @@ -% Cells and smart pointers - -> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and -> Arc (and how to use them together). diff --git a/src/doc/style/ownership/constructors.md b/src/doc/style/ownership/constructors.md deleted file mode 100644 index 51fc74ac1158a..0000000000000 --- a/src/doc/style/ownership/constructors.md +++ /dev/null @@ -1,62 +0,0 @@ -% Constructors - -### Define constructors as static, inherent methods. [FIXME: needs RFC] - -In Rust, "constructors" are just a convention: - -```rust,ignore -impl Vec { - pub fn new() -> Vec { ... } -} -``` - -Constructors are static (no `self`) inherent methods for the type that they -construct. Combined with the practice of -[fully importing type names](../style/imports.md), this convention leads to -informative but concise construction: - -```rust,ignore -use vec::Vec; - -// construct a new vector -let mut v = Vec::new(); -``` - -This convention also applied to conversion constructors (prefix `from` rather -than `new`). - -### Provide constructors for passive `struct`s with defaults. [FIXME: needs RFC] - -Given the `struct` - -```rust,ignore -pub struct Config { - pub color: Color, - pub size: Size, - pub shape: Shape, -} -``` - -provide a constructor if there are sensible defaults: - -```rust,ignore -impl Config { - pub fn new() -> Config { - Config { - color: Brown, - size: Medium, - shape: Square, - } - } -} -``` - -which then allows clients to concisely override using `struct` update syntax: - -```rust,ignore -Config { color: Red, .. Config::new() }; -``` - -See the [guideline for field privacy](../features/types/README.md) for -discussion on when to create such "passive" `struct`s with public -fields. diff --git a/src/doc/style/ownership/destructors.md b/src/doc/style/ownership/destructors.md deleted file mode 100644 index 1cfcd78d20da8..0000000000000 --- a/src/doc/style/ownership/destructors.md +++ /dev/null @@ -1,22 +0,0 @@ -% Destructors - -Unlike constructors, destructors in Rust have a special status: they are added -by implementing `Drop` for a type, and they are automatically invoked as values -go out of scope. - -> **[FIXME]** This section needs to be expanded. - -### Destructors should not fail. [FIXME: needs RFC] - -Destructors are executed on thread failure, and in that context a failing -destructor causes the program to abort. - -Instead of failing in a destructor, provide a separate method for checking for -clean teardown, e.g. a `close` method, that returns a `Result` to signal -problems. - -### Destructors should not block. [FIXME: needs RFC] - -Similarly, destructors should not invoke blocking operations, which can make -debugging much more difficult. Again, consider providing a separate method for -preparing for an infallible, nonblocking teardown. diff --git a/src/doc/style/ownership/raii.md b/src/doc/style/ownership/raii.md deleted file mode 100644 index 244e8096a1a2f..0000000000000 --- a/src/doc/style/ownership/raii.md +++ /dev/null @@ -1,12 +0,0 @@ -% RAII - -Resource Acquisition is Initialization - -> **[FIXME]** Explain the RAII pattern and give best practices. - -### Whenever possible, tie resource access to guard scopes [FIXME] - -> **[FIXME]** Example: Mutex guards guarantee that access to the -> protected resource only happens when the guard is in scope. - -`must_use` diff --git a/src/doc/style/platform.md b/src/doc/style/platform.md deleted file mode 100644 index d29d060b69461..0000000000000 --- a/src/doc/style/platform.md +++ /dev/null @@ -1,7 +0,0 @@ -% FFI and platform-specific code **[FIXME]** - -> **[FIXME]** Not sure where this should live. - -When writing cross-platform code, group platform-specific code into a -module called `platform`. Avoid `#[cfg]` directives outside this -`platform` module. diff --git a/src/doc/style/safety/README.md b/src/doc/style/safety/README.md deleted file mode 100644 index 1ac6e704d23eb..0000000000000 --- a/src/doc/style/safety/README.md +++ /dev/null @@ -1,19 +0,0 @@ -% Safety and guarantees - -> **[FIXME]** Is there a better phrase than "strong guarantees" that encompasses -> both e.g. memory safety and e.g. data structure invariants? - -A _guarantee_ is a property that holds no matter what client code does, unless -the client explicitly opts out: - -* Rust guarantees memory safety and data-race freedom, with `unsafe` - blocks as an opt-out mechanism. - -* APIs in Rust often provide their own guarantees. For example, `std::str` -guarantees that its underlying buffer is valid utf-8. The `std::path::Path` type -guarantees no interior nulls. Both strings and paths provide `unsafe` mechanisms -for opting out of these guarantees (and thereby avoiding runtime checks). - -Thinking about guarantees is an essential part of writing good Rust code. The -rest of this subsection outlines some cross-cutting principles around -guarantees. diff --git a/src/doc/style/safety/lib-guarantees.md b/src/doc/style/safety/lib-guarantees.md deleted file mode 100644 index 8ee64f1806a69..0000000000000 --- a/src/doc/style/safety/lib-guarantees.md +++ /dev/null @@ -1,81 +0,0 @@ -% Library-level guarantees - -Most libraries rely on internal invariants, e.g. about their data, resource -ownership, or protocol states. In Rust, broken invariants cannot produce -segfaults, but they can still lead to wrong answers. - -### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]** - -Library-level invariants should be turned into guarantees whenever -practical. They should hold no matter what the client does, modulo -explicit opt-outs. Depending on the kind of invariant, this can be -achieved through a combination of static and dynamic enforcement, as -described below. - -#### Static enforcement: - -Guaranteeing invariants almost always requires _hiding_, -i.e. preventing the client from directly accessing or modifying -internal data. - -For example, the representation of the `str` type is hidden, -which means that any value of type `str` must have been produced -through an API under the control of the `str` module, and these -APIs in turn ensure valid utf-8 encoding. - -Rust's type system makes it possible to provide guarantees even while -revealing more of the representation than usual. For example, the -`as_bytes()` method on `&str` gives a _read-only_ view into the -underlying buffer, which cannot be used to violate the utf-8 property. - -#### Dynamic enforcement: - -Malformed inputs from the client are hazards to library-level -guarantees, so library APIs should validate their input. - -For example, `std::str::from_utf8_owned` attempts to convert a `u8` -slice into an owned string, but dynamically checks that the slice is -valid utf-8 and returns `Err` if not. - -See -[the discussion on input validation](../features/functions-and-methods/input.md) -for more detail. - - -### Prefer static enforcement of guarantees. **[FIXME: needs RFC]** - -Static enforcement provides two strong benefits over dynamic enforcement: - -* Bugs are caught at compile time. -* There is no runtime cost. - -Sometimes purely static enforcement is impossible or impractical. In these -cases, a library should check as much as possible statically, but defer to -dynamic checks where needed. - -For example, the `std::string` module exports a `String` type with the guarantee -that all instances are valid utf-8: - -* Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example, - the `append` method can push a `&str` onto the end of a `String` without - checking anything dynamically, since the existing `String` and `&str` are - statically guaranteed to be in utf-8. - -* Some _producers_ of a `String` must perform dynamic checks. For example, the - `from_utf8` function attempts to convert a `Vec` into a `String`, but - dynamically checks that the contents are utf-8. - -### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]** - -Providing library-level guarantees sometimes entails inconvenience (for static -checks) or overhead (for dynamic checks). So it is sometimes desirable to allow -clients to sidestep this checking, while promising to use the API in a way that -still provides the guarantee. Such escape hatches should only be introduced when -there is a demonstrated need for them. - -It should be trivial for clients to audit their use of the library for -escape hatches. - -See -[the discussion on input validation](../features/functions-and-methods/input.md) -for conventions on marking opt-out functions. diff --git a/src/doc/style/safety/unsafe.md b/src/doc/style/safety/unsafe.md deleted file mode 100644 index a8a50af044c29..0000000000000 --- a/src/doc/style/safety/unsafe.md +++ /dev/null @@ -1,22 +0,0 @@ -% Using `unsafe` - -### Unconditionally guarantee safety, or mark API as `unsafe`. **[FIXME: needs RFC]** - -Memory safety, type safety, and data race freedom are basic assumptions for all -Rust code. - -APIs that use `unsafe` blocks internally thus have two choices: - -* They can guarantee safety _unconditionally_ (i.e., regardless of client - behavior or inputs) and be exported as safe code. Any safety violation is then - the library's fault, not the client's fault. - -* They can export potentially unsafe functions with the `unsafe` qualifier. In - this case, the documentation should make very clear the conditions under which - safety is guaranteed. - -The result is that a client program can never violate safety merely by having a -bug; it must have explicitly opted out by using an `unsafe` block. - -Of the two options for using `unsafe`, creating such safe abstractions (the -first option above) is strongly preferred. diff --git a/src/doc/style/style/README.md b/src/doc/style/style/README.md deleted file mode 100644 index 87449710543c0..0000000000000 --- a/src/doc/style/style/README.md +++ /dev/null @@ -1,5 +0,0 @@ -% Style - -This section gives a set of strict rules for styling Rust code. - -> **[FIXME]** General remarks about the style guidelines diff --git a/src/doc/style/style/braces.md b/src/doc/style/style/braces.md deleted file mode 100644 index 80323dba1d4c2..0000000000000 --- a/src/doc/style/style/braces.md +++ /dev/null @@ -1,77 +0,0 @@ -% Braces, semicolons, and commas [FIXME: needs RFC] - -### Opening braces always go on the same line. - -```rust,ignore -fn foo() { - ... -} - -fn frobnicate(a: Bar, b: Bar, - c: Bar, d: Bar) - -> Bar { - ... -} - -trait Bar { - fn baz(&self); -} - -impl Bar for Baz { - fn baz(&self) { - ... - } -} - -frob(|x| { - x.transpose() -}) -``` - -### `match` arms get braces, except for single-line expressions. - -```rust,ignore -match foo { - bar => baz, - quux => { - do_something(); - do_something_else() - } -} -``` - -### `return` statements get semicolons. - -```rust,ignore -fn foo() { - do_something(); - - if condition() { - return; - } - - do_something_else(); -} -``` - -### Trailing commas - -> **[FIXME]** We should have a guideline for when to include trailing -> commas in `struct`s, `match`es, function calls, etc. -> -> One possible rule: a trailing comma should be included whenever the -> closing delimiter appears on a separate line: - -```rust,ignore -Foo { bar: 0, baz: 1 } - -Foo { - bar: 0, - baz: 1, -} - -match a_thing { - None => 0, - Some(x) => 1, -} -``` diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md deleted file mode 100644 index af02d87cc8da8..0000000000000 --- a/src/doc/style/style/comments.md +++ /dev/null @@ -1,122 +0,0 @@ -% Comments [RFC #505] - -### Avoid block comments. - -Use line comments: - -```rust -// Wait for the main thread to return, and set the process error code -// appropriately. -``` - -Instead of: - -``` rust -/* - * Wait for the main thread to return, and set the process error code - * appropriately. - */ -``` - -## Doc comments - -Doc comments are prefixed by three slashes (`///`) and indicate -documentation that you would like to be included in Rustdoc's output. -They support -[Markdown syntax](https://en.wikipedia.org/wiki/Markdown) -and are the main way of documenting your public APIs. - -The supported markdown syntax includes all of the extensions listed in the -[GitHub Flavored Markdown] -(https://help.github.com/articles/github-flavored-markdown) documentation, -plus superscripts. - -### Summary line - -The first line in any doc comment should be a single-line short sentence -providing a summary of the code. This line is used as a short summary -description throughout Rustdoc's output, so it's a good idea to keep it -short. - -### Sentence structure - -All doc comments, including the summary line, should begin with a -capital letter and end with a period, question mark, or exclamation -point. Prefer full sentences to fragments. - -The summary line should be written in -[third person singular present indicative form] -(http://en.wikipedia.org/wiki/English_verbs#Third_person_singular_present). -Basically, this means write "Returns" instead of "Return". - -For example: - -```rust,ignore -/// Sets up a default runtime configuration, given compiler-supplied arguments. -/// -/// This function will block until the entire pool of M:N schedulers has -/// exited. This function also requires a local thread to be available. -/// -/// # Arguments -/// -/// * `argc` & `argv` - The argument vector. On Unix this information is used -/// by `os::args`. -/// * `main` - The initial procedure to run inside of the M:N scheduling pool. -/// Once this procedure exits, the scheduling pool will begin to shut -/// down. The entire pool (and this function) will only return once -/// all child threads have finished executing. -/// -/// # Return value -/// -/// The return value is used as the process return code. 0 on success, 101 on -/// error. -``` - -### Code snippets - -Only use inner doc comments `//!` to write crate and module-level documentation, -nothing else. When using `mod` blocks, prefer `///` outside of the block: - -```rust -/// This module contains tests -mod test { - // ... -} -``` - -over - -```rust -mod test { - //! This module contains tests - - // ... -} -``` - -### Avoid inner doc comments. - -Use inner doc comments _only_ to document crates and file-level modules: - -```rust,ignore -//! The core library. -//! -//! The core library is a something something... -``` - -### Explain context. - -Rust doesn't have special constructors, only functions that return new -instances. These aren't visible in the automatically generated documentation -for a type, so you should specifically link to them: - -```rust,ignore -/// An iterator that yields `None` forever after the underlying iterator -/// yields `None` once. -/// -/// These can be created through -/// [`iter.fuse()`](trait.Iterator.html#method.fuse). -pub struct Fuse { - // ... -} -``` diff --git a/src/doc/style/style/features.md b/src/doc/style/style/features.md deleted file mode 100644 index 13cc37fc236ca..0000000000000 --- a/src/doc/style/style/features.md +++ /dev/null @@ -1,13 +0,0 @@ -## `return` [RFC #968] - -Terminate `return` statements with semicolons: - -``` rust,ignore -fn foo(bar: i32) -> Option { - if some_condition() { - return None; - } - - ... -} -``` diff --git a/src/doc/style/style/imports.md b/src/doc/style/style/imports.md deleted file mode 100644 index c958875ddb926..0000000000000 --- a/src/doc/style/style/imports.md +++ /dev/null @@ -1,50 +0,0 @@ -% Imports [FIXME: needs RFC] - -The imports of a crate/module should consist of the following -sections, in order, with a blank space between each: - -* `extern crate` directives -* external `use` imports -* local `use` imports -* `pub use` imports - -For example: - -```rust,ignore -// Crates. -extern crate getopts; -extern crate mylib; - -// Standard library imports. -use getopts::{optopt, getopts}; -use std::os; - -// Import from a library that we wrote. -use mylib::webserver; - -// Will be reexported when we import this module. -pub use self::types::Webdata; -``` - -### Avoid `use *`, except in tests. - -Glob imports have several downsides: -* They make it harder to tell where names are bound. -* They are forwards-incompatible, since new upstream exports can clash - with existing names. - -When writing a [`test` submodule](../testing/README.md), importing `super::*` is appropriate -as a convenience. - -### Prefer fully importing types/traits while module-qualifying functions. - -For example: - -```rust,ignore -use option::Option; -use mem; - -let i: isize = mem::transmute(Option(0)); -``` - -> **[FIXME]** Add rationale. diff --git a/src/doc/style/style/naming/README.md b/src/doc/style/style/naming/README.md deleted file mode 100644 index 6d88a838f5f53..0000000000000 --- a/src/doc/style/style/naming/README.md +++ /dev/null @@ -1,115 +0,0 @@ -% Naming conventions - -### General conventions [RFC #430] - -> The guidelines below were approved by [RFC #430](https://github.com/rust-lang/rfcs/pull/430). - -In general, Rust tends to use `CamelCase` for "type-level" constructs -(types and traits) and `snake_case` for "value-level" constructs. More -precisely: - -| Item | Convention | -| ---- | ---------- | -| Crates | `snake_case` (but prefer single word) | -| Modules | `snake_case` | -| Types | `CamelCase` | -| Traits | `CamelCase` | -| Enum variants | `CamelCase` | -| Functions | `snake_case` | -| Methods | `snake_case` | -| General constructors | `new` or `with_more_details` | -| Conversion constructors | `from_some_other_type` | -| Local variables | `snake_case` | -| Static variables | `SCREAMING_SNAKE_CASE` | -| Constant variables | `SCREAMING_SNAKE_CASE` | -| Type parameters | concise `CamelCase`, usually single uppercase letter: `T` | -| Lifetimes | short, lowercase: `'a` | - -

-In `CamelCase`, acronyms count as one word: use `Uuid` rather than -`UUID`. In `snake_case`, acronyms are lower-cased: `is_xid_start`. - -In `snake_case` or `SCREAMING_SNAKE_CASE`, a "word" should never -consist of a single letter unless it is the last "word". So, we have -`btree_map` rather than `b_tree_map`, but `PI_2` rather than `PI2`. - -### Referring to types in function/method names [RFC 344] - -> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344). - -Function names often involve type names, the most common example being conversions -like `as_slice`. If the type has a purely textual name (ignoring parameters), it -is straightforward to convert between type conventions and function conventions: - -Type name | Text in methods ---------- | --------------- -`String` | `string` -`Vec` | `vec` -`YourType`| `your_type` - -Types that involve notation follow the convention below. There is some -overlap on these rules; apply the most specific applicable rule: - -Type name | Text in methods ---------- | --------------- -`&str` | `str` -`&[T]` | `slice` -`&mut [T]`| `mut_slice` -`&[u8]` | `bytes` -`&T` | `ref` -`&mut T` | `mut` -`*const T`| `ptr` -`*mut T` | `mut_ptr` - -### Avoid redundant prefixes [RFC 356] - -> The guidelines below were approved by [RFC #356](https://github.com/rust-lang/rfcs/pull/356). - -Names of items within a module should not be prefixed with that module's name: - -Prefer - -```rust,ignore -mod foo { - pub struct Error { ... } -} -``` - -over - -```rust,ignore -mod foo { - pub struct FooError { ... } -} -``` - -This convention avoids stuttering (like `io::IoError`). Library clients can -rename on import to avoid clashes. - -### Getter/setter methods [RFC 344] - -> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344). - -Some data structures do not wish to provide direct access to their fields, but -instead offer "getter" and "setter" methods for manipulating the field state -(often providing checking or other functionality). - -The convention for a field `foo: T` is: - -* A method `foo(&self) -> &T` for getting the current value of the field. -* A method `set_foo(&self, val: T)` for setting the field. (The `val` argument - here may take `&T` or some other type, depending on the context.) - -Note that this convention is about getters/setters on ordinary data types, *not* -on [builder objects](../../ownership/builders.html). - -### Escape hatches [FIXME] - -> **[FIXME]** Should we standardize a convention for functions that may break API -> guarantees? e.g. `ToCStr::to_c_str_unchecked` - -### Predicates - -* Simple boolean predicates should be prefixed with `is_` or another - short question word, e.g., `is_empty`. -* Common exceptions: `lt`, `gt`, and other established predicate names. diff --git a/src/doc/style/style/naming/containers.md b/src/doc/style/style/naming/containers.md deleted file mode 100644 index c352a5b1bf191..0000000000000 --- a/src/doc/style/style/naming/containers.md +++ /dev/null @@ -1,69 +0,0 @@ -% Common container/wrapper methods [FIXME: needs RFC] - -Containers, wrappers, and cells all provide ways to access the data -they enclose. Accessor methods often have variants to access the data -by value, by reference, and by mutable reference. - -In general, the `get` family of methods is used to access contained -data without any risk of thread failure; they return `Option` as -appropriate. This name is chosen rather than names like `find` or -`lookup` because it is appropriate for a wider range of container types. - -#### Containers - -For a container with keys/indexes of type `K` and elements of type `V`: - -```rust,ignore -// Look up element without failing -fn get(&self, key: K) -> Option<&V> -fn get_mut(&mut self, key: K) -> Option<&mut V> - -// Convenience for .get(key).map(|elt| elt.clone()) -fn get_clone(&self, key: K) -> Option - -// Lookup element, failing if it is not found: -impl Index for Container { ... } -impl IndexMut for Container { ... } -``` - -#### Wrappers/Cells - -Prefer specific conversion functions like `as_bytes` or `into_vec` whenever -possible. Otherwise, use: - -```rust,ignore -// Extract contents without failing -fn get(&self) -> &V -fn get_mut(&mut self) -> &mut V -fn unwrap(self) -> V -``` - -#### Wrappers/Cells around `Copy` data - -```rust,ignore -// Extract contents without failing -fn get(&self) -> V -``` - -#### `Option`-like types - -Finally, we have the cases of types like `Option` and `Result`, which -play a special role for failure. - -For `Option`: - -```rust,ignore -// Extract contents or fail if not available -fn assert(self) -> V -fn expect(self, &str) -> V -``` - -For `Result`: - -```rust,ignore -// Extract the contents of Ok variant; fail if Err -fn assert(self) -> V - -// Extract the contents of Err variant; fail if Ok -fn assert_err(self) -> E -``` diff --git a/src/doc/style/style/naming/conversions.md b/src/doc/style/style/naming/conversions.md deleted file mode 100644 index 0287919c78aae..0000000000000 --- a/src/doc/style/style/naming/conversions.md +++ /dev/null @@ -1,32 +0,0 @@ -% Conversions [Rust issue #7087] - -> The guidelines below were approved by [rust issue #7087](https://github.com/rust-lang/rust/issues/7087). - -> **[FIXME]** Should we provide standard traits for conversions? Doing -> so nicely will require -> [trait reform](https://github.com/rust-lang/rfcs/pull/48) to land. - -Conversions should be provided as methods, with names prefixed as follows: - -| Prefix | Cost | Consumes convertee | -| ------ | ---- | ------------------ | -| `as_` | Free | No | -| `to_` | Expensive | No | -| `into_` | Variable | Yes | - -

-For example: - -* `as_bytes()` gives a `&[u8]` view into a `&str`, which is a no-op. -* `to_owned()` copies a `&str` to a new `String`. -* `into_bytes()` consumes a `String` and yields the underlying - `Vec`, which is a no-op. - -Conversions prefixed `as_` and `into_` typically _decrease abstraction_, either -exposing a view into the underlying representation (`as`) or deconstructing data -into its underlying representation (`into`). Conversions prefixed `to_`, on the -other hand, typically stay at the same level of abstraction but do some work to -change one representation into another. - -> **[FIXME]** The distinctions between conversion methods does not work -> so well for `from_` conversion constructors. Is that a problem? diff --git a/src/doc/style/style/naming/iterators.md b/src/doc/style/style/naming/iterators.md deleted file mode 100644 index 945cbe4800cb0..0000000000000 --- a/src/doc/style/style/naming/iterators.md +++ /dev/null @@ -1,32 +0,0 @@ -% Iterators - -#### Method names [RFC #199] - -> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199). - -For a container with elements of type `U`, iterator methods should be named: - -```rust,ignore -fn iter(&self) -> T // where T implements Iterator<&U> -fn iter_mut(&mut self) -> T // where T implements Iterator<&mut U> -fn into_iter(self) -> T // where T implements Iterator -``` - -The default iterator variant yields shared references `&U`. - -#### Type names [RFC #344] - -> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344). - -The name of an iterator type should be the same as the method that -produces the iterator. - -For example: - -* `iter` should yield an `Iter` -* `iter_mut` should yield an `IterMut` -* `into_iter` should yield an `IntoIter` -* `keys` should yield `Keys` - -These type names make the most sense when prefixed with their owning module, -e.g. `vec::IntoIter`. diff --git a/src/doc/style/style/naming/ownership.md b/src/doc/style/style/naming/ownership.md deleted file mode 100644 index 32cd8a1595afb..0000000000000 --- a/src/doc/style/style/naming/ownership.md +++ /dev/null @@ -1,34 +0,0 @@ -% Ownership variants [RFC #199] - -> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199). - -Functions often come in multiple variants: immutably borrowed, mutably -borrowed, and owned. - -The right default depends on the function in question. Variants should -be marked through suffixes. - -#### Immutably borrowed by default - -If `foo` uses/produces an immutable borrow by default, use: - -* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant. -* The `_move` suffix (e.g. `foo_move`) for the owned variant. - -#### Owned by default - -If `foo` uses/produces owned data by default, use: - -* The `_ref` suffix (e.g. `foo_ref`) for the immutably borrowed variant. -* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant. - -#### Exceptions - -In the case of iterators, the moving variant can also be understood as -an `into` conversion, `into_iter`, and `for x in v.into_iter()` reads -arguably better than `for x in v.iter_move()`, so the convention is -`into_iter`. - -For mutably borrowed variants, if the `mut` qualifier is part of a -type name (e.g. `as_mut_slice`), it should appear as it would appear -in the type. diff --git a/src/doc/style/style/optional.md b/src/doc/style/style/optional.md deleted file mode 100644 index d3c2178cc993f..0000000000000 --- a/src/doc/style/style/optional.md +++ /dev/null @@ -1,3 +0,0 @@ -* - -* diff --git a/src/doc/style/style/organization.md b/src/doc/style/style/organization.md deleted file mode 100644 index 85065406d761c..0000000000000 --- a/src/doc/style/style/organization.md +++ /dev/null @@ -1,14 +0,0 @@ -% Organization [FIXME: needs RFC] - -> **[FIXME]** What else? - -### Reexport the most important types at the crate level. - -Crates `pub use` the most common types for convenience, so that clients do not -have to remember or write the crate's module hierarchy to use these types. - -### Define types and operations together. - -Type definitions and the functions/methods that operate on them should be -defined together in a single module, with the type appearing above the -functions/methods. diff --git a/src/doc/style/style/whitespace.md b/src/doc/style/style/whitespace.md deleted file mode 100644 index c33c17c8e42a2..0000000000000 --- a/src/doc/style/style/whitespace.md +++ /dev/null @@ -1,133 +0,0 @@ -% Whitespace [FIXME: needs RFC] - -* Lines must not exceed 99 characters. -* Use 4 spaces for indentation, _not_ tabs. -* No trailing whitespace at the end of lines or files. - -### Spaces - -* Use spaces around binary operators, including the equals sign in attributes: - -```rust,ignore -#[deprecated = "Use `bar` instead."] -fn foo(a: usize, b: usize) -> usize { - a + b -} -``` - -* Use a space after colons and commas: - -```rust,ignore -fn foo(a: Bar); - -MyStruct { foo: 3, bar: 4 } - -foo(bar, baz); -``` - -* Use a space after the opening and before the closing brace for - single line blocks or `struct` expressions: - -```rust,ignore -spawn(proc() { do_something(); }) - -Point { x: 0.1, y: 0.3 } -``` - -### Line wrapping - -* For multiline function signatures, each new line should align with the - first parameter. Multiple parameters per line are permitted: - -```rust,ignore -fn frobnicate(a: Bar, b: Bar, - c: Bar, d: Bar) - -> Bar { - ... -} - -fn foo( - a: Bar, - b: Bar) - -> Baz { - ... -} -``` - -* Multiline function invocations generally follow the same rule as for - signatures. However, if the final argument begins a new block, the - contents of the block may begin on a new line, indented one level: - -```rust,ignore -fn foo_bar(a: Bar, b: Bar, - c: |Bar|) -> Bar { - ... -} - -// Same line is fine: -foo_bar(x, y, |z| { z.transpose(y) }); - -// Indented body on new line is also fine: -foo_bar(x, y, |z| { - z.quux(); - z.rotate(x) -}) -``` - -> **[FIXME]** Do we also want to allow the following? -> -> ```rust,ignore -> frobnicate( -> arg1, -> arg2, -> arg3) -> ``` -> -> This style could ease the conflict between line length and functions -> with many parameters (or long method chains). - -### Matches - -> * **[Deprecated]** If you have multiple patterns in a single `match` -> arm, write each pattern on a separate line: -> -> ```rust,ignore -> match foo { -> bar(_) -> | baz => quux, -> x -> | y -> | z => { -> quuux -> } -> } -> ``` - -### Alignment - -Idiomatic code should not use extra whitespace in the middle of a line -to provide alignment. - - -```rust,ignore -// Good -struct Foo { - short: f64, - really_long: f64, -} - -// Bad -struct Bar { - short: f64, - really_long: f64, -} - -// Good -let a = 0; -let radius = 7; - -// Bad -let b = 0; -let diameter = 7; -``` diff --git a/src/doc/style/testing/README.md b/src/doc/style/testing/README.md deleted file mode 100644 index a21f69414d326..0000000000000 --- a/src/doc/style/testing/README.md +++ /dev/null @@ -1,5 +0,0 @@ -% Testing - -> **[FIXME]** Add some general remarks about when and how to unit -> test, versus other kinds of testing. What are our expectations for -> Rust's core libraries? diff --git a/src/doc/style/testing/unit.md b/src/doc/style/testing/unit.md deleted file mode 100644 index dbbe9fc3ac6da..0000000000000 --- a/src/doc/style/testing/unit.md +++ /dev/null @@ -1,30 +0,0 @@ -% Unit testing - -Unit tests should live in a `tests` submodule at the bottom of the module they -test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when -testing. - -The `tests` module should contain: - -* Imports needed only for testing. -* Functions marked with `#[test]` striving for full coverage of the parent module's - definitions. -* Auxiliary functions needed for writing the tests. - -For example: - -``` rust -// Excerpt from std::str - -#[cfg(test)] -mod tests { - #[test] - fn test_eq() { - assert!((eq(&"".to_owned(), &"".to_owned()))); - assert!((eq(&"foo".to_owned(), &"foo".to_owned()))); - assert!((!eq(&"foo".to_owned(), &"bar".to_owned()))); - } -} -``` - -> **[FIXME]** add details about useful macros for testing, e.g. `assert!` diff --git a/src/doc/style/todo.md b/src/doc/style/todo.md deleted file mode 100644 index 28ef2a1832d8b..0000000000000 --- a/src/doc/style/todo.md +++ /dev/null @@ -1,5 +0,0 @@ -* [Containers and iteration]() -* [The visitor pattern]() -* [Concurrency]() -* [Documentation]() -* [Macros]() From 57719e2d73acdda337d1f68640ab551226cbe404 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 25 Aug 2016 15:20:31 -0400 Subject: [PATCH 278/768] Also remove build steps for style --- mk/docs.mk | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mk/docs.mk b/mk/docs.mk index f202c75360bf8..6c0be654e1f5d 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -66,7 +66,7 @@ ERR_IDX_GEN_MD = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE) D := $(S)src/doc -DOC_TARGETS := book nomicon style error-index +DOC_TARGETS := book nomicon error-index COMPILER_DOC_TARGETS := DOC_L10N_TARGETS := @@ -209,13 +209,6 @@ doc/nomicon/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/nomicon/*.md) | $(Q)rm -rf doc/nomicon $(Q)$(RUSTBOOK) build $(S)src/doc/nomicon doc/nomicon -style: doc/style/index.html - -doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/ - @$(call E, rustbook: $@) - $(Q)rm -rf doc/style - $(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style - error-index: doc/error-index.html # Metadata used to generate the index is created as a side effect of From cf8e1fee1619b29fb1d9a355f28a9f992426dd5a Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 25 Aug 2016 16:20:21 -0400 Subject: [PATCH 279/768] add a simple example for `thread::current()` --- src/libstd/thread/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index f06c105d30e65..42260cf195ffa 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -322,6 +322,24 @@ pub fn spawn(f: F) -> JoinHandle where } /// Gets a handle to the thread that invokes it. +/// +/// #Examples +/// +/// Getting a handle to the current thread with `thread::current()`: +/// +/// ``` +/// use std::thread; +/// +/// let handler = thread::Builder::new() +/// .name("named thread".into()) +/// .spawn(|| { +/// let handle = thread::current(); +/// assert_eq!(handle.name(), Some("named thread")); +/// }) +/// .unwrap(); +/// +/// handler.join().unwrap(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn current() -> Thread { thread_info::current_thread().expect("use of std::thread::current() is not \ From 8250a26b5bcea9190ac63e756c35d8a54bf9da0c Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 19 Aug 2016 18:58:14 -0700 Subject: [PATCH 280/768] Implement RFC#1559: allow all literals in attributes. --- src/librustc/hir/check_attr.rs | 19 +- src/librustc/hir/fold.rs | 23 +- src/librustc/lint/context.rs | 12 +- src/librustc_borrowck/borrowck/mir/mod.rs | 7 +- src/librustc_driver/lib.rs | 12 +- src/librustc_incremental/assert_dep_graph.rs | 39 ++- .../persist/dirty_clean.rs | 16 +- src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/unused.rs | 7 + src/librustc_metadata/common.rs | 15 +- src/librustc_metadata/creader.rs | 3 +- src/librustc_metadata/decoder.rs | 51 +-- src/librustc_metadata/encoder.rs | 37 +- src/librustc_metadata/macro_import.rs | 11 +- src/librustc_plugin/load.rs | 20 +- src/librustc_plugin/registry.rs | 5 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustdoc/clean/mod.rs | 56 ++- src/librustdoc/test.rs | 3 +- src/librustdoc/visit_ast.rs | 6 +- src/libsyntax/ast.rs | 58 ++- src/libsyntax/attr.rs | 330 ++++++++++++------ src/libsyntax/config.rs | 37 +- src/libsyntax/diagnostic_list.rs | 18 + src/libsyntax/ext/build.rs | 13 +- src/libsyntax/feature_gate.rs | 51 ++- src/libsyntax/fold.rs | 19 +- src/libsyntax/parse/attr.rs | 64 +++- src/libsyntax/print/pprust.rs | 19 +- src/libsyntax/test.rs | 9 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/libsyntax_ext/deriving/mod.rs | 6 +- .../auxiliary/macro_crate_test.rs | 17 +- src/test/compile-fail/E0565-1.rs | 17 + src/test/compile-fail/E0565.rs | 17 + src/test/compile-fail/attr-literals.rs | 33 ++ src/test/compile-fail/gated-attr-literals.rs | 44 +++ src/test/parse-fail/suffixed-literal-meta.rs | 25 ++ .../attr-literals.rs} | 16 +- .../auxiliary/custom_derive_plugin.rs | 1 - .../auxiliary/custom_derive_plugin_attr.rs | 2 +- .../auxiliary/macro_crate_test.rs | 103 +++++- .../auxiliary/plugin_args.rs | 4 +- .../macro-crate-multi-decorator-literals.rs | 58 +++ 45 files changed, 942 insertions(+), 373 deletions(-) create mode 100644 src/test/compile-fail/E0565-1.rs create mode 100644 src/test/compile-fail/E0565.rs create mode 100644 src/test/compile-fail/attr-literals.rs create mode 100644 src/test/compile-fail/gated-attr-literals.rs create mode 100644 src/test/parse-fail/suffixed-literal-meta.rs rename src/test/{parse-fail/non-str-meta.rs => pretty/attr-literals.rs} (66%) create mode 100644 src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index a1c04dfcab5e6..350b9fd88f6e7 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -11,7 +11,7 @@ use session::Session; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::visit; use syntax::visit::Visitor; @@ -52,18 +52,22 @@ impl<'a> CheckAttrVisitor<'a> { return; } }; + for word in words { - let word: &str = &word.name(); - let message = match word { + let name = match word.name() { + Some(word) => word, + None => continue, + }; + + let message = match &*name { "C" => { if target != Target::Struct && target != Target::Enum { - "attribute should be applied to struct or enum" + "attribute should be applied to struct or enum" } else { continue } } - "packed" | - "simd" => { + "packed" | "simd" => { if target != Target::Struct { "attribute should be applied to struct" } else { @@ -74,13 +78,14 @@ impl<'a> CheckAttrVisitor<'a> { "i32" | "u32" | "i64" | "u64" | "isize" | "usize" => { if target != Target::Enum { - "attribute should be applied to enum" + "attribute should be applied to enum" } else { continue } } _ => continue, }; + span_err!(self.sess, attr.span, E0517, "{}", message); } } diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 0edfd16bdfd1b..99bd22cc87b19 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -12,8 +12,8 @@ //! and returns a piece of the same type. use hir::*; -use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem}; -use syntax::ast::MetaItemKind; +use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_}; +use syntax::ast::{NestedMetaItem, NestedMetaItemKind, MetaItem, MetaItemKind}; use hir; use syntax_pos::Span; use syntax::codemap::{respan, Spanned}; @@ -38,6 +38,10 @@ pub trait Folder : Sized { noop_fold_meta_items(meta_items, self) } + fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem { + noop_fold_meta_list_item(list_item, self) + } + fn fold_meta_item(&mut self, meta_item: P) -> P { noop_fold_meta_item(meta_item, self) } @@ -486,13 +490,26 @@ pub fn noop_fold_attribute(at: Attribute, fld: &mut T) -> Option(li: NestedMetaItem, fld: &mut T) + -> NestedMetaItem { + Spanned { + node: match li.node { + NestedMetaItemKind::MetaItem(mi) => { + NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi)) + }, + NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit) + }, + span: fld.new_span(li.span) + } +} + pub fn noop_fold_meta_item(mi: P, fld: &mut T) -> P { mi.map(|Spanned { node, span }| { Spanned { node: match node { MetaItemKind::Word(id) => MetaItemKind::Word(id), MetaItemKind::List(id, mis) => { - MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e))) + MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e))) } MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s), }, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 29bcc1257fd31..bccd217352b70 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::parse::token::InternedString; use syntax::ast; use syntax_pos::Span; @@ -372,12 +372,10 @@ pub fn gather_attr(attr: &ast::Attribute) return out; }; - for meta in metas { - out.push(if meta.is_word() { - Ok((meta.name().clone(), level, meta.span)) - } else { - Err(meta.span) - }); + for li in metas { + out.push(li.word().map_or(Err(li.span), |word| { + Ok((word.name().clone(), level, word.span)) + })); } out diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index dbee0ea9b00e9..55c6a4de9df50 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -11,7 +11,7 @@ use borrowck::BorrowckCtxt; use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; @@ -43,8 +43,9 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option return Some(mi.clone()), + _ => continue } } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4e87c931cc19d..1f3f823d0b8ab 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -655,17 +655,19 @@ impl RustcDefaultCalls { if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() { continue; } + if cfg.is_word() { println!("{}", cfg.name()); - } else if cfg.is_value_str() { - if let Some(s) = cfg.value_str() { - println!("{}=\"{}\"", cfg.name(), s); - } + } else if let Some(s) = cfg.value_str() { + println!("{}=\"{}\"", cfg.name(), s); } else if cfg.is_meta_item_list() { // Right now there are not and should not be any // MetaItemKind::List items in the configuration returned by // `build_configuration`. - panic!("MetaItemKind::List encountered in default cfg") + panic!("Found an unexpected list in cfg attribute '{}'!", cfg.name()) + } else { + // There also shouldn't be literals. + panic!("Found an unexpected literal in cfg attribute '{}'!", cfg.name()) } } } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 420c88e89be0d..482b351481c4e 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -56,7 +56,7 @@ use std::env; use std::fs::File; use std::io::Write; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::parse::token::InternedString; use syntax_pos::Span; @@ -116,14 +116,18 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { for attr in self.tcx.get_attrs(def_id).iter() { if attr.check_name(IF_THIS_CHANGED) { let mut id = None; - for meta_item in attr.meta_item_list().unwrap_or_default() { - if meta_item.is_word() && id.is_none() { - id = Some(meta_item.name().clone()); - } else { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) + for list_item in attr.meta_item_list().unwrap_or_default() { + match list_item.word() { + Some(word) if id.is_none() => { + id = Some(word.name().clone()) + }, + _ => { + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node) + } } } + let id = id.unwrap_or(InternedString::new(ID)); self.if_this_changed.entry(id) .or_insert(FnvHashSet()) @@ -131,16 +135,21 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { } else if attr.check_name(THEN_THIS_WOULD_NEED) { let mut dep_node_interned = None; let mut id = None; - for meta_item in attr.meta_item_list().unwrap_or_default() { - if meta_item.is_word() && dep_node_interned.is_none() { - dep_node_interned = Some(meta_item.name().clone()); - } else if meta_item.is_word() && id.is_none() { - id = Some(meta_item.name().clone()); - } else { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) + for list_item in attr.meta_item_list().unwrap_or_default() { + match list_item.word() { + Some(word) if dep_node_interned.is_none() => { + dep_node_interned = Some(word.name().clone()); + }, + Some(word) if id.is_none() => { + id = Some(word.name().clone()) + }, + _ => { + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node) + } } } + let dep_node = match dep_node_interned { Some(ref n) => { match DepNode::from_label_string(&n[..], def_id) { diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 65da3a09ecca5..f0092ce04d1f6 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -31,8 +31,8 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use rustc_data_structures::fnv::FnvHashSet; -use syntax::ast::{self, Attribute, MetaItem}; -use syntax::attr::AttrMetaMethods; +use syntax::ast::{self, Attribute, NestedMetaItem}; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::parse::token::InternedString; use rustc::ty::TyCtxt; @@ -71,13 +71,17 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> { } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - fn expect_associated_value(&self, item: &MetaItem) -> InternedString { + fn expect_associated_value(&self, item: &NestedMetaItem) -> InternedString { if let Some(value) = item.value_str() { value } else { - self.tcx.sess.span_fatal( - item.span, - &format!("associated value expected for `{}`", item.name())); + let msg = if let Some(name) = item.name() { + format!("associated value expected for `{}`", name) + } else { + "expected an associated value".to_string() + }; + + self.tcx.sess.span_fatal(item.span, &msg); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b4a2648b5dca7..9a4eec2d05b7a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,8 +44,8 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; -use syntax_pos::Span; +use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods, AttributeMethods}; +use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::FnKind; @@ -317,7 +317,7 @@ impl LateLintPass for MissingDoc { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { attr.check_name("doc") && match attr.meta_item_list() { None => false, - Some(l) => attr::contains_name(&l[..], "hidden"), + Some(l) => attr::list_contains_name(&l[..], "hidden"), } }); self.doc_hidden_stack.push(doc_hidden); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 57705301aab4e..44c2ffe45ccb4 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -234,10 +234,13 @@ impl LintPass for UnusedAttributes { impl LateLintPass for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { + debug!("checking attribute: {:?}", attr); + // Note that check_name() marks the attribute as used if it matches. for &(ref name, ty, _) in KNOWN_ATTRIBUTES { match ty { AttributeType::Whitelisted if attr.check_name(name) => { + debug!("{:?} is Whitelisted", name); break; }, _ => () @@ -247,11 +250,13 @@ impl LateLintPass for UnusedAttributes { let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); for &(ref name, ty) in plugin_attributes.iter() { if ty == AttributeType::Whitelisted && attr.check_name(&name) { + debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty); break; } } if !attr::is_used(attr) { + debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| { @@ -275,6 +280,8 @@ impl LateLintPass for UnusedAttributes { }; cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); } + } else { + debug!("Attr was used: {:?}", attr); } } } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 99a3f3b00c8b0..85cf41e42a273 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -45,26 +45,13 @@ pub const tag_items_closure_kind: usize = 0x2a; pub const tag_items_closure_ty: usize = 0x2b; pub const tag_def_key: usize = 0x2c; -// GAP 0x2d 0x2e +// GAP 0x2d 0x34 pub const tag_index: usize = 0x110; // top-level only pub const tag_xref_index: usize = 0x111; // top-level only pub const tag_xref_data: usize = 0x112; // top-level only - -pub const tag_meta_item_name_value: usize = 0x2f; - -pub const tag_meta_item_name: usize = 0x30; - -pub const tag_meta_item_value: usize = 0x31; - pub const tag_attributes: usize = 0x101; // top-level only -pub const tag_attribute: usize = 0x32; - -pub const tag_meta_item_word: usize = 0x33; - -pub const tag_meta_item_list: usize = 0x34; - // The list of crates that this crate depends on pub const tag_crate_deps: usize = 0x102; // top-level only diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 46469efea6bc8..4dc3d04c4a23b 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,8 +35,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap; use syntax::parse; -use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::parse::token::InternedString; use syntax::visit; use syntax_pos::{self, Span, mk_sp, Pos}; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b0335258b4041..b8ed1f7bae63b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -56,7 +56,6 @@ use syntax::parse::token; use syntax::ast; use syntax::codemap; use syntax::print::pprust; -use syntax::ptr::P; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; pub type Cmd<'a> = &'a CrateMetadata; @@ -1121,44 +1120,20 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { })).collect() } -fn get_meta_items(md: rbml::Doc) -> Vec> { - reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str()); - attr::mk_word_item(n) - }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); - let n = token::intern_and_get_ident(nd.as_str()); - let v = token::intern_and_get_ident(vd.as_str()); - // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants, - // but currently the encoder just drops them - attr::mk_name_value_item_str(n, v) - })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str()); - let subitems = get_meta_items(meta_item_doc); - attr::mk_list_item(n, subitems) - })).collect() -} - fn get_attributes(md: rbml::Doc) -> Vec { - match reader::maybe_get_doc(md, tag_attributes) { - Some(attrs_d) => { - reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| { - let is_sugared_doc = reader::doc_as_u8( - reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) - ) == 1; - let meta_items = get_meta_items(attr_doc); - // Currently it's only possible to have a single meta item on - // an attribute - assert_eq!(meta_items.len(), 1); - let meta_item = meta_items.into_iter().nth(0).unwrap(); - attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc) - }).collect() - }, - None => vec![], - } + reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| { + let mut decoder = reader::Decoder::new(attrs_doc); + let mut attrs: Vec = decoder.read_opaque(|opaque_decoder, _| { + Decodable::decode(opaque_decoder) + }).unwrap(); + + // Need new unique IDs: old thread-local IDs won't map to new threads. + for attr in attrs.iter_mut() { + attr.node.id = attr::mk_attr_id(); + } + + attrs + }) } fn list_crate_attributes(md: rbml::Doc, hash: &Svh, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 9a668b69b2eeb..ef8253713f5a1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -41,7 +41,7 @@ use std::io::{Cursor, SeekFrom}; use std::rc::Rc; use std::u32; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; -use syntax::attr::{self,AttrMetaMethods,AttributeMethods}; +use syntax::attr; use errors::Handler; use syntax; use syntax_pos::BytePos; @@ -1412,40 +1412,11 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { rbml_w.end_tag(); } -fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) { - if mi.is_word() { - let name = mi.name(); - rbml_w.start_tag(tag_meta_item_word); - rbml_w.wr_tagged_str(tag_meta_item_name, &name); - rbml_w.end_tag(); - } else if mi.is_value_str() { - let name = mi.name(); - /* FIXME (#623): support other literal kinds */ - let value = mi.value_str().unwrap(); - rbml_w.start_tag(tag_meta_item_name_value); - rbml_w.wr_tagged_str(tag_meta_item_name, &name); - rbml_w.wr_tagged_str(tag_meta_item_value, &value); - rbml_w.end_tag(); - } else { // it must be a list - let name = mi.name(); - let items = mi.meta_item_list().unwrap(); - rbml_w.start_tag(tag_meta_item_list); - rbml_w.wr_tagged_str(tag_meta_item_name, &name); - for inner_item in items { - encode_meta_item(rbml_w, &inner_item); - } - rbml_w.end_tag(); - } -} - fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { rbml_w.start_tag(tag_attributes); - for attr in attrs { - rbml_w.start_tag(tag_attribute); - rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); - encode_meta_item(rbml_w, attr.meta()); - rbml_w.end_tag(); - } + rbml_w.emit_opaque(|opaque_encoder| { + attrs.encode(opaque_encoder) + }).unwrap(); rbml_w.end_tag(); } diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index b2a2dcf90fa4b..ec0c9f455cd0c 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,8 +18,7 @@ use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; -use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{self, AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::ext; use syntax_pos::Span; @@ -64,8 +63,8 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { } if let (Some(sel), Some(names)) = (import.as_mut(), names) { for attr in names { - if attr.is_word() { - sel.insert(attr.name().clone(), attr.span()); + if let Some(word) = attr.word() { + sel.insert(word.name().clone(), attr.span()); } else { span_err!(self.sess, attr.span(), E0466, "bad macro import"); } @@ -82,8 +81,8 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { }; for attr in names { - if attr.is_word() { - reexport.insert(attr.name().clone(), attr.span()); + if let Some(word) = attr.word() { + reexport.insert(word.name().clone(), attr.span()); } else { call_bad_macro_reexport(self.sess, attr.span()); } diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index fb68eae96476f..5a8d2e58c558b 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,8 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::ptr::P; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax_pos::{Span, COMMAND_LINE_SP}; /// Pointer to a registrar function. @@ -30,7 +29,7 @@ pub type PluginRegistrarFun = pub struct PluginRegistrar { pub fun: PluginRegistrarFun, - pub args: Vec>, + pub args: Vec, } struct PluginLoader<'a> { @@ -69,13 +68,14 @@ pub fn load_plugins(sess: &Session, }; for plugin in plugins { - if plugin.value_str().is_some() { - call_malformed_plugin_attribute(sess, attr.span); - continue; + // plugins must have a name and can't be key = value + match plugin.name() { + Some(ref name) if !plugin.is_value_str() => { + let args = plugin.meta_item_list().map(ToOwned::to_owned); + loader.load_plugin(plugin.span, name, args.unwrap_or_default()); + }, + _ => call_malformed_plugin_attribute(sess, attr.span), } - - let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default(); - loader.load_plugin(plugin.span, &plugin.name(), args); } } } @@ -102,7 +102,7 @@ impl<'a> PluginLoader<'a> { } } - fn load_plugin(&mut self, span: Span, name: &str, args: Vec>) { + fn load_plugin(&mut self, span: Span, name: &str, args: Vec) { let registrar = self.reader.find_plugin_registrar(span, name); if let Some((lib, svh, index)) = registrar { diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 54fa0197de4fe..5ae6584aed425 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -19,7 +19,6 @@ use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator}; use syntax::ext::base::{MacroExpanderFn, MacroRulesTT}; use syntax::parse::token; -use syntax::ptr::P; use syntax::ast; use syntax::feature_gate::AttributeType; use syntax_pos::Span; @@ -41,7 +40,7 @@ pub struct Registry<'a> { pub sess: &'a Session, #[doc(hidden)] - pub args_hidden: Option>>, + pub args_hidden: Option>, #[doc(hidden)] pub krate_span: Span, @@ -95,7 +94,7 @@ impl<'a> Registry<'a> { /// /// Returns empty slice in case the plugin was loaded /// with `--extra-plugins` - pub fn args<'b>(&'b self) -> &'b [P] { + pub fn args<'b>(&'b self) -> &'b [ast::NestedMetaItem] { self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[]) } diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index e0532e7476f51..e2633c829761f 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,7 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::parse::token::InternedString; use {ModuleSource, ModuleTranslation}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2e655ce38bcc..02fa073dd5523 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,10 +26,11 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::{AttributeMethods, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::codemap::Spanned; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; +use syntax::print::pprust as syntax_pprust; use syntax_pos::{self, DUMMY_SP, Pos}; use rustc_trans::back::link; @@ -501,11 +502,24 @@ impl Attributes for [Attribute] { } } +/// This is a flattened version of the AST's Attribute + MetaItem. #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub enum Attribute { Word(String), List(String, Vec), - NameValue(String, String) + NameValue(String, String), + Literal(String), +} + +impl Clean for ast::NestedMetaItem { + fn clean(&self, cx: &DocContext) -> Attribute { + if let Some(mi) = self.meta_item() { + mi.clean(cx) + } else { // must be a literal + let lit = self.literal().unwrap(); + Literal(syntax_pprust::lit_to_string(lit)) + } + } } impl Clean for ast::MetaItem { @@ -528,12 +542,28 @@ impl Clean for ast::Attribute { } // This is a rough approximation that gets us what we want. -impl attr::AttrMetaMethods for Attribute { - fn name(&self) -> InternedString { +impl attr::AttrNestedMetaItemMethods for Attribute { + fn check_name(&self, name: &str) -> bool { + self.name().map_or(false, |mi_name| &*mi_name == name) + } + + fn literal(&self) -> Option<&ast::Lit> { None } + + fn is_literal(&self) -> bool { + match *self { + Literal(..) => true, + _ => false, + } + } + + fn meta_item(&self) -> Option<&P> { None } + + fn name(&self) -> Option { match *self { Word(ref n) | List(ref n, _) | NameValue(ref n, _) => { - token::intern_and_get_ident(n) - } + Some(token::intern_and_get_ident(n)) + }, + _ => None } } @@ -545,7 +575,8 @@ impl attr::AttrMetaMethods for Attribute { _ => None, } } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { None } + + fn word(&self) -> Option<&P> { None } fn is_word(&self) -> bool { match *self { @@ -554,12 +585,7 @@ impl attr::AttrMetaMethods for Attribute { } } - fn is_value_str(&self) -> bool { - match *self { - NameValue(..) => true, - _ => false, - } - } + fn meta_item_list<'a>(&'a self) -> Option<&'a [ast::NestedMetaItem]> { None } fn is_meta_item_list(&self) -> bool { match *self { @@ -2535,8 +2561,8 @@ impl Clean> for doctree::Import { // Don't inline doc(hidden) imports so they can be stripped at a later stage. let denied = self.vis != hir::Public || self.attrs.iter().any(|a| { &a.name()[..] == "doc" && match a.meta_item_list() { - Some(l) => attr::contains_name(l, "no_inline") || - attr::contains_name(l, "hidden"), + Some(l) => attr::list_contains_name(l, "no_inline") || + attr::list_contains_name(l, "hidden"), None => false, } }); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 7d1dbbe5dc07d..23a047f922f9d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -141,6 +141,7 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { use syntax::attr::AttrMetaMethods; + use syntax::attr::AttrNestedMetaItemMethods; use syntax::print::pprust; let mut opts = TestOptions { @@ -162,7 +163,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { if attr.check_name("attr") { if let Some(l) = attr.meta_item_list() { for item in l { - opts.attrs.push(pprust::meta_item_to_string(item)); + opts.attrs.push(pprust::meta_list_item_to_string(item)); } } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0334c5ef5c4f4..4e3a81b1baeac 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax_pos::Span; use rustc::hir::map as hir_map; @@ -333,8 +333,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let node = if item.vis == hir::Public { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(list) if &item.name()[..] == "doc" => { - list.iter().any(|i| &i.name()[..] == "inline") + Some(list) if item.check_name("doc") => { + list.iter().any(|i| i.check_name("inline")) } _ => false, } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..63fd2e7686fdf 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -439,6 +439,22 @@ pub struct Crate { pub exported_macros: Vec, } +/// A spanned compile-time attribute list item. +pub type NestedMetaItem = Spanned; + +/// Possible values inside of compile-time attribute lists. +/// +/// E.g. the '..' in `#[name(..)]`. +#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug, PartialEq)] +pub enum NestedMetaItemKind { + /// A full MetaItem, for recursive meta items. + MetaItem(P), + /// A literal. + /// + /// E.g. "foo", 64, true + Literal(Lit), +} + /// A spanned compile-time attribute item. /// /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` @@ -456,7 +472,7 @@ pub enum MetaItemKind { /// List meta item. /// /// E.g. `derive(..)` as in `#[derive(..)]` - List(InternedString, Vec>), + List(InternedString, Vec), /// Name value meta item. /// /// E.g. `feature = "foo"` as in `#[feature = "foo"]` @@ -472,19 +488,21 @@ impl PartialEq for MetaItemKind { Word(ref no) => (*ns) == (*no), _ => false }, + List(ref ns, ref miss) => match *other { + List(ref no, ref miso) => { + ns == no && + miss.iter().all(|mi| { + miso.iter().any(|x| x.node == mi.node) + }) + } + _ => false + }, NameValue(ref ns, ref vs) => match *other { NameValue(ref no, ref vo) => { (*ns) == (*no) && vs.node == vo.node } _ => false }, - List(ref ns, ref miss) => match *other { - List(ref no, ref miso) => { - ns == no && - miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node)) - } - _ => false - } } } } @@ -1105,6 +1123,30 @@ impl LitKind { _ => false, } } + + /// Returns true if this literal has no suffix. Note: this will return true + /// for literals with prefixes such as raw strings and byte strings. + pub fn is_unsuffixed(&self) -> bool { + match *self { + // unsuffixed variants + LitKind::Str(..) => true, + LitKind::ByteStr(..) => true, + LitKind::Byte(..) => true, + LitKind::Char(..) => true, + LitKind::Int(_, LitIntType::Unsuffixed) => true, + LitKind::FloatUnsuffixed(..) => true, + LitKind::Bool(..) => true, + // suffixed variants + LitKind::Int(_, LitIntType::Signed(..)) => false, + LitKind::Int(_, LitIntType::Unsigned(..)) => false, + LitKind::Float(..) => false, + } + } + + /// Returns true if this literal has a suffix. + pub fn is_suffixed(&self) -> bool { + !self.is_unsuffixed() + } } // NB: If you change this, you'll probably want to change the corresponding diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index b622f6861b383..4897425f2c06c 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -15,9 +15,10 @@ pub use self::ReprAttr::*; pub use self::IntType::*; use ast; -use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind}; -use ast::{Expr, Item, Local, Stmt, StmtKind}; -use codemap::{respan, spanned, dummy_spanned, Spanned}; +use ast::{AttrId, Attribute, Attribute_}; +use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; +use ast::{Lit, Expr, Item, Local, Stmt, StmtKind}; +use codemap::{respan, spanned, dummy_spanned}; use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; @@ -40,6 +41,7 @@ enum AttrError { MissingSince, MissingFeature, MultipleStabilityLevels, + UnsupportedLiteral } fn handle_errors(diag: &Handler, span: Span, error: AttrError) { @@ -52,10 +54,12 @@ fn handle_errors(diag: &Handler, span: Span, error: AttrError) { AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"), AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544, "multiple stability levels"), + AttrError::UnsupportedLiteral => span_err!(diag, span, E0565, "unsupported literal"), } } pub fn mark_used(attr: &Attribute) { + debug!("Marking {:?} as used.", attr); let AttrId(id) = attr.node.id; USED_ATTRS.with(|slot| { let idx = (id / 64) as usize; @@ -77,6 +81,93 @@ pub fn is_used(attr: &Attribute) -> bool { }) } +pub trait AttrNestedMetaItemMethods { + /// Returns true if this list item is a MetaItem with a name of `name`. + fn check_name(&self, name: &str) -> bool { + self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) + } + + /// Returns the name of the meta item, e.g. `foo` in `#[foo]`, + /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem + fn name(&self) -> Option { + self.meta_item().and_then(|meta_item| Some(meta_item.name())) + } + + /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. + fn meta_item(&self) -> Option<&P>; + + /// Returns the Lit if self is a NestedMetaItemKind::Literal. + fn literal(&self) -> Option<&Lit>; + + /// Gets the string value if self is a MetaItem and the MetaItem is a + /// MetaItemKind::NameValue variant containing a string, otherwise None. + fn value_str(&self) -> Option { + self.meta_item().and_then(|meta_item| meta_item.value_str()) + } + + /// Returns a MetaItem if self is a MetaItem with Kind Word. + fn word(&self) -> Option<&P> { + self.meta_item().and_then(|meta_item| if meta_item.is_word() { + Some(meta_item) + } else { + None + }) + } + + /// Gets a list of inner meta items from a list MetaItem type. + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) + } + + /// Returns `true` if the variant is MetaItem. + fn is_meta_item(&self) -> bool { + self.meta_item().is_some() + } + + /// Returns `true` if the variant is Literal. + fn is_literal(&self) -> bool { + self.literal().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a word. + fn is_word(&self) -> bool { + self.word().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a ValueString. + fn is_value_str(&self) -> bool { + self.value_str().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a list. + fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } + + /// Returns the Span for `self`. + fn span(&self) -> Span; +} + +impl AttrNestedMetaItemMethods for NestedMetaItem { + fn meta_item(&self) -> Option<&P> { + match self.node { + NestedMetaItemKind::MetaItem(ref item) => Some(&item), + _ => None + } + } + + fn literal(&self) -> Option<&Lit> { + match self.node { + NestedMetaItemKind::Literal(ref lit) => Some(&lit), + _ => None + } + } + + fn span(&self) -> Span { + self.span + } +} + pub trait AttrMetaMethods { fn check_name(&self, name: &str) -> bool { name == &self.name()[..] @@ -89,8 +180,9 @@ pub trait AttrMetaMethods { /// Gets the string value if self is a MetaItemKind::NameValue variant /// containing a string, otherwise None. fn value_str(&self) -> Option; + /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[P]>; + fn meta_item_list(&self) -> Option<&[NestedMetaItem]>; /// Indicates if the attribute is a Word. fn is_word(&self) -> bool; @@ -116,11 +208,14 @@ impl AttrMetaMethods for Attribute { } matches } + fn name(&self) -> InternedString { self.meta().name() } + fn value_str(&self) -> Option { self.meta().value_str() } - fn meta_item_list(&self) -> Option<&[P]> { + + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta().meta_item_list() } @@ -150,7 +245,7 @@ impl AttrMetaMethods for MetaItem { } } - fn meta_item_list(&self) -> Option<&[P]> { + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { match self.node { MetaItemKind::List(_, ref l) => Some(&l[..]), _ => None @@ -171,7 +266,7 @@ impl AttrMetaMethods for MetaItem { impl AttrMetaMethods for P { fn name(&self) -> InternedString { (**self).name() } fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[P]> { + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { (**self).meta_item_list() } fn is_word(&self) -> bool { (**self).is_word() } @@ -229,10 +324,14 @@ pub fn mk_name_value_item(name: InternedString, value: ast::Lit) mk_spanned_name_value_item(DUMMY_SP, name, value) } -pub fn mk_list_item(name: InternedString, items: Vec>) -> P { +pub fn mk_list_item(name: InternedString, items: Vec) -> P { mk_spanned_list_item(DUMMY_SP, name, items) } +pub fn mk_list_word_item(name: InternedString) -> ast::NestedMetaItem { + dummy_spanned(NestedMetaItemKind::MetaItem(mk_spanned_word_item(DUMMY_SP, name))) +} + pub fn mk_word_item(name: InternedString) -> P { mk_spanned_word_item(DUMMY_SP, name) } @@ -242,7 +341,7 @@ pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Li P(respan(sp, MetaItemKind::NameValue(name, value))) } -pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec>) +pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec) -> P { P(respan(sp, MetaItemKind::List(name, items))) } @@ -332,6 +431,14 @@ pub fn contains(haystack: &[P], needle: &MetaItem) -> bool { }) } +pub fn list_contains_name(items: &[AM], name: &str) -> bool { + debug!("attr::list_contains_name (name={})", name); + items.iter().any(|item| { + debug!(" testing: {:?}", item.name()); + item.check_name(name) + }) +} + pub fn contains_name(metas: &[AM], name: &str) -> bool { debug!("attr::contains_name (name={})", name); metas.iter().any(|item| { @@ -357,27 +464,6 @@ pub fn last_meta_item_value_str_by_name(items: &[P], name: &str) /* Higher-level applications */ -pub fn sort_meta_items(items: Vec>) -> Vec> { - // This is sort of stupid here, but we need to sort by - // human-readable strings. - let mut v = items.into_iter() - .map(|mi| (mi.name(), mi)) - .collect::)>>(); - - v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); - - // There doesn't seem to be a more optimal way to do this - v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| { - Spanned { - node: match node { - MetaItemKind::List(n, mis) => MetaItemKind::List(n, sort_meta_items(mis)), - _ => node - }, - span: span - } - })).collect() -} - pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } @@ -427,14 +513,15 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In if items.len() != 1 { diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); }); InlineAttr::None - } else if contains_name(&items[..], "always") { + } else if list_contains_name(&items[..], "always") { InlineAttr::Always - } else if contains_name(&items[..], "never") { + } else if list_contains_name(&items[..], "never") { InlineAttr::Never } else { diagnostic.map(|d| { - span_err!(d, (*items[0]).span, E0535, "invalid argument"); + span_err!(d, items[0].span, E0535, "invalid argument"); }); + InlineAttr::None } } @@ -453,27 +540,44 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches(cfgs: &[P], cfg: &ast::MetaItem, - sess: &ParseSess, features: Option<&Features>) + sess: &ParseSess, + features: Option<&Features>) -> bool { match cfg.node { - ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" => - mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)), - ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" => - mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)), - ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => { - if mis.len() != 1 { - span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); - return false; + ast::MetaItemKind::List(ref pred, ref mis) => { + for mi in mis.iter() { + if !mi.is_meta_item() { + handle_errors(&sess.span_diagnostic, mi.span, AttrError::UnsupportedLiteral); + return false; + } + } + + // The unwraps below may look dangerous, but we've already asserted + // that they won't fail with the loop above. + match &pred[..] { + "any" => mis.iter().any(|mi| { + cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features) + }), + "all" => mis.iter().all(|mi| { + cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features) + }), + "not" => { + if mis.len() != 1 { + span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); + return false; + } + + !cfg_matches(cfgs, mis[0].meta_item().unwrap(), sess, features) + }, + p => { + span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); + false + } } - !cfg_matches(cfgs, &mis[0], sess, features) - } - ast::MetaItemKind::List(ref pred, _) => { - span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", pred); - false }, ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => { - if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { - gated_cfg.check_and_emit(sess, features); + if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { + gated_cfg.check_and_emit(sess, feats); } contains(cfgs, cfg) } @@ -557,14 +661,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut since = None; let mut reason = None; for meta in metas { - match &*meta.name() { - "since" => if !get(meta, &mut since) { continue 'outer }, - "reason" => if !get(meta, &mut reason) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let Some(mi) = meta.meta_item() { + match &*mi.name() { + "since" => if !get(mi, &mut since) { continue 'outer }, + "reason" => if !get(mi, &mut reason) { continue 'outer }, + _ => { + handle_errors(diagnostic, mi.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -595,15 +704,20 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut reason = None; let mut issue = None; for meta in metas { - match &*meta.name() { - "feature" => if !get(meta, &mut feature) { continue 'outer }, - "reason" => if !get(meta, &mut reason) { continue 'outer }, - "issue" => if !get(meta, &mut issue) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let Some(mi) = meta.meta_item() { + match &*mi.name() { + "feature" => if !get(mi, &mut feature) { continue 'outer }, + "reason" => if !get(mi, &mut reason) { continue 'outer }, + "issue" => if !get(mi, &mut issue) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -645,14 +759,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut feature = None; let mut since = None; for meta in metas { - match &*meta.name() { - "feature" => if !get(meta, &mut feature) { continue 'outer }, - "since" => if !get(meta, &mut since) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { + match &*mi.name() { + "feature" => if !get(mi, &mut feature) { continue 'outer }, + "since" => if !get(mi, &mut since) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -739,14 +858,19 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut since = None; let mut note = None; for meta in metas { - match &*meta.name() { - "since" => if !get(meta, &mut since) { continue 'outer }, - "note" => if !get(meta, &mut note) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { + match &*mi.name() { + "since" => if !get(mi, &mut since) { continue 'outer }, + "note" => if !get(mi, &mut note) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -796,32 +920,36 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec ast::MetaItemKind::List(ref s, ref items) if s == "repr" => { mark_used(attr); for item in items { - match item.node { - ast::MetaItemKind::Word(ref word) => { - let hint = match &word[..] { - // Can't use "extern" because it's not a lexical identifier. - "C" => Some(ReprExtern), - "packed" => Some(ReprPacked), - "simd" => Some(ReprSimd), - _ => match int_type_of_word(&word) { - Some(ity) => Some(ReprInt(item.span, ity)), - None => { - // Not a word we recognize - span_err!(diagnostic, item.span, E0552, - "unrecognized representation hint"); - None - } - } - }; + if !item.is_meta_item() { + handle_errors(diagnostic, item.span, AttrError::UnsupportedLiteral); + continue + } - match hint { - Some(h) => acc.push(h), - None => { } + if let Some(mi) = item.word() { + let word = &*mi.name(); + let hint = match word { + // Can't use "extern" because it's not a lexical identifier. + "C" => Some(ReprExtern), + "packed" => Some(ReprPacked), + "simd" => Some(ReprSimd), + _ => match int_type_of_word(word) { + Some(ity) => Some(ReprInt(item.span, ity)), + None => { + // Not a word we recognize + span_err!(diagnostic, item.span, E0552, + "unrecognized representation hint"); + None + } } + }; + + match hint { + Some(h) => acc.push(h), + None => { } } - // Not a word: - _ => span_err!(diagnostic, item.span, E0553, - "unrecognized enum representation hint"), + } else { + span_err!(diagnostic, item.span, E0553, + "unrecognized enum representation hint"); } } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a825cf866a878..4663143f4b1f8 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use attr::{AttrMetaMethods, HasAttrs}; +use attr::{AttrMetaMethods, AttrNestedMetaItemMethods, HasAttrs}; use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; use {fold, attr}; @@ -52,6 +52,7 @@ impl<'a> StripUnconfigured<'a> { return None; } }; + let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { (2, Some(cfg), Some(mi)) => (cfg, mi), _ => { @@ -61,15 +62,24 @@ impl<'a> StripUnconfigured<'a> { } }; - if attr::cfg_matches(self.config, &cfg, self.sess, self.features) { - self.process_cfg_attr(respan(mi.span, ast::Attribute_ { - id: attr::mk_attr_id(), - style: attr.node.style, - value: mi.clone(), - is_sugared_doc: false, - })) - } else { - None + use attr::cfg_matches; + match (cfg.meta_item(), mi.meta_item()) { + (Some(cfg), Some(mi)) => + if cfg_matches(self.config, &cfg, self.sess, self.features) { + self.process_cfg_attr(respan(mi.span, ast::Attribute_ { + id: attr::mk_attr_id(), + style: attr.node.style, + value: mi.clone(), + is_sugared_doc: false, + })) + } else { + None + }, + _ => { + let msg = "unexpected literal(s) in `#[cfg_attr(, )]`"; + self.sess.span_diagnostic.span_err(attr.span, msg); + None + } } } @@ -91,7 +101,12 @@ impl<'a> StripUnconfigured<'a> { return true; } - attr::cfg_matches(self.config, &mis[0], self.sess, self.features) + if !mis[0].is_meta_item() { + self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal"); + return true; + } + + attr::cfg_matches(self.config, mis[0].meta_item().unwrap(), self.sess, self.features) }) } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 010b1d638e63c..9110e989a8a14 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -161,6 +161,24 @@ fn main() {} ``` "##, +E0565: r##" +A literal was used in an attribute that doesn't support literals. + +Erroneous code example: + +```compile_fail,E0565 +#[inline("always")] // error: unsupported literal +pub fn something() {} +``` + +Literals in attributes are new and largely unsupported. Work to support literals +where appropriate is ongoing. Try using an unquoted name instead: + +``` +#[inline(always)] +pub fn something() {} +``` +"##, } register_diagnostics! { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..1d3939df6fb82 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -277,10 +277,13 @@ pub trait AstBuilder { fn attribute(&self, sp: Span, mi: P) -> ast::Attribute; fn meta_word(&self, sp: Span, w: InternedString) -> P; + + fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem; + fn meta_list(&self, sp: Span, name: InternedString, - mis: Vec> ) + mis: Vec ) -> P; fn meta_name_value(&self, sp: Span, @@ -1141,10 +1144,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn meta_word(&self, sp: Span, w: InternedString) -> P { attr::mk_spanned_word_item(sp, w) } - fn meta_list(&self, sp: Span, name: InternedString, mis: Vec>) + + fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem { + respan(sp, ast::NestedMetaItemKind::MetaItem(attr::mk_spanned_word_item(sp, w))) + } + + fn meta_list(&self, sp: Span, name: InternedString, mis: Vec) -> P { attr::mk_spanned_list_item(sp, name, mis) } + fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind) -> P { attr::mk_spanned_name_value_item(sp, name, respan(sp, value)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d746f8e21141f..df1d5c4d9ca2f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -26,10 +26,8 @@ use self::AttributeType::*; use self::AttributeGate::*; use abi::Abi; -use ast::{NodeId, PatKind}; -use ast; -use attr; -use attr::AttrMetaMethods; +use ast::{self, NodeId, PatKind}; +use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use codemap::CodeMap; use syntax_pos::Span; use errors::Handler; @@ -283,7 +281,10 @@ declare_features! ( (active, relaxed_adts, "1.12.0", Some(35626)), // The `!` type - (active, never_type, "1.13.0", Some(35121)) + (active, never_type, "1.13.0", Some(35121)), + + // Allows all literals in attribute lists and values of key-value pairs. + (active, attr_literals, "1.13.0", Some(34981)) ); declare_features! ( @@ -831,11 +832,34 @@ impl<'a> PostExpansionVisitor<'a> { } } +fn contains_novel_literal(item: &ast::MetaItem) -> bool { + use ast::MetaItemKind::*; + use ast::NestedMetaItemKind::*; + + match item.node { + Word(..) => false, + NameValue(_, ref lit) => !lit.node.is_str(), + List(_, ref list) => list.iter().any(|li| { + match li.node { + MetaItem(ref mi) => contains_novel_literal(&**mi), + Literal(_) => true, + } + }), + } +} + impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { + // check for gated attributes self.context.check_attribute(attr, false); } + + if contains_novel_literal(&*(attr.node.value)) { + gate_feature_post!(&self, attr_literals, attr.span, + "non-string literals in attributes, or string \ + literals in top-level positions, are experimental"); + } } fn visit_name(&mut self, sp: Span, name: ast::Name) { @@ -895,7 +919,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { for attr in &i.attrs { if attr.name() == "repr" { for item in attr.meta_item_list().unwrap_or(&[]) { - if item.name() == "simd" { + if item.check_name("simd") { gate_feature_post!(&self, repr_simd, i.span, "SIMD types are experimental \ and possibly buggy"); @@ -1155,13 +1179,14 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F } Some(list) => { for mi in list { - let name = if mi.is_word() { - mi.name() - } else { - span_err!(span_handler, mi.span, E0556, - "malformed feature, expected just one word"); - continue - }; + let name = if let Some(word) = mi.word() { + word.name() + } else { + span_err!(span_handler, mi.span, E0556, + "malformed feature, expected just one word"); + continue + }; + if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter() .find(|& &(n, _, _, _)| name == n) { *(setter(&mut features)) = true; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b257ab98987dc..b361a856dbe2c 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -47,6 +47,10 @@ pub trait Folder : Sized { noop_fold_meta_items(meta_items, self) } + fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem { + noop_fold_meta_list_item(list_item, self) + } + fn fold_meta_item(&mut self, meta_item: P) -> P { noop_fold_meta_item(meta_item, self) } @@ -513,12 +517,25 @@ pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac { } } +pub fn noop_fold_meta_list_item(li: NestedMetaItem, fld: &mut T) + -> NestedMetaItem { + Spanned { + node: match li.node { + NestedMetaItemKind::MetaItem(mi) => { + NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi)) + }, + NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit) + }, + span: fld.new_span(li.span) + } +} + pub fn noop_fold_meta_item(mi: P, fld: &mut T) -> P { mi.map(|Spanned {node, span}| Spanned { node: match node { MetaItemKind::Word(id) => MetaItemKind::Word(id), MetaItemKind::List(id, mis) => { - MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e))) + MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e))) } MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s) }, diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 2ae3236cd5aa7..27dd055cd3ae7 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -193,9 +193,26 @@ impl<'a> Parser<'a> { Ok(attrs) } - /// matches meta_item = IDENT - /// | IDENT = lit - /// | IDENT meta_seq + fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + let lit = self.parse_lit()?; + debug!("Checking if {:?} is unusuffixed.", lit); + + if !lit.node.is_unsuffixed() { + let msg = "suffixed literals are not allowed in attributes"; + self.diagnostic().struct_span_err(lit.span, msg) + .help("instead of using a suffixed literal \ + (1u8, 1.0f32, etc.), use an unsuffixed version \ + (1, 1.0, etc.).") + .emit() + } + + Ok(lit) + } + + /// Per RFC#1559, matches the following grammar: + /// + /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, P> { let nt_meta = match self.token { token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()), @@ -213,16 +230,7 @@ impl<'a> Parser<'a> { match self.token { token::Eq => { self.bump(); - let lit = self.parse_lit()?; - // FIXME #623 Non-string meta items are not serialized correctly; - // just forbid them for now - match lit.node { - ast::LitKind::Str(..) => {} - _ => { - self.span_err(lit.span, - "non-string literals are not allowed in meta-items"); - } - } + let lit = self.parse_unsuffixed_lit()?; let hi = self.span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit)))) } @@ -238,11 +246,35 @@ impl<'a> Parser<'a> { } } - /// matches meta_seq = ( COMMASEP(meta_item) ) - fn parse_meta_seq(&mut self) -> PResult<'a, Vec>> { + /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; + fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + let sp = self.span; + let lo = self.span.lo; + + match self.parse_unsuffixed_lit() { + Ok(lit) => { + return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::Literal(lit))) + } + Err(ref mut err) => self.diagnostic().cancel(err) + } + + match self.parse_meta_item() { + Ok(mi) => { + return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + } + Err(ref mut err) => self.diagnostic().cancel(err) + } + + let found = self.this_token_to_string(); + let msg = format!("expected unsuffixed literal or identifier, found {}", found); + Err(self.diagnostic().struct_span_err(sp, &msg)) + } + + /// matches meta_seq = ( COMMASEP(meta_item_inner) ) + fn parse_meta_seq(&mut self) -> PResult<'a, Vec> { self.parse_unspanned_seq(&token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), - |p: &mut Parser<'a>| p.parse_meta_item()) + |p: &mut Parser<'a>| p.parse_meta_item_inner()) } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..562cc896aef01 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -120,7 +120,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, // of the feature gate, so we fake them up here. // #![feature(prelude_import)] - let prelude_import_meta = attr::mk_word_item(InternedString::new("prelude_import")); + let prelude_import_meta = attr::mk_list_word_item(InternedString::new("prelude_import")); let list = attr::mk_list_item(InternedString::new("feature"), vec![prelude_import_meta]); let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list); @@ -406,6 +406,10 @@ pub fn block_to_string(blk: &ast::Block) -> String { }) } +pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { + to_string(|s| s.print_meta_list_item(li)) +} + pub fn meta_item_to_string(mi: &ast::MetaItem) -> String { to_string(|s| s.print_meta_item(mi)) } @@ -764,6 +768,17 @@ pub trait PrintState<'a> { } } + fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()> { + match item.node { + ast::NestedMetaItemKind::MetaItem(ref mi) => { + self.print_meta_item(mi) + }, + ast::NestedMetaItemKind::Literal(ref lit) => { + self.print_literal(lit) + } + } + } + fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> { try!(self.ibox(INDENT_UNIT)); match item.node { @@ -780,7 +795,7 @@ pub trait PrintState<'a> { try!(self.popen()); try!(self.commasep(Consistent, &items[..], - |s, i| s.print_meta_item(&i))); + |s, i| s.print_meta_list_item(&i))); try!(self.pclose()); } } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index faf6a17a15045..ce917f248e1ef 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,8 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::AttrMetaMethods; -use attr; +use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; @@ -210,9 +209,8 @@ impl fold::Folder for EntryPointCleaner { folded.map(|ast::Item {id, ident, attrs, node, vis, span}| { let allow_str = InternedString::new("allow"); let dead_code_str = InternedString::new("dead_code"); - let allow_dead_code_item = - attr::mk_list_item(allow_str, - vec![attr::mk_word_item(dead_code_str)]); + let word_vec = vec![attr::mk_list_word_item(dead_code_str)]; + let allow_dead_code_item = attr::mk_list_item(allow_str, word_vec); let allow_dead_code = attr::mk_attr_outer(attr::mk_attr_id(), allow_dead_code_item); @@ -413,6 +411,7 @@ fn should_panic(i: &ast::Item) -> ShouldPanic { Some(attr) => { let msg = attr.meta_item_list() .and_then(|list| list.iter().find(|mi| mi.check_name("expected"))) + .and_then(|li| li.meta_item()) .and_then(|mi| mi.value_str()); ShouldPanic::Yes(msg) } diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 2ab0f0ff54669..2515435abeb9e 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -40,7 +40,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, } let inline = cx.meta_word(span, InternedString::new("inline")); - let hidden = cx.meta_word(span, InternedString::new("hidden")); + let hidden = cx.meta_list_item_word(span, InternedString::new("hidden")); let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]); let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)]; let trait_def = TraitDef { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..bae40ddf45c9f 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -623,7 +623,7 @@ impl<'a> TraitDef<'a> { let unused_qual = cx.attribute(self.span, cx.meta_list(self.span, InternedString::new("allow"), - vec![cx.meta_word(self.span, + vec![cx.meta_list_item_word(self.span, InternedString::new("unused_qualifications"))])); let mut a = vec![attr, unused_qual]; a.extend(self.attributes.iter().cloned()); diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index aee86b246b985..ffc1bfd6db8cd 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; @@ -98,8 +98,8 @@ fn expand_derive(cx: &mut ExtCtxt, let mut eq_span = None; for titem in traits.iter().rev() { - let tname = if titem.is_word() { - titem.name() + let tname = if let Some(word) = titem.word() { + word.name() } else { cx.span_err(titem.span, "malformed `derive` entry"); continue; diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index a6bc9db199c8b..6db10eeae769b 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -17,7 +17,8 @@ extern crate syntax_pos; extern crate rustc; extern crate rustc_plugin; -use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind}; +use syntax::ast::{self, Item, MetaItem, ItemKind}; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; use syntax::parse::{self, token}; use syntax::ptr::P; @@ -62,8 +63,8 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) } fn expand_into_foo_multi(cx: &mut ExtCtxt, - sp: Span, - attr: &MetaItem, + _sp: Span, + _attr: &MetaItem, it: Annotatable) -> Annotatable { match it { Annotatable::Item(it) => { @@ -72,7 +73,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone() })) } - Annotatable::ImplItem(it) => { + Annotatable::ImplItem(_) => { quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| { match i.node { ItemKind::Impl(_, _, _, _, _, mut items) => { @@ -82,7 +83,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, } }) } - Annotatable::TraitItem(it) => { + Annotatable::TraitItem(_) => { quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| { match i.node { ItemKind::Trait(_, _, _, mut items) => { @@ -97,15 +98,15 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, // Create a duplicate of the annotatable, based on the MetaItem fn expand_duplicate(cx: &mut ExtCtxt, - sp: Span, + _sp: Span, mi: &MetaItem, it: &Annotatable, push: &mut FnMut(Annotatable)) { let copy_name = match mi.node { ast::MetaItemKind::List(_, ref xs) => { - if let ast::MetaItemKind::Word(ref w) = xs[0].node { - token::str_to_ident(&w) + if let Some(word) = xs[0].word() { + token::str_to_ident(&word.name()) } else { cx.span_err(mi.span, "Expected word"); return; diff --git a/src/test/compile-fail/E0565-1.rs b/src/test/compile-fail/E0565-1.rs new file mode 100644 index 0000000000000..d3e68c7c0daf8 --- /dev/null +++ b/src/test/compile-fail/E0565-1.rs @@ -0,0 +1,17 @@ +// 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. + +#![feature(attr_literals)] + +// deprecated doesn't currently support literals +#[deprecated("since")] //~ ERROR E0565 +fn f() { } + +fn main() { } diff --git a/src/test/compile-fail/E0565.rs b/src/test/compile-fail/E0565.rs new file mode 100644 index 0000000000000..b2d369223e7da --- /dev/null +++ b/src/test/compile-fail/E0565.rs @@ -0,0 +1,17 @@ +// 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. + +#![feature(attr_literals)] + +// repr currently doesn't support literals +#[repr("C")] //~ ERROR E0565 +struct A { } + +fn main() { } diff --git a/src/test/compile-fail/attr-literals.rs b/src/test/compile-fail/attr-literals.rs new file mode 100644 index 0000000000000..b54288035175d --- /dev/null +++ b/src/test/compile-fail/attr-literals.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. + +// Check that literals in attributes parse just fine. + +#![feature(rustc_attrs, attr_literals)] +#![allow(dead_code)] +#![allow(unused_variables)] + +#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown +struct Q { } + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/gated-attr-literals.rs b/src/test/compile-fail/gated-attr-literals.rs new file mode 100644 index 0000000000000..f3132d5593e62 --- /dev/null +++ b/src/test/compile-fail/gated-attr-literals.rs @@ -0,0 +1,44 @@ +// 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. + +// Check that literals in attributes don't parse without the feature gate. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR string literals in top-level positions, are experimental +#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes, or string literals in top-level positions +#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes, or string literals in top-level positions +#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR string literals in top-level positions, are experimental +#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown + //~^ ERROR string literals in top-level positions, are experimental +struct Q { } + +#[rustc_error] +fn main() { } diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs new file mode 100644 index 0000000000000..0e2840c69d364 --- /dev/null +++ b/src/test/parse-fail/suffixed-literal-meta.rs @@ -0,0 +1,25 @@ +// 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. + +// compile-flags: -Z parse-only + +#[foo = 1usize] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u8] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u16] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u32] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u64] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1isize] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i8] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i16] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i32] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i64] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes +fn main() { } diff --git a/src/test/parse-fail/non-str-meta.rs b/src/test/pretty/attr-literals.rs similarity index 66% rename from src/test/parse-fail/non-str-meta.rs rename to src/test/pretty/attr-literals.rs index 3e2e69d2814e5..ba8c580cb0a01 100644 --- a/src/test/parse-fail/non-str-meta.rs +++ b/src/test/pretty/attr-literals.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// pp-exact +// Tests literals in attributes. -// Issue #623 - non-string meta items are not serialized correctly; -// for now just forbid them +#![feature(custom_attribute, attr_literals)] -#[foo = 1] //~ ERROR: non-string literals are not allowed in meta-items -fn main() { } +fn main() { + #![hello("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))] + #[align = 8] + fn f() { } + + #[vec(1, 2, 3)] + fn g() { } +} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 42135703b75a4..274e430bbea74 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -24,7 +24,6 @@ use syntax::ast; use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; -use syntax::ptr::P; use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; use syntax_pos::Span; diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index eeecd0b24e29e..882e90b2d6c15 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -26,7 +26,7 @@ use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; -use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; +use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure}; use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching}; use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; use syntax_pos::Span; diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 3f50811f826e0..e37cd89f29991 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -17,8 +17,11 @@ extern crate rustc; extern crate rustc_plugin; extern crate syntax_pos; -use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind}; +use syntax::ast::{self, Item, MetaItem, ItemKind}; +use syntax::codemap::DUMMY_SP; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; +use syntax::ext::quote::rt::ToTokens; use syntax::parse::{self, token}; use syntax::ptr::P; use syntax::tokenstream::TokenTree; @@ -41,10 +44,13 @@ pub fn plugin_registrar(reg: &mut Registry) { token::intern("duplicate"), // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_duplicate))); + reg.register_syntax_extension( + token::intern("caller"), + // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + MultiDecorator(Box::new(expand_caller))); } -fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box { +fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { if !tts.is_empty() { cx.span_fatal(sp, "make_a_1 takes no arguments"); } @@ -52,19 +58,18 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) } // See Issue #15750 -fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) - -> Box { +fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box { // Parse an expression and emit it unchanged. - let mut parser = parse::new_parser_from_tts(cx.parse_sess(), - cx.cfg(), tts.to_vec()); + let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec()); let expr = parser.parse_expr().unwrap(); MacEager::expr(quote_expr!(&mut *cx, $expr)) } fn expand_into_foo_multi(cx: &mut ExtCtxt, - sp: Span, - attr: &MetaItem, - it: Annotatable) -> Vec { + _sp: Span, + _attr: &MetaItem, + it: Annotatable) + -> Vec { match it { Annotatable::Item(it) => vec![ Annotatable::Item(P(Item { @@ -74,7 +79,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()), Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()), ], - Annotatable::ImplItem(it) => vec![ + Annotatable::ImplItem(_it) => vec![ quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| { match i.node { ItemKind::Impl(_, _, _, _, _, mut items) => { @@ -84,7 +89,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, } }) ], - Annotatable::TraitItem(it) => vec![ + Annotatable::TraitItem(_it) => vec![ quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| { match i.node { ItemKind::Trait(_, _, _, mut items) => { @@ -99,15 +104,14 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, // Create a duplicate of the annotatable, based on the MetaItem fn expand_duplicate(cx: &mut ExtCtxt, - sp: Span, + _sp: Span, mi: &MetaItem, it: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let copy_name = match mi.node { ast::MetaItemKind::List(_, ref xs) => { - if let ast::MetaItemKind::Word(ref w) = xs[0].node { - token::str_to_ident(&w) + if let Some(word) = xs[0].word() { + token::str_to_ident(&word.name()) } else { cx.span_err(mi.span, "Expected word"); return; @@ -142,4 +146,69 @@ fn expand_duplicate(cx: &mut ExtCtxt, } } +pub fn token_separate(ecx: &ExtCtxt, things: &[T], + token: token::Token) -> Vec { + let mut output: Vec = vec![]; + for (i, thing) in things.iter().enumerate() { + output.extend(thing.to_tokens(ecx)); + if i < things.len() - 1 { + output.push(TokenTree::Token(DUMMY_SP, token.clone())); + } + } + + output +} + +fn expand_caller(cx: &mut ExtCtxt, + sp: Span, + mi: &MetaItem, + it: &Annotatable, + push: &mut FnMut(Annotatable)) { + let (orig_fn_name, ret_type) = match *it { + Annotatable::Item(ref item) => match item.node { + ItemKind::Fn(ref decl, _, _, _, _, _) => { + (item.ident, &decl.output) + } + _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.") + }, + _ => cx.span_fatal(sp, "Only functions can be annotated.") + }; + + let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() { + if list.len() < 2 { + cx.span_fatal(mi.span(), "Need a function name and at least one parameter."); + } + + let fn_name = match list[0].name() { + Some(name) => token::str_to_ident(&name), + None => cx.span_fatal(list[0].span(), "First parameter must be an ident.") + }; + + (fn_name, &list[1..]) + } else { + cx.span_fatal(mi.span, "Expected list."); + }; + + let literals: Vec = arguments.iter().map(|arg| { + if let Some(lit) = arg.literal() { + lit.clone() + } else { + cx.span_fatal(arg.span(), "Expected literal."); + } + }).collect(); + + let arguments = token_separate(cx, literals.as_slice(), token::Comma); + if let ast::FunctionRetTy::Ty(ref rt) = *ret_type { + push(Annotatable::Item(quote_item!(cx, + fn $caller_name() -> $rt { + $orig_fn_name($arguments) + }).unwrap())) + } else { + push(Annotatable::Item(quote_item!(cx, + fn $caller_name() { + $orig_fn_name($arguments) + }).unwrap())) + } +} + pub fn foo() {} diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs index f0edc0f2b120f..f21c914a76c9c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs @@ -30,7 +30,7 @@ use syntax::tokenstream; use rustc_plugin::Registry; struct Expander { - args: Vec>, + args: Vec, } impl TTMacroExpander for Expander { @@ -38,7 +38,7 @@ impl TTMacroExpander for Expander { ecx: &'cx mut ExtCtxt, sp: Span, _: &[tokenstream::TokenTree]) -> Box { - let args = self.args.iter().map(|i| pprust::meta_item_to_string(&*i)) + let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) .collect::>().join(", "); let interned = token::intern_and_get_ident(&args[..]); MacEager::expr(ecx.expr_str(sp, interned)) diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs new file mode 100644 index 0000000000000..6dc651bb653a3 --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs @@ -0,0 +1,58 @@ +// Copyright 2013-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:macro_crate_test.rs +// ignore-stage1 + +#![feature(plugin, custom_attribute, attr_literals)] +#![plugin(macro_crate_test)] + +#[macro_use] +#[no_link] +extern crate macro_crate_test; + +// The `caller(name, args...)` attribute emits a new nullary function named +// `name` that calls the annotated function with `args`. As an example, consider +// the following: +// +// #[caller(simple, 1, "hello", 3.14)] +// fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, float) { +// (num, string, float) +// } +// +// This results in a function named `simple` that calls `f(1, "hello", 3.14)`. +// As a result, the expression `simple()` evaluates to `(1, "helllo", 3.14)`. + +#[caller(simple, 1, "hello", 3.14)] +#[caller(simple1, 2, "bye", 6.28)] +#[caller(simple2, 3, "hi", 1.01)] +fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, f32) { + (num, string, float) +} + +#[caller(complex, true, 10)] +#[caller(complex1, false, 15)] +#[caller(complex2, true, 20)] +fn g(emit: bool, num: i32) -> Option { + match emit { + true => Some(num), + false => None + } +} + +fn main() { + assert_eq!(simple(), (1, "hello", 3.14)); + assert_eq!(simple1(), (2, "bye", 6.28)); + assert_eq!(simple2(), (3, "hi", 1.01)); + + assert_eq!(complex(), Some(10)); + assert_eq!(complex1(), None); + assert_eq!(complex2(), Some(20)); +} From a65b201d94422eb81addef4bed2d37211e39661b Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 25 Aug 2016 13:28:35 -0700 Subject: [PATCH 281/768] prevent error message interleaving on win/unix --- src/librustc_errors/emitter.rs | 87 ++++++++++++++++++++++++- src/librustc_errors/lib.rs | 1 + src/librustc_errors/lock.rs | 112 +++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 src/librustc_errors/lock.rs diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 793155cfa8f8f..ed133d21b8a0f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -724,7 +724,10 @@ impl EmitterWriter { } match write!(&mut self.dst, "\n") { Err(e) => panic!("failed to emit error: {}", e), - _ => () + _ => match self.dst.flush() { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } } } } @@ -749,6 +752,21 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { fn emit_to_destination(rendered_buffer: &Vec>, lvl: &Level, dst: &mut Destination) -> io::Result<()> { + use lock; + + // In order to prevent error message interleaving, where multiple error lines get intermixed + // when multiple compiler processes error simultaneously, we emit errors with additional + // steps. + // + // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When + // the .flush() is called we take the buffer created from the buffered writes and write it at + // one shot. Because the Unix systems use ANSI for the colors, which is a text-based styling + // scheme, this buffered approach works and maintains the styling. + // + // On Windows, styling happens through calls to a terminal API. This prevents us from using the + // same buffering approach. Instead, we use a global Windows mutex, which we acquire long + // enough to output the full error message, then we release. + let _buffer_lock = lock::acquire_global_lock("rustc_errors"); for line in rendered_buffer { for part in line { dst.apply_style(lvl.clone(), part.style)?; @@ -757,6 +775,7 @@ fn emit_to_destination(rendered_buffer: &Vec>, } write!(dst, "\n")?; } + dst.flush()?; Ok(()) } @@ -783,14 +802,74 @@ fn stderr_isatty() -> bool { } } +pub type BufferedStderr = term::Terminal + Send; + pub enum Destination { Terminal(Box), + BufferedTerminal(Box), Raw(Box), } +/// Buffered writer gives us a way on Unix to buffer up an entire error message before we output +/// it. This helps to prevent interleaving of multiple error messages when multiple compiler +/// processes error simultaneously +pub struct BufferedWriter { + buffer: Vec, +} + +impl BufferedWriter { + // note: we use _new because the conditional compilation at its use site may make this + // this function unused on some platforms + fn _new() -> BufferedWriter { + BufferedWriter { + buffer: vec![] + } + } +} + +impl Write for BufferedWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + for b in buf { + self.buffer.push(*b); + } + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + let mut stderr = io::stderr(); + let result = (|| { + stderr.write_all(&self.buffer)?; + stderr.flush() + })(); + self.buffer.clear(); + result + } +} + impl Destination { + #[cfg(not(windows))] + /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error + /// to be emitted at one time. + fn from_stderr() -> Destination { + let stderr: Option> = + term::TerminfoTerminal::new(BufferedWriter::_new()) + .map(|t| Box::new(t) as Box); + + match stderr { + Some(t) => BufferedTerminal(t), + None => Raw(Box::new(io::stderr())), + } + } + + #[cfg(windows)] + /// Return a normal, unbuffered terminal when on Windows. fn from_stderr() -> Destination { - match term::stderr() { + let stderr: Option> = + term::TerminfoTerminal::new(io::stderr()) + .map(|t| Box::new(t) as Box) + .or_else(|| term::WinConsole::new(io::stderr()).ok() + .map(|t| Box::new(t) as Box)); + + match stderr { Some(t) => Terminal(t), None => Raw(Box::new(io::stderr())), } @@ -839,6 +918,7 @@ impl Destination { fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> { match *self { Terminal(ref mut t) => { t.attr(attr)?; } + BufferedTerminal(ref mut t) => { t.attr(attr)?; } Raw(_) => { } } Ok(()) @@ -847,6 +927,7 @@ impl Destination { fn reset_attrs(&mut self) -> io::Result<()> { match *self { Terminal(ref mut t) => { t.reset()?; } + BufferedTerminal(ref mut t) => { t.reset()?; } Raw(_) => { } } Ok(()) @@ -857,12 +938,14 @@ impl Write for Destination { fn write(&mut self, bytes: &[u8]) -> io::Result { match *self { Terminal(ref mut t) => t.write(bytes), + BufferedTerminal(ref mut t) => t.write(bytes), Raw(ref mut w) => w.write(bytes), } } fn flush(&mut self) -> io::Result<()> { match *self { Terminal(ref mut t) => t.flush(), + BufferedTerminal(ref mut t) => t.flush(), Raw(ref mut w) => w.flush(), } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4b3e53d931f13..c99bc47044853 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -50,6 +50,7 @@ pub mod emitter; pub mod snippet; pub mod registry; pub mod styled_buffer; +mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION }; use syntax_pos::{MacroBacktrace}; diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs new file mode 100644 index 0000000000000..0a9e0c4bbefb3 --- /dev/null +++ b/src/librustc_errors/lock.rs @@ -0,0 +1,112 @@ +// 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. + +//! Bindings to acquire a global named lock. +//! +//! This is intended to be used to synchronize multiple compiler processes to +//! ensure that we can output complete errors without interleaving on Windows. +//! Note that this is currently only needed for allowing only one 32-bit MSVC +//! linker to execute at once on MSVC hosts, so this is only implemented for +//! `cfg(windows)`. Also note that this may not always be used on Windows, +//! only when targeting 32-bit MSVC. +//! +//! For more information about why this is necessary, see where this is called. + +use std::any::Any; + +#[cfg(windows)] +#[allow(bad_style)] +pub fn acquire_global_lock(name: &str) -> Box { + use std::ffi::CString; + use std::io; + + type LPSECURITY_ATTRIBUTES = *mut u8; + type BOOL = i32; + type LPCSTR = *const u8; + type HANDLE = *mut u8; + type DWORD = u32; + + const INFINITE: DWORD = !0; + const WAIT_OBJECT_0: DWORD = 0; + const WAIT_ABANDONED: DWORD = 0x00000080; + + extern "system" { + fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES, + bInitialOwner: BOOL, + lpName: LPCSTR) -> HANDLE; + fn WaitForSingleObject(hHandle: HANDLE, + dwMilliseconds: DWORD) -> DWORD; + fn ReleaseMutex(hMutex: HANDLE) -> BOOL; + fn CloseHandle(hObject: HANDLE) -> BOOL; + } + + struct Handle(HANDLE); + + impl Drop for Handle { + fn drop(&mut self) { + unsafe { + CloseHandle(self.0); + } + } + } + + struct Guard(Handle); + + impl Drop for Guard { + fn drop(&mut self) { + unsafe { + ReleaseMutex((self.0).0); + } + } + } + + let cname = CString::new(name).unwrap(); + unsafe { + // Create a named mutex, with no security attributes and also not + // acquired when we create it. + // + // This will silently create one if it doesn't already exist, or it'll + // open up a handle to one if it already exists. + let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8); + if mutex.is_null() { + panic!("failed to create global mutex named `{}`: {}", name, + io::Error::last_os_error()); + } + let mutex = Handle(mutex); + + // Acquire the lock through `WaitForSingleObject`. + // + // A return value of `WAIT_OBJECT_0` means we successfully acquired it. + // + // A return value of `WAIT_ABANDONED` means that the previous holder of + // the thread exited without calling `ReleaseMutex`. This can happen, + // for example, when the compiler crashes or is interrupted via ctrl-c + // or the like. In this case, however, we are still transferred + // ownership of the lock so we continue. + // + // If an error happens.. well... that's surprising! + match WaitForSingleObject(mutex.0, INFINITE) { + WAIT_OBJECT_0 | WAIT_ABANDONED => {} + code => { + panic!("WaitForSingleObject failed on global mutex named \ + `{}`: {} (ret={:x})", name, + io::Error::last_os_error(), code); + } + } + + // Return a guard which will call `ReleaseMutex` when dropped. + Box::new(Guard(mutex)) + } +} + +#[cfg(unix)] +pub fn acquire_global_lock(_name: &str) -> Box { + Box::new(()) +} From 4eb08bb2ab43f0ad80071469771381a4dd03603d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 23 Aug 2016 03:21:17 +0000 Subject: [PATCH 282/768] Refactor away `AttrNestedMetaItemMethods`. --- src/librustc/hir/check_attr.rs | 2 +- src/librustc/lint/context.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_incremental/assert_dep_graph.rs | 2 +- .../persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/macro_import.rs | 2 +- src/librustc_plugin/load.rs | 2 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/test.rs | 1 - src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/attr.rs | 74 +++++++++---------- src/libsyntax/config.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax_ext/deriving/mod.rs | 2 +- 18 files changed, 50 insertions(+), 59 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 350b9fd88f6e7..42f293577b3be 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -11,7 +11,7 @@ use session::Session; use syntax::ast; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::visit; use syntax::visit::Visitor; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index bccd217352b70..ed812471594ed 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::parse::token::InternedString; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 55c6a4de9df50..3285cecb79c4d 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -11,7 +11,7 @@ use borrowck::BorrowckCtxt; use syntax::ast::{self, MetaItem}; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::AttrMetaMethods; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 482b351481c4e..7ab61d494b5cf 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -56,7 +56,7 @@ use std::env; use std::fs::File; use std::io::Write; use syntax::ast; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use syntax_pos::Span; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index f0092ce04d1f6..0a87c0833188b 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -32,7 +32,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use rustc_data_structures::fnv::FnvHashSet; use syntax::ast::{self, Attribute, NestedMetaItem}; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use rustc::ty::TyCtxt; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 9a4eec2d05b7a..57afcc47d6784 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods, AttributeMethods}; +use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4dc3d04c4a23b..91b7acff03f1f 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,7 +35,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap; use syntax::parse; -use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::parse::token::InternedString; use syntax::visit; use syntax_pos::{self, Span, mk_sp, Pos}; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index ec0c9f455cd0c..2482a53fe48b9 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,7 +18,7 @@ use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; -use syntax::attr::{self, AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::ext; use syntax_pos::Span; diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 5a8d2e58c558b..895645a76cba2 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{AttrMetaMethods}; use syntax_pos::{Span, COMMAND_LINE_SP}; /// Pointer to a registrar function. diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index e2633c829761f..e0532e7476f51 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,7 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use {ModuleSource, ModuleTranslation}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 02fa073dd5523..79c0bfaaa3448 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; use syntax::codemap::Spanned; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; @@ -542,7 +542,7 @@ impl Clean for ast::Attribute { } // This is a rough approximation that gets us what we want. -impl attr::AttrNestedMetaItemMethods for Attribute { +impl Attribute { fn check_name(&self, name: &str) -> bool { self.name().map_or(false, |mi_name| &*mi_name == name) } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 23a047f922f9d..caf05a947d366 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -141,7 +141,6 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { use syntax::attr::AttrMetaMethods; - use syntax::attr::AttrNestedMetaItemMethods; use syntax::print::pprust; let mut opts = TestOptions { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4e3a81b1baeac..d3397a04b3a53 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use rustc::hir::map as hir_map; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 4897425f2c06c..f1a820ce1d420 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -81,32 +81,47 @@ pub fn is_used(attr: &Attribute) -> bool { }) } -pub trait AttrNestedMetaItemMethods { +impl NestedMetaItem { + /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. + pub fn meta_item(&self) -> Option<&P> { + match self.node { + NestedMetaItemKind::MetaItem(ref item) => Some(&item), + _ => None + } + } + + /// Returns the Lit if self is a NestedMetaItemKind::Literal. + pub fn literal(&self) -> Option<&Lit> { + match self.node { + NestedMetaItemKind::Literal(ref lit) => Some(&lit), + _ => None + } + } + + /// Returns the Span for `self`. + pub fn span(&self) -> Span { + self.span + } + /// Returns true if this list item is a MetaItem with a name of `name`. - fn check_name(&self, name: &str) -> bool { + pub fn check_name(&self, name: &str) -> bool { self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) } /// Returns the name of the meta item, e.g. `foo` in `#[foo]`, /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem - fn name(&self) -> Option { + pub fn name(&self) -> Option { self.meta_item().and_then(|meta_item| Some(meta_item.name())) } - /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. - fn meta_item(&self) -> Option<&P>; - - /// Returns the Lit if self is a NestedMetaItemKind::Literal. - fn literal(&self) -> Option<&Lit>; - /// Gets the string value if self is a MetaItem and the MetaItem is a /// MetaItemKind::NameValue variant containing a string, otherwise None. - fn value_str(&self) -> Option { + pub fn value_str(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.value_str()) } /// Returns a MetaItem if self is a MetaItem with Kind Word. - fn word(&self) -> Option<&P> { + pub fn word(&self) -> Option<&P> { self.meta_item().and_then(|meta_item| if meta_item.is_word() { Some(meta_item) } else { @@ -115,57 +130,34 @@ pub trait AttrNestedMetaItemMethods { } /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) } /// Returns `true` if the variant is MetaItem. - fn is_meta_item(&self) -> bool { + pub fn is_meta_item(&self) -> bool { self.meta_item().is_some() } /// Returns `true` if the variant is Literal. - fn is_literal(&self) -> bool { + pub fn is_literal(&self) -> bool { self.literal().is_some() } /// Returns `true` if self is a MetaItem and the meta item is a word. - fn is_word(&self) -> bool { + pub fn is_word(&self) -> bool { self.word().is_some() } /// Returns `true` if self is a MetaItem and the meta item is a ValueString. - fn is_value_str(&self) -> bool { + pub fn is_value_str(&self) -> bool { self.value_str().is_some() } /// Returns `true` if self is a MetaItem and the meta item is a list. - fn is_meta_item_list(&self) -> bool { + pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } - - /// Returns the Span for `self`. - fn span(&self) -> Span; -} - -impl AttrNestedMetaItemMethods for NestedMetaItem { - fn meta_item(&self) -> Option<&P> { - match self.node { - NestedMetaItemKind::MetaItem(ref item) => Some(&item), - _ => None - } - } - - fn literal(&self) -> Option<&Lit> { - match self.node { - NestedMetaItemKind::Literal(ref lit) => Some(&lit), - _ => None - } - } - - fn span(&self) -> Span { - self.span - } } pub trait AttrMetaMethods { @@ -431,7 +423,7 @@ pub fn contains(haystack: &[P], needle: &MetaItem) -> bool { }) } -pub fn list_contains_name(items: &[AM], name: &str) -> bool { +pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { debug!("attr::list_contains_name (name={})", name); items.iter().any(|item| { debug!(" testing: {:?}", item.name()); diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 4663143f4b1f8..ed05dc243b32f 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use attr::{AttrMetaMethods, AttrNestedMetaItemMethods, HasAttrs}; +use attr::{AttrMetaMethods, HasAttrs}; use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; use {fold, attr}; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index df1d5c4d9ca2f..d2aa9a4cb6bff 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -27,7 +27,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind}; -use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use attr::{self, AttrMetaMethods}; use codemap::CodeMap; use syntax_pos::Span; use errors::Handler; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index ce917f248e1ef..0a14eae7d3532 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,7 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use attr::{self, AttrMetaMethods}; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index ffc1bfd6db8cd..fae17c0465bf5 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; From e264828b27b30980f6a9c316e17dc44e6b9be09f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 23 Aug 2016 03:39:04 +0000 Subject: [PATCH 283/768] Refactor away `AttributeMethods`. --- src/librustc/traits/error_reporting.rs | 2 +- src/librustc_incremental/calculate_svh/mod.rs | 1 - src/librustc_lint/builtin.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/attr.rs | 13 +++---------- src/libsyntax/print/pprust.rs | 2 +- 6 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6f263fcebeb0..b8c5ed51eabaf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -37,7 +37,7 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; use syntax::ast; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use errors::DiagnosticBuilder; diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 42bb1a5246738..b14c20ae8d46e 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -28,7 +28,6 @@ //! at the beginning. use syntax::ast; -use syntax::attr::AttributeMethods; use std::hash::{Hash, SipHasher, Hasher}; use rustc::dep_graph::DepNode; use rustc::hir; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 57afcc47d6784..6ab53b75f5028 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 79c0bfaaa3448..1f1844f9b73a1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::codemap::Spanned; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index f1a820ce1d420..f8fecd5fda02f 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -267,23 +267,16 @@ impl AttrMetaMethods for P { fn span(&self) -> Span { (**self).span() } } - -pub trait AttributeMethods { - fn meta(&self) -> &MetaItem; - fn with_desugared_doc(&self, f: F) -> T where - F: FnOnce(&Attribute) -> T; -} - -impl AttributeMethods for Attribute { +impl Attribute { /// Extract the MetaItem from inside this Attribute. - fn meta(&self) -> &MetaItem { + pub fn meta(&self) -> &MetaItem { &self.node.value } /// Convert self to a normal #[doc="foo"] comment, if it is a /// comment like `///` or `/** */`. (Returns self unchanged for /// non-sugared doc attributes.) - fn with_desugared_doc(&self, f: F) -> T where + pub fn with_desugared_doc(&self, f: F) -> T where F: FnOnce(&Attribute) -> T, { if self.node.is_sugared_doc { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 562cc896aef01..0caf9ae0d78dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -16,7 +16,7 @@ use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use util::parser::AssocOp; use attr; -use attr::{AttrMetaMethods, AttributeMethods}; +use attr::AttrMetaMethods; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; use errors; From bfb01bbb263923106b33fdaa140a5fa464426162 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 23 Aug 2016 03:54:53 +0000 Subject: [PATCH 284/768] Refactor away `AttrMetaMethods`. --- src/librustc/hir/check_attr.rs | 1 - src/librustc/lint/context.rs | 2 +- src/librustc/middle/lang_items.rs | 1 - src/librustc/middle/recursion_limit.rs | 1 - src/librustc/middle/stability.rs | 2 +- src/librustc/session/config.rs | 2 - src/librustc/traits/error_reporting.rs | 1 - src/librustc/ty/mod.rs | 2 +- src/librustc_borrowck/borrowck/fragments.rs | 1 - src/librustc_borrowck/borrowck/mir/mod.rs | 3 - src/librustc_borrowck/borrowck/mod.rs | 1 - src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 1 - src/librustc_incremental/assert_dep_graph.rs | 1 - .../persist/dirty_clean.rs | 1 - src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_lint/unused.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/macro_import.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 1 - src/librustc_plugin/load.rs | 1 - src/librustc_trans/assert_module_sources.rs | 1 - src/librustc_trans/back/link.rs | 1 - src/librustc_trans/base.rs | 1 - src/librustc_trans/consts.rs | 2 +- src/librustc_trans/symbol_names_test.rs | 1 - src/librustc_typeck/check/mod.rs | 1 - src/librustdoc/clean/mod.rs | 59 +----------- src/librustdoc/test.rs | 1 - src/librustdoc/visit_ast.rs | 1 - src/libsyntax/attr.rs | 92 +++++++------------ src/libsyntax/config.rs | 2 +- src/libsyntax/ext/expand.rs | 1 - src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/print/pprust.rs | 1 - src/libsyntax/test.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 1 - src/libsyntax_ext/deriving/mod.rs | 1 - 40 files changed, 50 insertions(+), 158 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 42f293577b3be..21143f93a7da8 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -11,7 +11,6 @@ use session::Session; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::visit; use syntax::visit::Visitor; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ed812471594ed..c921158614327 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token::InternedString; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index a209b1d1abd7c..d1769d5cbc51b 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -30,7 +30,6 @@ use middle::weak_lang_items; use util::nodemap::FnvHashMap; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use hir::intravisit::Visitor; use hir; diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 7dcd358165c92..0764e817f4307 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -17,7 +17,6 @@ use session::Session; use syntax::ast; -use syntax::attr::AttrMetaMethods; pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) { for attr in &krate.attrs { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index cbbc2c4f98f5e..405202bc634e4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -27,7 +27,7 @@ use syntax_pos::{Span, DUMMY_SP}; use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version}; -use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods}; +use syntax::attr::{self, Stability, Deprecation}; use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use hir; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8a32797dbd75a..7a1848f42d212 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -25,7 +25,6 @@ use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::parse; use syntax::parse::token::InternedString; use syntax::feature_gate::UnstableFeatures; @@ -1774,7 +1773,6 @@ mod tests { use std::rc::Rc; use super::{OutputType, OutputTypes, Externs, PanicStrategy}; use syntax::attr; - use syntax::attr::AttrMetaMethods; fn optgroups() -> Vec { super::rustc_optgroups().into_iter() diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b8c5ed51eabaf..a09ce38c4bb1a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -37,7 +37,6 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use errors::DiagnosticBuilder; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6c82157c8ca7c..ded9867fa6f2a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -43,7 +43,7 @@ use std::rc::Rc; use std::slice; use std::vec::IntoIter; use syntax::ast::{self, CrateNum, Name, NodeId}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token::InternedString; use syntax_pos::{DUMMY_SP, Span}; diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index d3d6fa9eb52b5..a8993724e6706 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -27,7 +27,6 @@ use rustc::middle::mem_categorization as mc; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::{Span, DUMMY_SP}; #[derive(PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 3285cecb79c4d..2d429aaab6a08 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -11,7 +11,6 @@ use borrowck::BorrowckCtxt; use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; @@ -127,8 +126,6 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, bd: BD) -> DataflowResults where BD: BitDenotation> + DataflowOperator { - use syntax::attr::AttrMetaMethods; - let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option { if let Some(item) = has_rustc_mir_with(attrs, name) { if let Some(s) = item.value_str() { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..343e9251e1db6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,6 @@ use std::fmt; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 3f2f6c84da190..c6ab4578f0632 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -49,7 +49,7 @@ use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use syntax::{ast, diagnostics, visit}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::{self, PResult, token}; use syntax::util::node_count::NodeCounter; use syntax; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1f3f823d0b8ab..efadf1ff488df 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -95,7 +95,6 @@ use std::thread; use rustc::session::early_error; use syntax::{ast, json}; -use syntax::attr::AttrMetaMethods; use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 7ab61d494b5cf..8df8f50037118 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -56,7 +56,6 @@ use std::env; use std::fs::File; use std::io::Write; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use syntax_pos::Span; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 0a87c0833188b..fda7ef207a344 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -32,7 +32,6 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use rustc_data_structures::fnv::FnvHashSet; use syntax::ast::{self, Attribute, NestedMetaItem}; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use rustc::ty::TyCtxt; diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 15914838acf0d..0e130c3bb66bf 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -14,7 +14,7 @@ use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax_pos::Span; use rustc::hir::{self, PatKind}; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6ab53b75f5028..a103386e2c980 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; @@ -1145,7 +1145,7 @@ impl LintPass for UnstableFeatures { impl LateLintPass for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { - if attr::contains_name(&[attr.meta().clone()], "feature") { + if attr.meta().check_name("feature") { if let Some(items) = attr.meta().meta_item_list() { for item in items { ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 44c2ffe45ccb4..411daa0c12aee 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -18,7 +18,7 @@ use lint::{LintPass, EarlyLintPass, LateLintPass}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; use syntax::ptr::P; use syntax_pos::Span; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 91b7acff03f1f..7e1f3ea618c97 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,7 +35,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap; use syntax::parse; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token::InternedString; use syntax::visit; use syntax_pos::{self, Span, mk_sp, Pos}; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 2482a53fe48b9..25fedb10201a9 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,7 +18,7 @@ use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::ext; use syntax_pos::Span; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 972e7f5be7075..f65680b567c74 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -32,7 +32,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use syntax::parse::token; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; -use syntax::attr::AttrMetaMethods; #[derive(Copy, Clone)] pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 895645a76cba2..9e56397bc99e9 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,6 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::attr::{AttrMetaMethods}; use syntax_pos::{Span, COMMAND_LINE_SP}; /// Pointer to a registrar function. diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index e0532e7476f51..7fe6d2bbfe24e 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,6 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use {ModuleSource, ModuleTranslation}; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 9f401b13d6f97..b21785c27dae5 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -42,7 +42,6 @@ use std::process::Command; use std::str; use flate; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::Span; // RLIB LLVM-BYTECODE OBJECT LAYOUT diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 165884c8f55a2..f231344f22f45 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -93,7 +93,6 @@ use std::rc::Rc; use std::str; use std::i32; use syntax_pos::{Span, DUMMY_SP}; -use syntax::attr::AttrMetaMethods; use syntax::attr; use rustc::hir; use syntax::ast; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index fa1e008d496e4..2b6e2a23261bd 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -29,7 +29,7 @@ use rustc::hir; use std::ffi::{CStr, CString}; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token; pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 9a7fe54e0d9f5..25c30151ad45d 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -17,7 +17,6 @@ use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; use syntax::ast; -use syntax::attr::AttrMetaMethods; use common::SharedCrateContext; use monomorphize::Instance; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 16300d869abf5..619aafa799f3e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -113,7 +113,6 @@ use std::ops::Deref; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::codemap::{self, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token::{self, InternedString, keywords}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1f1844f9b73a1..3a1e22f81b5c9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,9 +26,8 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::codemap::Spanned; -use syntax::parse::token::{self, InternedString, keywords}; +use syntax::parse::token::keywords; use syntax::ptr::P; use syntax::print::pprust as syntax_pprust; use syntax_pos::{self, DUMMY_SP, Pos}; @@ -541,62 +540,6 @@ impl Clean for ast::Attribute { } } -// This is a rough approximation that gets us what we want. -impl Attribute { - fn check_name(&self, name: &str) -> bool { - self.name().map_or(false, |mi_name| &*mi_name == name) - } - - fn literal(&self) -> Option<&ast::Lit> { None } - - fn is_literal(&self) -> bool { - match *self { - Literal(..) => true, - _ => false, - } - } - - fn meta_item(&self) -> Option<&P> { None } - - fn name(&self) -> Option { - match *self { - Word(ref n) | List(ref n, _) | NameValue(ref n, _) => { - Some(token::intern_and_get_ident(n)) - }, - _ => None - } - } - - fn value_str(&self) -> Option { - match *self { - NameValue(_, ref v) => { - Some(token::intern_and_get_ident(v)) - } - _ => None, - } - } - - fn word(&self) -> Option<&P> { None } - - fn is_word(&self) -> bool { - match *self { - Word(_) => true, - _ => false, - } - } - - fn meta_item_list<'a>(&'a self) -> Option<&'a [ast::NestedMetaItem]> { None } - - fn is_meta_item_list(&self) -> bool { - match *self { - List(..) => true, - _ => false, - } - } - - fn span(&self) -> syntax_pos::Span { unimplemented!() } -} - #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct TyParam { pub name: String, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index caf05a947d366..1805da2385b67 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -140,7 +140,6 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { - use syntax::attr::AttrMetaMethods; use syntax::print::pprust; let mut opts = TestOptions { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d3397a04b3a53..e66d01e5c2db1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,6 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use rustc::hir::map as hir_map; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index f8fecd5fda02f..6060ff529f215 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -160,40 +160,8 @@ impl NestedMetaItem { } } -pub trait AttrMetaMethods { - fn check_name(&self, name: &str) -> bool { - name == &self.name()[..] - } - - /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`, - /// `#[foo="bar"]` and `#[foo(bar)]` - fn name(&self) -> InternedString; - - /// Gets the string value if self is a MetaItemKind::NameValue variant - /// containing a string, otherwise None. - fn value_str(&self) -> Option; - - /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[NestedMetaItem]>; - - /// Indicates if the attribute is a Word. - fn is_word(&self) -> bool; - - /// Indicates if the attribute is a Value String. - fn is_value_str(&self) -> bool { - self.value_str().is_some() - } - - /// Indicates if the attribute is a Meta-Item List. - fn is_meta_item_list(&self) -> bool { - self.meta_item_list().is_some() - } - - fn span(&self) -> Span; -} - -impl AttrMetaMethods for Attribute { - fn check_name(&self, name: &str) -> bool { +impl Attribute { + pub fn check_name(&self, name: &str) -> bool { let matches = name == &self.name()[..]; if matches { mark_used(self); @@ -201,23 +169,32 @@ impl AttrMetaMethods for Attribute { matches } - fn name(&self) -> InternedString { self.meta().name() } + pub fn name(&self) -> InternedString { self.meta().name() } - fn value_str(&self) -> Option { + pub fn value_str(&self) -> Option { self.meta().value_str() } - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta().meta_item_list() } - fn is_word(&self) -> bool { self.meta().is_word() } + pub fn is_word(&self) -> bool { self.meta().is_word() } + + pub fn span(&self) -> Span { self.meta().span } - fn span(&self) -> Span { self.meta().span } + pub fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } + + /// Indicates if the attribute is a Value String. + pub fn is_value_str(&self) -> bool { + self.value_str().is_some() + } } -impl AttrMetaMethods for MetaItem { - fn name(&self) -> InternedString { +impl MetaItem { + pub fn name(&self) -> InternedString { match self.node { MetaItemKind::Word(ref n) => (*n).clone(), MetaItemKind::NameValue(ref n, _) => (*n).clone(), @@ -225,7 +202,7 @@ impl AttrMetaMethods for MetaItem { } } - fn value_str(&self) -> Option { + pub fn value_str(&self) -> Option { match self.node { MetaItemKind::NameValue(_, ref v) => { match v.node { @@ -237,34 +214,33 @@ impl AttrMetaMethods for MetaItem { } } - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { match self.node { MetaItemKind::List(_, ref l) => Some(&l[..]), _ => None } } - fn is_word(&self) -> bool { + pub fn is_word(&self) -> bool { match self.node { MetaItemKind::Word(_) => true, _ => false, } } - fn span(&self) -> Span { self.span } -} + pub fn span(&self) -> Span { self.span } + + pub fn check_name(&self, name: &str) -> bool { + name == &self.name()[..] + } -// Annoying, but required to get test_cfg to work -impl AttrMetaMethods for P { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - (**self).meta_item_list() + pub fn is_value_str(&self) -> bool { + self.value_str().is_some() + } + + pub fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() } - fn is_word(&self) -> bool { (**self).is_word() } - fn is_value_str(&self) -> bool { (**self).is_value_str() } - fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() } - fn span(&self) -> Span { (**self).span() } } impl Attribute { @@ -424,9 +400,9 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { }) } -pub fn contains_name(metas: &[AM], name: &str) -> bool { +pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { debug!("attr::contains_name (name={})", name); - metas.iter().any(|item| { + attrs.iter().any(|item| { debug!(" testing: {}", item.name()); item.check_name(name) }) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ed05dc243b32f..ff1ecd443717e 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use attr::{AttrMetaMethods, HasAttrs}; +use attr::HasAttrs; use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; use {fold, attr}; diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 031d9a2d3f46e..bc0f4de4471fb 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,7 +13,6 @@ use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; use attr::{self, HasAttrs}; -use attr::AttrMetaMethods; use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use syntax_pos::{self, Span, ExpnId}; use config::StripUnconfigured; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d2aa9a4cb6bff..cd2705fb7d8e8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -27,7 +27,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind}; -use attr::{self, AttrMetaMethods}; +use attr; use codemap::CodeMap; use syntax_pos::Span; use errors::Handler; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d130..6f06dd14d8fc7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -678,7 +678,7 @@ mod tests { use codemap::Spanned; use ast::{self, PatKind}; use abi::Abi; - use attr::{first_attr_value_str_by_name, AttrMetaMethods}; + use attr::first_attr_value_str_by_name; use parse; use parse::parser::Parser; use parse::token::{str_to_ident}; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0caf9ae0d78dd..28f1016c51f36 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -16,7 +16,6 @@ use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use util::parser::AssocOp; use attr; -use attr::AttrMetaMethods; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; use errors; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 0a14eae7d3532..e3e2457c471c0 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,7 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::{self, AttrMetaMethods}; +use attr; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index bae40ddf45c9f..0d69fc007997f 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -194,7 +194,6 @@ use std::vec; use syntax::abi::Abi; use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData}; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::codemap::{self, respan}; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index fae17c0465bf5..81085122e875b 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,6 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; From 469753f0abc4b9eac811d8b2955d478825f9c3e1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 24 Aug 2016 23:59:18 +0000 Subject: [PATCH 285/768] Fix fallout in tests. --- src/librustc/session/config.rs | 8 ++++++-- .../compile-fail-fulldeps/auxiliary/macro_crate_test.rs | 1 - .../auxiliary/custom_derive_plugin_attr.rs | 1 - src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs | 1 - 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7a1848f42d212..562dce6a1b129 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1772,7 +1772,9 @@ mod tests { use std::path::PathBuf; use std::rc::Rc; use super::{OutputType, OutputTypes, Externs, PanicStrategy}; - use syntax::attr; + use syntax::{ast, attr}; + use syntax::parse::token::InternedString; + use syntax::codemap::dummy_spanned; fn optgroups() -> Vec { super::rustc_optgroups().into_iter() @@ -1801,7 +1803,9 @@ mod tests { let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); let cfg = build_configuration(&sess, cfg); - assert!((attr::contains_name(&cfg[..], "test"))); + assert!(attr::contains(&cfg, &dummy_spanned(ast::MetaItemKind::Word({ + InternedString::new("test") + })))); } // When the user supplies --test and --cfg test, don't implicitly add diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 6db10eeae769b..5a3412b7ed9f9 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -18,7 +18,6 @@ extern crate rustc; extern crate rustc_plugin; use syntax::ast::{self, Item, MetaItem, ItemKind}; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; use syntax::parse::{self, token}; use syntax::ptr::P; diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 882e90b2d6c15..91b4b74797a83 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -21,7 +21,6 @@ extern crate rustc; extern crate rustc_plugin; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index e37cd89f29991..46fdf91125845 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -19,7 +19,6 @@ extern crate syntax_pos; use syntax::ast::{self, Item, MetaItem, ItemKind}; use syntax::codemap::DUMMY_SP; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; use syntax::ext::quote::rt::ToTokens; use syntax::parse::{self, token}; From aeedf22880ea550ce0aafa827df6f54aaab7c931 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Aug 2016 00:13:48 +0200 Subject: [PATCH 286/768] Add E0525 error explanation --- src/librustc/diagnostics.rs | 45 ++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index ba68686c55117..38c60a0b7c7c1 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1721,6 +1721,50 @@ fn cookie() -> ! { // error: definition of an unknown language item: `cookie` ``` "##, +E0525: r##" +A closure was attempted to get used whereas it doesn't implement the expected +trait. + +Erroneous code example: + +```compile_fail,E0525 +struct X; + +fn foo(_: T) {} +fn bar(_: T) {} + +fn main() { + let x = X; + let closure = |_| foo(x); // error: expected a closure that implements + // the `Fn` trait, but this closure only + // implements `FnOnce` + bar(closure); +} +``` + +In the example above, `closure` is an `FnOnce` closure whereas the `bar` +function expected an `Fn` closure. In this case, it's simple to fix the issue, +you just have to implement `Copy` and `Clone` traits on `struct X` and it'll +be ok: + +``` +#[derive(Clone, Copy)] // We implement `Clone` and `Copy` traits. +struct X; + +fn foo(_: T) {} +fn bar(_: T) {} + +fn main() { + let x = X; + let closure = |_| foo(x); + bar(closure); // ok! +} +``` + +To understand better how closures work in Rust, read: +https://doc.rust-lang.org/book/closures.html +"##, + } @@ -1760,5 +1804,4 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0491, // in type `..`, reference has a longer lifetime than the data it... E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0525 // expected a closure that implements `..` but this closure only implements `..` } From 14b4d72e01708a82e3d070f72ac87988f08df7da Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Aug 2016 21:10:19 +0300 Subject: [PATCH 287/768] rustc_borrowck: Don't hash types in loan paths --- src/librustc_borrowck/borrowck/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..9ab6aaa95630a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -41,6 +41,7 @@ use rustc::ty::{self, TyCtxt}; use std::fmt; use std::mem; use std::rc::Rc; +use std::hash::{Hash, Hasher}; use syntax::ast; use syntax::attr::AttrMetaMethods; use syntax_pos::{MultiSpan, Span}; @@ -345,7 +346,7 @@ impl<'tcx> Loan<'tcx> { } } -#[derive(Eq, Hash)] +#[derive(Eq)] pub struct LoanPath<'tcx> { kind: LoanPathKind<'tcx>, ty: ty::Ty<'tcx>, @@ -353,10 +354,13 @@ pub struct LoanPath<'tcx> { impl<'tcx> PartialEq for LoanPath<'tcx> { fn eq(&self, that: &LoanPath<'tcx>) -> bool { - let r = self.kind == that.kind; - debug_assert!(self.ty == that.ty || !r, - "Somehow loan paths are equal though their tys are not."); - r + self.kind == that.kind + } +} + +impl<'tcx> Hash for LoanPath<'tcx> { + fn hash(&self, state: &mut H) { + self.kind.hash(state); } } From f4c55dd08f8e02145d28f2ccdc07cf3e9d9ffc1b Mon Sep 17 00:00:00 2001 From: "changchun.fan" Date: Mon, 22 Aug 2016 15:37:08 +0800 Subject: [PATCH 288/768] Fix documentation in cell mod --- src/libcore/cell.rs | 49 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 2af48ef2fabe3..9b8c1be231ad2 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -119,26 +119,55 @@ //! `Cell`. //! //! ``` +//! #![feature(core_intrinsics)] +//! #![feature(shared)] //! use std::cell::Cell; +//! use std::ptr::Shared; +//! use std::intrinsics::abort; +//! use std::intrinsics::assume; //! -//! struct Rc { -//! ptr: *mut RcBox +//! struct Rc { +//! ptr: Shared> //! } //! -//! struct RcBox { -//! # #[allow(dead_code)] +//! struct RcBox { +//! strong: Cell, +//! refcount: Cell, //! value: T, -//! refcount: Cell //! } //! -//! impl Clone for Rc { +//! impl Clone for Rc { //! fn clone(&self) -> Rc { -//! unsafe { -//! (*self.ptr).refcount.set((*self.ptr).refcount.get() + 1); -//! Rc { ptr: self.ptr } -//! } +//! self.inc_strong(); +//! Rc { ptr: self.ptr } +//! } +//! } +//! +//! trait RcBoxPtr { +//! +//! fn inner(&self) -> &RcBox; +//! +//! fn strong(&self) -> usize { +//! self.inner().strong.get() +//! } +//! +//! fn inc_strong(&self) { +//! self.inner() +//! .strong +//! .set(self.strong() +//! .checked_add(1) +//! .unwrap_or_else(|| unsafe { abort() })); //! } //! } +//! +//! impl RcBoxPtr for Rc { +//! fn inner(&self) -> &RcBox { +//! unsafe { +//! assume(!(*(&self.ptr as *const _ as *const *const ())).is_null()); +//! &(**self.ptr) +//! } +//! } +//! } //! ``` //! From 88e4def9c74bbb3d8c68f16c87ee38a55b5379f5 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Thu, 25 Aug 2016 19:09:48 +0530 Subject: [PATCH 289/768] Update E0453 to new error format Fixes #35929. Part of #35233. r? @jonathandturner --- src/librustc/lint/context.rs | 5 +++-- src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs | 6 ++++-- src/test/compile-fail/E0453.rs | 5 ++++- src/test/compile-fail/lint-forbid-attr.rs | 6 ++++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index daac315e14def..9c06f0cca1566 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -606,11 +606,12 @@ pub trait LintContext: Sized { "{}({}) overruled by outer forbid({})", level.as_str(), lint_name, lint_name); + diag_builder.span_label(span, &format!("overruled by previous forbid")); match now_source { LintSource::Default => &mut diag_builder, LintSource::Node(forbid_source_span) => { - diag_builder.span_note(forbid_source_span, - "`forbid` lint level set here") + diag_builder.span_label(forbid_source_span, + &format!("`forbid` level set here")) }, LintSource::CommandLine => { diag_builder.note("`forbid` lint level was set on command line") diff --git a/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs index 61a8ee88a7082..75a025f064852 100644 --- a/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs @@ -15,11 +15,13 @@ #![plugin(lint_plugin_test)] #![forbid(test_lint)] //~^ NOTE lint level defined here -//~| NOTE `forbid` lint level set here +//~| NOTE `forbid` level set here fn lintme() { } //~ ERROR item is named 'lintme' -#[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(test_lint) +#[allow(test_lint)] +//~^ ERROR allow(test_lint) overruled by outer forbid(test_lint) +//~| NOTE overruled by previous forbid pub fn main() { lintme(); } diff --git a/src/test/compile-fail/E0453.rs b/src/test/compile-fail/E0453.rs index 629b373cd7f12..6fed3dca94ef1 100644 --- a/src/test/compile-fail/E0453.rs +++ b/src/test/compile-fail/E0453.rs @@ -9,7 +9,10 @@ // except according to those terms. #![forbid(non_snake_case)] +//~^ NOTE `forbid` level set here -#[allow(non_snake_case)] //~ ERROR E0453 +#[allow(non_snake_case)] +//~^ ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) +//~| NOTE overruled by previous forbid fn main() { } diff --git a/src/test/compile-fail/lint-forbid-attr.rs b/src/test/compile-fail/lint-forbid-attr.rs index fd2513c5a066d..a23083b5c8c11 100644 --- a/src/test/compile-fail/lint-forbid-attr.rs +++ b/src/test/compile-fail/lint-forbid-attr.rs @@ -9,8 +9,10 @@ // except according to those terms. #![forbid(deprecated)] -//~^ NOTE `forbid` lint level set here +//~^ NOTE `forbid` level set here -#[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated) +#[allow(deprecated)] +//~^ ERROR allow(deprecated) overruled by outer forbid(deprecated) +//~| NOTE overruled by previous forbid fn main() { } From 840795234695eda5c0be1ae8481add2e897f8bbf Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 26 Aug 2016 07:39:17 +0300 Subject: [PATCH 290/768] Do not emit "class method" debuginfo for types that are not DICompositeType. --- src/librustc_trans/debuginfo/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 58425cf60d550..73ed7a5510f3a 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -419,7 +419,15 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(), instance.substs, &impl_self_ty); - Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) + + // Only "class" methods are generally understood by LLVM, + // so avoid methods on other types (e.g. `<*mut T>::null`). + match impl_self_ty.sty { + ty::TyStruct(..) | ty::TyEnum(..) => { + Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) + } + _ => None + } } else { // For trait method impls we still use the "parallel namespace" // strategy From 2b10df7f24828b09759277cc3a9c18c493c38ce0 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Thu, 25 Aug 2016 20:56:47 -0400 Subject: [PATCH 291/768] Replace unnecessary uses of `TraitObject` with casts --- src/liballoc/boxed.rs | 9 ++------- src/liballoc/lib.rs | 2 +- src/libcore/any.rs | 14 ++------------ src/libstd/error.rs | 22 ++++------------------ 4 files changed, 9 insertions(+), 38 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index dae12f6e8bdf7..c8a78f84f1857 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -67,7 +67,6 @@ use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, Unique}; -use core::raw::TraitObject; use core::convert::From; /// A value that represents the heap. This is the default place that the `box` @@ -428,12 +427,8 @@ impl Box { pub fn downcast(self) -> Result, Box> { if self.is::() { unsafe { - // Get the raw representation of the trait object - let raw = Box::into_raw(self); - let to: TraitObject = mem::transmute::<*mut Any, TraitObject>(raw); - - // Extract the data pointer - Ok(Box::from_raw(to.data as *mut T)) + let raw: *mut Any = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) } } else { Err(self) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d9fd2d92710dc..c6453da3f4697 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -91,7 +91,7 @@ #![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![feature(unsize)] -#![cfg_attr(not(test), feature(fused, raw, fn_traits, placement_new_protocol))] +#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))] #![cfg_attr(test, feature(test, box_heap))] // Allow testing this library diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 4f486ad7cb8b2..a3018a46eea22 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -72,8 +72,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use mem::transmute; -use raw::TraitObject; use intrinsics; use marker::Reflect; @@ -199,11 +197,7 @@ impl Any { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { unsafe { - // Get the raw representation of the trait object - let to: TraitObject = transmute(self); - - // Extract the data pointer - Some(&*(to.data as *const T)) + Some(&*(self as *const Any as *const T)) } } else { None @@ -240,11 +234,7 @@ impl Any { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { unsafe { - // Get the raw representation of the trait object - let to: TraitObject = transmute(self); - - // Extract the data pointer - Some(&mut *(to.data as *const T as *mut T)) + Some(&mut *(self as *mut Any as *mut T)) } } else { None diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 44595361fb57c..ab537f39bf96a 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -54,7 +54,6 @@ use fmt::{self, Debug, Display}; use marker::Reflect; use mem::transmute; use num; -use raw::TraitObject; use str; use string; @@ -326,11 +325,7 @@ impl Error + 'static { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { unsafe { - // Get the raw representation of the trait object - let to: TraitObject = transmute(self); - - // Extract the data pointer - Some(&*(to.data as *const T)) + Some(&*(self as *const Error as *const T)) } } else { None @@ -344,11 +339,7 @@ impl Error + 'static { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { unsafe { - // Get the raw representation of the trait object - let to: TraitObject = transmute(self); - - // Extract the data pointer - Some(&mut *(to.data as *const T as *mut T)) + Some(&mut *(self as *mut Error as *mut T)) } } else { None @@ -409,13 +400,8 @@ impl Error { pub fn downcast(self: Box) -> Result, Box> { if self.is::() { unsafe { - // Get the raw representation of the trait object - let raw = Box::into_raw(self); - let to: TraitObject = - transmute::<*mut Error, TraitObject>(raw); - - // Extract the data pointer - Ok(Box::from_raw(to.data as *mut T)) + let raw: *mut Error = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) } } else { Err(self) From ee055a1ff37bb47f32ed460ca7d249d91f8cbe7d Mon Sep 17 00:00:00 2001 From: Daniele Baracchi Date: Wed, 24 Aug 2016 13:07:43 +0200 Subject: [PATCH 292/768] Stabilize type-macros Closes #27245 --- src/libsyntax/ext/expand.rs | 13 +---------- src/libsyntax/feature_gate.rs | 5 ++--- src/test/compile-fail/issue-30007.rs | 2 -- src/test/compile-fail/issue-32950.rs | 2 +- src/test/compile-fail/macro-context.rs | 2 -- src/test/compile-fail/macro-error.rs | 2 -- .../restricted/tuple-struct-fields/test.rs | 2 +- .../restricted/tuple-struct-fields/test2.rs | 2 +- .../restricted/tuple-struct-fields/test3.rs | 2 +- .../compile-fail/syntax-extension-minor.rs | 2 +- src/test/compile-fail/type-macros-fail.rs | 22 ------------------- .../run-pass/simd-intrinsic-generic-cast.rs | 3 +-- src/test/run-pass/type-macros-hlist.rs | 2 -- src/test/run-pass/type-macros-simple.rs | 2 -- 14 files changed, 9 insertions(+), 54 deletions(-) delete mode 100644 src/test/compile-fail/type-macros-fail.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 031d9a2d3f46e..26599208ec009 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -491,18 +491,7 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander) pub fn expand_type(t: P, fld: &mut MacroExpander) -> P { let t = match t.node.clone() { ast::TyKind::Mac(mac) => { - if fld.cx.ecfg.features.unwrap().type_macros { - expand_mac_invoc(mac, None, Vec::new(), t.span, fld) - } else { - feature_gate::emit_feature_err( - &fld.cx.parse_sess.span_diagnostic, - "type_macros", - t.span, - feature_gate::GateIssue::Language, - "type macros are experimental"); - - DummyResult::raw_ty(t.span) - } + expand_mac_invoc(mac, None, Vec::new(), t.span, fld) } _ => t }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d746f8e21141f..dc68e06463464 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -213,9 +213,6 @@ declare_features! ( // Allows associated type defaults (active, associated_type_defaults, "1.2.0", Some(29661)), - // Allows macros to appear in the type position. - (active, type_macros, "1.3.0", Some(27245)), - // allow `repr(simd)`, and importing the various simd intrinsics (active, repr_simd, "1.4.0", Some(27731)), @@ -321,6 +318,8 @@ declare_features! ( // mean anything (accepted, test_accepted_feature, "1.0.0", None), (accepted, tuple_indexing, "1.0.0", None), + // Allows macros to appear in the type position. + (accepted, type_macros, "1.13.0", Some(27245)), (accepted, while_let, "1.0.0", None), // Allows `#[deprecated]` attribute (accepted, deprecated, "1.9.0", Some(29935)) diff --git a/src/test/compile-fail/issue-30007.rs b/src/test/compile-fail/issue-30007.rs index 95a52cb232a49..fa0b75da999c2 100644 --- a/src/test/compile-fail/issue-30007.rs +++ b/src/test/compile-fail/issue-30007.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(type_macros)] - macro_rules! t { () => ( String ; ); //~ ERROR macro expansion ignores token `;` } diff --git a/src/test/compile-fail/issue-32950.rs b/src/test/compile-fail/issue-32950.rs index e8ca1c1fa98ff..20e5b1d72d3d7 100644 --- a/src/test/compile-fail/issue-32950.rs +++ b/src/test/compile-fail/issue-32950.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(type_macros, concat_idents)] +#![feature(concat_idents)] #[derive(Debug)] //~ NOTE in this expansion struct Baz( diff --git a/src/test/compile-fail/macro-context.rs b/src/test/compile-fail/macro-context.rs index 5d07f0747ff43..4aa0a3023bb10 100644 --- a/src/test/compile-fail/macro-context.rs +++ b/src/test/compile-fail/macro-context.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(type_macros)] - // (typeof used because it's surprisingly hard to find an unparsed token after a stmt) macro_rules! m { () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` diff --git a/src/test/compile-fail/macro-error.rs b/src/test/compile-fail/macro-error.rs index a69188da58d16..4a6dbf014a1ca 100644 --- a/src/test/compile-fail/macro-error.rs +++ b/src/test/compile-fail/macro-error.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(type_macros)] - macro_rules! foo { ($a:expr) => $a; //~ ERROR macro rhs must be delimited } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index 9cc53386d465c..f3dcf405a68a6 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted, type_macros)] +#![feature(pub_restricted)] mod foo { type T = (); diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 01466c6a85a5a..3bf8ca30a6c3f 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted, type_macros)] +#![feature(pub_restricted)] macro_rules! define_struct { ($t:ty) => { diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index ef187a1daed37..febe224fb84dc 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted, type_macros)] +#![feature(pub_restricted)] macro_rules! define_struct { ($t:ty) => { diff --git a/src/test/compile-fail/syntax-extension-minor.rs b/src/test/compile-fail/syntax-extension-minor.rs index 3e36b126523a7..f06e3544e575d 100644 --- a/src/test/compile-fail/syntax-extension-minor.rs +++ b/src/test/compile-fail/syntax-extension-minor.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(concat_idents, type_macros)] +#![feature(concat_idents)] pub fn main() { struct Foo; diff --git a/src/test/compile-fail/type-macros-fail.rs b/src/test/compile-fail/type-macros-fail.rs deleted file mode 100644 index 4712e2b65e16a..0000000000000 --- a/src/test/compile-fail/type-macros-fail.rs +++ /dev/null @@ -1,22 +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. - -macro_rules! Id { - ($T:tt) => ($T); -} - -struct Foo { - x: Id!(T) - //~^ ERROR: type macros are experimental (see issue #27245) -} - -fn main() { - let foo = Foo { x: i32 }; -} diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs index a20dd3ef72a54..2efd9333999b2 100644 --- a/src/test/run-pass/simd-intrinsic-generic-cast.rs +++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_simd, platform_intrinsics, concat_idents, - type_macros, test)] +#![feature(repr_simd, platform_intrinsics, concat_idents, test)] #![allow(non_camel_case_types)] extern crate test; diff --git a/src/test/run-pass/type-macros-hlist.rs b/src/test/run-pass/type-macros-hlist.rs index 803b0eae99e88..84c0983de80c8 100644 --- a/src/test/run-pass/type-macros-hlist.rs +++ b/src/test/run-pass/type-macros-hlist.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(type_macros)] - use std::ops::*; #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] diff --git a/src/test/run-pass/type-macros-simple.rs b/src/test/run-pass/type-macros-simple.rs index 22dfd507f7e2e..7d1045cf3f1a8 100644 --- a/src/test/run-pass/type-macros-simple.rs +++ b/src/test/run-pass/type-macros-simple.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(type_macros)] - macro_rules! Tuple { { $A:ty,$B:ty } => { ($A, $B) } } From a9907a1dd14c8fbed0f1b46f2cdddde7c2c15bbe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Aug 2016 00:14:01 +0200 Subject: [PATCH 293/768] Small error code explanations improvements --- src/librustc_lint/types.rs | 1 - src/librustc_trans/diagnostics.rs | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 99df5c6e5f95e..b0b5947145dbf 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -56,7 +56,6 @@ let Wrapping(x) = x; let y: usize = 1.wrapping_neg(); assert_eq!(x, y); ``` - "## } diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs index f7f065a3562ed..18d31448b1a24 100644 --- a/src/librustc_trans/diagnostics.rs +++ b/src/librustc_trans/diagnostics.rs @@ -23,8 +23,10 @@ extern "platform-intrinsic" { fn simd_add(a: T, b: T) -> T; } -unsafe { simd_add(0, 1); } -// error: invalid monomorphization of `simd_add` intrinsic +fn main() { + unsafe { simd_add(0, 1); } + // error: invalid monomorphization of `simd_add` intrinsic +} ``` The generic type has to be a SIMD type. Example: From 3e1b33dbdde108cadf10a35d36d14911cc3e5aea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Aug 2016 00:14:20 +0200 Subject: [PATCH 294/768] Add new error code tests --- src/test/compile-fail/E0502.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0503.rs | 15 +++++++++++++++ src/test/compile-fail/E0504.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/E0505.rs | 21 +++++++++++++++++++++ src/test/compile-fail/E0506.rs | 21 +++++++++++++++++++++ src/test/compile-fail/E0507.rs | 23 +++++++++++++++++++++++ src/test/compile-fail/E0508.rs | 16 ++++++++++++++++ src/test/compile-fail/E0509.rs | 28 ++++++++++++++++++++++++++++ src/test/compile-fail/E0511.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0512.rs | 15 +++++++++++++++ src/test/compile-fail/E0516.rs | 13 +++++++++++++ src/test/compile-fail/E0517.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/E0518.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0520.rs | 30 ++++++++++++++++++++++++++++++ src/test/compile-fail/E0522.rs | 16 ++++++++++++++++ src/test/compile-fail/E0527.rs | 20 ++++++++++++++++++++ 16 files changed, 324 insertions(+) create mode 100644 src/test/compile-fail/E0502.rs create mode 100644 src/test/compile-fail/E0503.rs create mode 100644 src/test/compile-fail/E0504.rs create mode 100644 src/test/compile-fail/E0505.rs create mode 100644 src/test/compile-fail/E0506.rs create mode 100644 src/test/compile-fail/E0507.rs create mode 100644 src/test/compile-fail/E0508.rs create mode 100644 src/test/compile-fail/E0509.rs create mode 100644 src/test/compile-fail/E0511.rs create mode 100644 src/test/compile-fail/E0512.rs create mode 100644 src/test/compile-fail/E0516.rs create mode 100644 src/test/compile-fail/E0517.rs create mode 100644 src/test/compile-fail/E0518.rs create mode 100644 src/test/compile-fail/E0520.rs create mode 100644 src/test/compile-fail/E0522.rs create mode 100644 src/test/compile-fail/E0527.rs diff --git a/src/test/compile-fail/E0502.rs b/src/test/compile-fail/E0502.rs new file mode 100644 index 0000000000000..fce8513ca64f9 --- /dev/null +++ b/src/test/compile-fail/E0502.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + let ref y = a; + bar(a); //~ ERROR E0502 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0503.rs b/src/test/compile-fail/E0503.rs new file mode 100644 index 0000000000000..810eb8d9b075c --- /dev/null +++ b/src/test/compile-fail/E0503.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let mut value = 3; + let _borrow = &mut value; + let _sum = value + 1; //~ ERROR E0503 +} diff --git a/src/test/compile-fail/E0504.rs b/src/test/compile-fail/E0504.rs new file mode 100644 index 0000000000000..c594f2415209d --- /dev/null +++ b/src/test/compile-fail/E0504.rs @@ -0,0 +1,25 @@ +// 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. + +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + + let x = move || { + println!("child function: {}", fancy_num.num); //~ ERROR E0504 + }; + + x(); + println!("main function: {}", fancy_ref.num); +} diff --git a/src/test/compile-fail/E0505.rs b/src/test/compile-fail/E0505.rs new file mode 100644 index 0000000000000..2d534b8a44a06 --- /dev/null +++ b/src/test/compile-fail/E0505.rs @@ -0,0 +1,21 @@ +// 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. + +struct Value {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + { + let _ref_to_val: &Value = &x; + eat(x); //~ ERROR E0505 + } +} diff --git a/src/test/compile-fail/E0506.rs b/src/test/compile-fail/E0506.rs new file mode 100644 index 0000000000000..ddaffd4a2736d --- /dev/null +++ b/src/test/compile-fail/E0506.rs @@ -0,0 +1,21 @@ +// 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. + +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + fancy_num = FancyNum { num: 6 }; //~ ERROR E0506 + + println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); +} diff --git a/src/test/compile-fail/E0507.rs b/src/test/compile-fail/E0507.rs new file mode 100644 index 0000000000000..87b1bf51bdbbf --- /dev/null +++ b/src/test/compile-fail/E0507.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); //~ ERROR E0507 +} diff --git a/src/test/compile-fail/E0508.rs b/src/test/compile-fail/E0508.rs new file mode 100644 index 0000000000000..a72c29cc3a59e --- /dev/null +++ b/src/test/compile-fail/E0508.rs @@ -0,0 +1,16 @@ +// 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. + +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = array[0]; //~ ERROR E0508 +} diff --git a/src/test/compile-fail/E0509.rs b/src/test/compile-fail/E0509.rs new file mode 100644 index 0000000000000..b92024cd6e20b --- /dev/null +++ b/src/test/compile-fail/E0509.rs @@ -0,0 +1,28 @@ +// 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. + +struct FancyNum { + num: usize +} + +struct DropStruct { + fancy: FancyNum +} + +impl Drop for DropStruct { + fn drop(&mut self) { + } +} + +fn main() { + let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; + let fancy_field = drop_struct.fancy; //~ ERROR E0509 + println!("Fancy: {}", fancy_field.num); +} diff --git a/src/test/compile-fail/E0511.rs b/src/test/compile-fail/E0511.rs new file mode 100644 index 0000000000000..c5c03f818253e --- /dev/null +++ b/src/test/compile-fail/E0511.rs @@ -0,0 +1,19 @@ +// 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. + +#![feature(platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_add(a: T, b: T) -> T; +} + +fn main() { + unsafe { simd_add(0, 1); } //~ ERROR E0511 +} diff --git a/src/test/compile-fail/E0512.rs b/src/test/compile-fail/E0512.rs new file mode 100644 index 0000000000000..25f9627164131 --- /dev/null +++ b/src/test/compile-fail/E0512.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn takes_u8(_: u8) {} + +fn main() { + unsafe { takes_u8(::std::mem::transmute(0u16)); } //~ ERROR E0512 +} diff --git a/src/test/compile-fail/E0516.rs b/src/test/compile-fail/E0516.rs new file mode 100644 index 0000000000000..a5f609de8497e --- /dev/null +++ b/src/test/compile-fail/E0516.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x: typeof(92) = 92; //~ ERROR E0516 +} diff --git a/src/test/compile-fail/E0517.rs b/src/test/compile-fail/E0517.rs new file mode 100644 index 0000000000000..be06e809915b5 --- /dev/null +++ b/src/test/compile-fail/E0517.rs @@ -0,0 +1,25 @@ +// 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. + +#[repr(C)] //~ ERROR E0517 +type Foo = u8; + +#[repr(packed)] //~ ERROR E0517 +enum Foo2 {Bar, Baz} + +#[repr(u8)] //~ ERROR E0517 +struct Foo3 {bar: bool, baz: bool} + +#[repr(C)] //~ ERROR E0517 +impl Foo3 { +} + +fn main() { +} diff --git a/src/test/compile-fail/E0518.rs b/src/test/compile-fail/E0518.rs new file mode 100644 index 0000000000000..8518bb4a6be3f --- /dev/null +++ b/src/test/compile-fail/E0518.rs @@ -0,0 +1,19 @@ +// 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. + +#[inline(always)] //~ ERROR E0518 +struct Foo; + +#[inline(never)] //~ ERROR E0518 +impl Foo { +} + +fn main() { +} diff --git a/src/test/compile-fail/E0520.rs b/src/test/compile-fail/E0520.rs new file mode 100644 index 0000000000000..bb52843ee7835 --- /dev/null +++ b/src/test/compile-fail/E0520.rs @@ -0,0 +1,30 @@ +// 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. + +#![feature(specialization)] + +trait SpaceLlama { + fn fly(&self); +} + +impl SpaceLlama for T { + default fn fly(&self) {} +} + +impl SpaceLlama for T { + fn fly(&self) {} +} + +impl SpaceLlama for i32 { + default fn fly(&self) {} //~ ERROR E0520 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0522.rs b/src/test/compile-fail/E0522.rs new file mode 100644 index 0000000000000..5103c83cafce3 --- /dev/null +++ b/src/test/compile-fail/E0522.rs @@ -0,0 +1,16 @@ +// 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. + +#![feature(lang_items)] + +#[lang = "cookie"] +fn cookie() -> ! { //~ E0522 + loop {} +} diff --git a/src/test/compile-fail/E0527.rs b/src/test/compile-fail/E0527.rs new file mode 100644 index 0000000000000..f03f35a57104f --- /dev/null +++ b/src/test/compile-fail/E0527.rs @@ -0,0 +1,20 @@ +// 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. + +#![feature(slice_patterns)] + +fn main() { + let r = &[1, 2, 3, 4]; + match r { + &[a, b] => { //~ ERROR E0527 + println!("a={}, b={}", a, b); + } + } +} From 50e0fbc9042856527dc35a0dfd9a7716dcf69ccd Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Wed, 17 Aug 2016 14:12:19 -0400 Subject: [PATCH 295/768] accumulate vector and assert for RangeFrom and RangeInclusive examples PR #35695 for `Range` was approved, so it seems that this side-effect-free style is preferred for Range* examples. This PR performs the same translation for `RangeFrom` and `RangeInclusive`. It also removes what looks to be an erroneously commented line for `#![feature(step_by)]`, and an unnecessary primitive-type annotation in `0u8..`. add `fn main` wrappers to enable Rust Playground "Run" button --- src/libcore/iter/range.rs | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 8408e5d88b4cb..66d05d81d80cd 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -263,14 +263,12 @@ impl ops::RangeFrom { /// # Examples /// /// ``` - /// # #![feature(step_by)] - /// - /// for i in (0u8..).step_by(2).take(10) { - /// println!("{}", i); + /// #![feature(step_by)] + /// fn main() { + /// let result: Vec<_> = (0..).step_by(2).take(5).collect(); + /// assert_eq!(result, vec![0, 2, 4, 6, 8]); /// } /// ``` - /// - /// This prints the first ten even natural integers (0 to 18). #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] pub fn step_by(self, by: A) -> StepBy { @@ -291,8 +289,10 @@ impl ops::Range { /// /// ``` /// #![feature(step_by)] - /// let result: Vec<_> = (0..10).step_by(2).collect(); - /// assert_eq!(result, vec![0, 2, 4, 6, 8]); + /// fn main() { + /// let result: Vec<_> = (0..10).step_by(2).collect(); + /// assert_eq!(result, vec![0, 2, 4, 6, 8]); + /// } /// ``` #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] @@ -315,20 +315,8 @@ impl ops::RangeInclusive { /// ``` /// #![feature(step_by, inclusive_range_syntax)] /// - /// for i in (0...10).step_by(2) { - /// println!("{}", i); - /// } - /// ``` - /// - /// This prints: - /// - /// ```text - /// 0 - /// 2 - /// 4 - /// 6 - /// 8 - /// 10 + /// let result: Vec<_> = (0...10).step_by(2).collect(); + /// assert_eq!(result, vec![0, 2, 4, 6, 8, 10]); /// ``` #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] From e2d9974b3b9a1021894c532b293e7624eaeb1e1c Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 25 Aug 2016 15:29:19 -0400 Subject: [PATCH 296/768] improve `BitAnd` trait documentation This pull request is based on the discussion in PR #35927. Add a module-level note that `&&` and `||` are short-circuiting operators and not overloadable. Add a simple `Scalar` example that lifts the `&` operator to a trivial struct tuple. Make `BooleanVector` a struct tuple. Derive `PartialEq` for `BooleanVector` instead of implementing it. Adds a `fn main` wrapper so that the example can integrate with Rust Playground. simplified bitand expression add a comment explaining what "rhs" means --- src/libcore/ops.rs | 62 ++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index b9adaf0206d94..128cf8f05bb59 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -21,6 +21,11 @@ //! custom operators are required, you should look toward macros or compiler //! plugins to extend Rust's syntax. //! +//! Note that the `&&` and `||` operators short-circuit, i.e. they only +//! evaluate their second operand if it contributes to the result. Since this +//! behavior is not enforceable by traits, `&&` and `||` are not supported as +//! overloadable operators. +//! //! Many of the operators take their operands by value. In non-generic //! contexts involving built-in types, this is usually not a problem. //! However, using these operators in generic code, requires some @@ -793,41 +798,56 @@ not_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// /// # Examples /// -/// In this example, the `BitAnd` trait is implemented for a `BooleanVector` -/// struct. +/// In this example, the `&` operator is lifted to a trivial `Scalar` type. /// /// ``` /// use std::ops::BitAnd; /// -/// #[derive(Debug)] -/// struct BooleanVector { -/// value: Vec, -/// }; +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); /// -/// impl BitAnd for BooleanVector { +/// impl BitAnd for Scalar { /// type Output = Self; /// +/// // rhs is the "right-hand side" of the expression `a & b` /// fn bitand(self, rhs: Self) -> Self { -/// BooleanVector { -/// value: self.value -/// .iter() -/// .zip(rhs.value.iter()) -/// .map(|(x, y)| *x && *y) -/// .collect(), -/// } +/// Scalar(self.0 & rhs.0) /// } /// } /// -/// impl PartialEq for BooleanVector { -/// fn eq(&self, other: &Self) -> bool { -/// self.value == other.value +/// fn main() { +/// assert_eq!(Scalar(true) & Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(true) & Scalar(false), Scalar(false)); +/// assert_eq!(Scalar(false) & Scalar(true), Scalar(false)); +/// assert_eq!(Scalar(false) & Scalar(false), Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitAnd` trait is implemented for a `BooleanVector` +/// struct. +/// +/// ``` +/// use std::ops::BitAnd; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitAnd for BooleanVector { +/// type Output = Self; +/// +/// fn bitand(self, BooleanVector(rhs): Self) -> Self { +/// let BooleanVector(lhs) = self; +/// assert_eq!(lhs.len(), rhs.len()); +/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) /// } /// } /// -/// let bv1 = BooleanVector { value: vec![true, true, false, false] }; -/// let bv2 = BooleanVector { value: vec![true, false, true, false] }; -/// let expected = BooleanVector { value: vec![true, false, false, false] }; -/// assert_eq!(bv1 & bv2, expected); +/// fn main() { +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, false, false, false]); +/// assert_eq!(bv1 & bv2, expected); +/// } /// ``` #[lang = "bitand"] #[stable(feature = "rust1", since = "1.0.0")] From ced1252654d9f589867a410d4c0c7328484d95c7 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 26 Aug 2016 10:59:46 -0700 Subject: [PATCH 297/768] Introduce `into_inner` method on `std::io::Take`. https://github.com/rust-lang/rust/issues/23755 --- src/libstd/io/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 1053792cd439b..06609cfad152e 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1501,6 +1501,33 @@ impl Take { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } + + /// Consumes the `Take`, returning the wrapped reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_take_into_inner)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = try!(File::open("foo.txt")); + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// try!(handle.read(&mut buffer)); + /// + /// let file = handle.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "io_take_into_inner", issue = "0")] + pub fn into_inner(self) -> T { + self.inner + } } #[stable(feature = "rust1", since = "1.0.0")] From c043a27e4232993d4366962f854d4d3812c66fff Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Fri, 26 Aug 2016 15:39:16 -0400 Subject: [PATCH 298/768] fix port for visit_statement --- src/librustc_mir/transform/qualify_consts.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2879941fdc320..756b06a0a699c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -36,6 +36,7 @@ use syntax_pos::Span; use std::collections::hash_map::Entry; use std::fmt; +use std::usize; use super::promote_consts::{self, Candidate, TempState}; @@ -393,8 +394,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { for index in 0..mir.var_decls.len() { if !self.const_fn_arg_vars.contains(index) { self.assign(&Lvalue::Var(Var::new(index)), Location { - block: BasicBlock::new(0), - statement_index: 0 + block: bb, + statement_index: usize::MAX, }); } } @@ -859,7 +860,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) { - self.nest(|this| this.super_statement(bb, statement, location)); + self.nest(|this| { + this.visit_source_info(&statement.source_info); + match statement.kind { + StatementKind::Assign(ref lvalue, ref rvalue) => { + this.visit_assign(bb, lvalue, rvalue, location); + } + StatementKind::SetDiscriminant { .. } | + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) => {} + } + }); } fn visit_terminator(&mut self, From 5222fa58a1bc766e5d9dc352e36d5725fa28cd7d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 18 Aug 2016 08:32:50 +0300 Subject: [PATCH 299/768] rustc: use accessors for Substs::{types,regions}. --- src/librustc/middle/dead.rs | 2 +- src/librustc/traits/error_reporting.rs | 7 ++- src/librustc/traits/fulfill.rs | 3 +- src/librustc/traits/object_safety.rs | 2 +- src/librustc/traits/select.rs | 35 ++++++------- src/librustc/ty/context.rs | 2 +- src/librustc/ty/flags.rs | 7 ++- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/mod.rs | 16 +++--- src/librustc/ty/relate.rs | 6 +-- src/librustc/ty/structural_impls.rs | 17 ------- src/librustc/ty/sty.rs | 19 +++---- src/librustc/ty/subst.rs | 52 +++++++++++++++++--- src/librustc/ty/util.rs | 5 +- src/librustc/ty/walk.rs | 19 ++++--- src/librustc/ty/wf.rs | 3 +- src/librustc/util/ppaux.rs | 36 +++++++------- src/librustc_metadata/tyencode.rs | 4 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 31 ++++++------ src/librustc_trans/callee.rs | 6 +-- src/librustc_trans/common.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 5 +- src/librustc_trans/debuginfo/mod.rs | 18 +++---- src/librustc_trans/debuginfo/type_names.rs | 4 +- src/librustc_trans/intrinsic.rs | 46 ++++++++--------- src/librustc_trans/meth.rs | 2 +- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/partitioning.rs | 4 +- src/librustc_trans/trans_item.rs | 33 +++++++------ src/librustc_trans/type_of.rs | 9 ++-- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 12 +++-- src/librustc_typeck/check/method/probe.rs | 22 +++++---- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/regionck.rs | 13 ++--- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/clean/mod.rs | 13 +++-- 43 files changed, 250 insertions(+), 229 deletions(-) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2a8594c59a837..37366f38974a4 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { - match substs.substs.types[0].sty { + match substs.substs.type_at(0).sty { TyEnum(tyid, _) | TyStruct(tyid, _) => { self.check_def_id(tyid.did) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6f263fcebeb0..10112e5084557 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -232,8 +232,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) { self_match_impls.push(def_id); - if trait_ref.substs.types[1..].iter() - .zip(&impl_trait_ref.substs.types[1..]) + if trait_ref.substs.types().skip(1) + .zip(impl_trait_ref.substs.types().skip(1)) .all(|(u,v)| self.fuzzy_match_tys(u, v)) { fuzzy_match_impls.push(def_id); @@ -738,8 +738,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); - let all_types = &trait_ref.substs().types; - if all_types.references_error() { + if predicate.references_error() { } else { // Typically, this ambiguity should only happen if // there are unresolved type inference variables diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 837e33b3e7fc2..76477d3df9360 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -142,7 +142,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { // Auto trait obligations on `impl Trait`. if tcx.trait_has_default_impl(predicate.def_id()) { let substs = predicate.skip_binder().trait_ref.substs; - if substs.types.len() == 1 && substs.regions.is_empty() { + if substs.types().count() == 1 && substs.regions().next().is_none() { if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty { return true; } @@ -440,7 +440,6 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't { t.skip_binder() // ok b/c this check doesn't care about regions .input_types() - .iter() .map(|t| selcx.infcx().resolve_type_vars_if_possible(t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 25d2df8fdedb3..219d520046762 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match predicate { ty::Predicate::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.0.trait_ref.input_types()[1..].iter().any(|t| t.has_self_ty()) + data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty()) } ty::Predicate::Projection(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9ea738bd326eb..f2ea14f17961f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -644,8 +644,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let input_types = stack.fresh_trait_ref.0.input_types(); - let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh()); + let unbound_input_types = stack.fresh_trait_ref.input_types().any(|ty| ty.is_fresh()); if unbound_input_types && self.intercrate { debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", stack.fresh_trait_ref); @@ -1064,9 +1063,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match *candidate { Ok(Some(_)) | Err(_) => true, - Ok(None) => { - cache_fresh_trait_pred.0.trait_ref.substs.types.has_infer_types() - } + Ok(None) => cache_fresh_trait_pred.has_infer_types() } } @@ -1603,7 +1600,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return; } }; - let target = obligation.predicate.skip_binder().input_types()[1]; + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); @@ -1936,7 +1933,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // for `PhantomData`, we pass `T` ty::TyStruct(def, substs) if def.is_phantom_data() => { - substs.types.to_vec() + substs.types().cloned().collect() } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2180,12 +2177,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self_ty.sty { ty::TyTrait(ref data) => { // OK to skip the binder, it is reintroduced below - let input_types = data.principal.skip_binder().input_types(); + let input_types = data.principal.input_types(); let assoc_types = data.projection_bounds.iter() .map(|pb| pb.skip_binder().ty); - let all_types: Vec<_> = input_types.iter().cloned() - .chain(assoc_types) - .collect(); + let all_types: Vec<_> = input_types.cloned() + .chain(assoc_types) + .collect(); // reintroduce the two binding levels we skipped, then flatten into one let all_types = ty::Binder(ty::Binder(all_types)); @@ -2476,7 +2473,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // regions here. See the comment there for more details. let source = self.infcx.shallow_resolve( tcx.no_late_bound_regions(&obligation.self_ty()).unwrap()); - let target = obligation.predicate.skip_binder().input_types()[1]; + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); let target = self.infcx.shallow_resolve(target); debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", @@ -2585,7 +2582,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } else { return Err(Unimplemented); }; - let mut ty_params = BitVector::new(substs_a.types.len()); + let mut ty_params = BitVector::new(substs_a.types().count()); let mut found = false; for ty in field.walk() { if let ty::TyParam(p) = ty.sty { @@ -2601,14 +2598,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // TyError and ensure they do not affect any other fields. // This could be checked after type collection for any struct // with a potentially unsized trailing field. - let types = substs_a.types.iter().enumerate().map(|(i, ty)| { + let types = substs_a.types().enumerate().map(|(i, ty)| { if ty_params.contains(i) { tcx.types.err } else { ty } }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions.clone()); + let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); for &ty in fields.split_last().unwrap().1 { if ty.subst(tcx, substs).references_error() { return Err(Unimplemented); @@ -2621,14 +2618,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Check that the source structure with the target's // type parameters is a subtype of the target. - let types = substs_a.types.iter().enumerate().map(|(i, ty)| { + let types = substs_a.types().enumerate().map(|(i, ty)| { if ty_params.contains(i) { - substs_b.types[i] + substs_b.type_at(i) } else { ty } }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions.clone()); + let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); let new_struct = tcx.mk_struct(def, substs); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = @@ -2753,7 +2750,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // substitution if we find that any of the input types, when // simplified, do not match. - obligation.predicate.0.input_types().iter() + obligation.predicate.skip_binder().input_types() .zip(impl_trait_ref.input_types()) .any(|(&obligation_ty, &impl_ty)| { let simplified_obligation_ty = diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3501dd4846087..2cae19d95ccbb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1152,7 +1152,7 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { impl_interners!('tcx, type_list: mk_type_list(Vec>, keep_local) -> [Ty<'tcx>], substs: mk_substs(Substs<'tcx>, |substs: &Substs| { - keep_local(&substs.types) || keep_local(&substs.regions) + substs.types().any(keep_local) || substs.regions().any(keep_local) }) -> Substs<'tcx>, bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| { keep_local(&fty.sig) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index c6c37296e9e12..c7300946eade8 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -208,8 +208,11 @@ impl FlagComputation { } fn add_substs(&mut self, substs: &Substs) { - self.add_tys(&substs.types); - for &r in &substs.regions { + for &ty in substs.types() { + self.add_ty(ty); + } + + for &r in substs.regions() { self.add_region(r); } } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 1dcc623d36558..62bd30e255592 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -264,7 +264,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match self_ty.sty { ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs) => { - if substs.types.is_empty() { // ignore regions + if substs.types().next().is_none() { // ignore regions self.push_item_path(buffer, adt_def.did); } else { buffer.push(&format!("<{}>", self_ty)); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6c82157c8ca7c..571ad3ca8b9aa 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -951,7 +951,6 @@ impl<'tcx> TraitPredicate<'tcx> { // leads to more recompilation. let def_ids: Vec<_> = self.input_types() - .iter() .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { ty::TyStruct(adt_def, _) | @@ -964,8 +963,8 @@ impl<'tcx> TraitPredicate<'tcx> { DepNode::TraitSelect(self.def_id(), def_ids) } - pub fn input_types(&self) -> &[Ty<'tcx>] { - &self.trait_ref.substs.types + pub fn input_types(&self) -> slice::Iter> { + self.trait_ref.input_types() } pub fn self_ty(&self) -> Ty<'tcx> { @@ -1107,7 +1106,7 @@ impl<'tcx> Predicate<'tcx> { pub fn walk_tys(&self) -> IntoIter> { let vec: Vec<_> = match *self { ty::Predicate::Trait(ref data) => { - data.0.trait_ref.input_types().to_vec() + data.skip_binder().input_types().cloned().collect() } ty::Predicate::Rfc1592(ref data) => { return data.walk_tys() @@ -1123,8 +1122,7 @@ impl<'tcx> Predicate<'tcx> { } ty::Predicate::Projection(ref data) => { let trait_inputs = data.0.projection_ty.trait_ref.input_types(); - trait_inputs.iter() - .cloned() + trait_inputs.cloned() .chain(Some(data.0.ty)) .collect() } @@ -1206,15 +1204,15 @@ impl<'tcx> TraitRef<'tcx> { } pub fn self_ty(&self) -> Ty<'tcx> { - self.substs.types[0] + self.substs.type_at(0) } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter> { // Select only the "input types" from a trait-reference. For // now this is all the types that appear in the // trait-reference, but it should eventually exclude // associated types. - &self.substs.types + self.substs.types() } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8975a799be143..481e8c97974ac 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -147,14 +147,12 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, { let tcx = relation.tcx(); - let types = a_subst.types.iter().enumerate().map(|(i, a_ty)| { - let b_ty = &b_subst.types[i]; + let types = a_subst.types().zip(b_subst.types()).enumerate().map(|(i, (a_ty, b_ty))| { let variance = variances.map_or(ty::Invariant, |v| v.types[i]); relation.relate_with_variance(variance, a_ty, b_ty) }).collect::>()?; - let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| { - let b_r = &b_subst.regions[i]; + let regions = a_subst.regions().zip(b_subst.regions()).enumerate().map(|(i, (a_r, b_r))| { let variance = variances.map_or(ty::Invariant, |v| v.regions[i]); relation.relate_with_variance(variance, a_r, b_r) }).collect::>()?; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f7c4b9938c279..9ccf817a53624 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,7 +9,6 @@ // except according to those terms. use infer::type_variable; -use ty::subst::Substs; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -692,22 +691,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let types = self.types.fold_with(folder); - let regions = self.regions.fold_with(folder); - Substs::new(folder.tcx(), types, regions) - } - - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_substs(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.types.visit_with(visitor) || self.regions.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ClosureSubsts { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 8aa81cc4743c9..3f8d55b4634e0 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -19,8 +19,9 @@ use util::common::ErrorReported; use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; -use std::ops; use std::mem; +use std::ops; +use std::slice; use syntax::abi; use syntax::ast::{self, Name}; use syntax::parse::token::keywords; @@ -335,7 +336,7 @@ impl<'tcx> PolyTraitRef<'tcx> { self.0.substs } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter> { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -360,12 +361,12 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter>{ // Select only the "input types" from a trait-reference. For // now this is all the types that appear in the // trait-reference, but it should eventually exclude // associated types. - &self.substs.types + self.substs.types() } } @@ -376,7 +377,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { self.0.def_id } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter> { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -1213,19 +1214,19 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } TyTrait(ref obj) => { let mut v = vec![obj.region_bound]; - v.extend_from_slice(&obj.principal.skip_binder().substs.regions); + v.extend(obj.principal.skip_binder().substs.regions()); v } TyEnum(_, substs) | TyStruct(_, substs) | TyAnon(_, substs) => { - substs.regions.to_vec() + substs.regions().cloned().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions.to_vec() + substs.func_substs.regions().cloned().collect() } TyProjection(ref data) => { - data.trait_ref.substs.regions.to_vec() + data.trait_ref.substs.regions().cloned().collect() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e1a19a7b7992e..96f4bda361b63 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -13,18 +13,20 @@ use middle::cstore; use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; -use ty::fold::{TypeFoldable, TypeFolder}; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; +use std::slice; + /////////////////////////////////////////////////////////////////////////// /// A substitution mapping type/region parameters to new values. -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Substs<'tcx> { - pub types: Vec>, - pub regions: Vec, + types: Vec>, + regions: Vec, } impl<'a, 'gcx, 'tcx> Substs<'tcx> { @@ -104,12 +106,34 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { self.regions.is_empty() && self.types.is_empty() } + #[inline] + pub fn types(&self) -> slice::Iter> { + self.types.iter() + } + + #[inline] + pub fn regions(&self) -> slice::Iter { + self.regions.iter() + } + + #[inline] + pub fn type_at(&self, i: usize) -> Ty<'tcx> { + self.types[i] + } + + #[inline] + pub fn region_at(&self, i: usize) -> ty::Region { + self.regions[i] + } + + #[inline] pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { - self.types[ty_param_def.index as usize] + self.type_at(ty_param_def.index as usize) } + #[inline] pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region { - self.regions[def.index as usize] + self.region_at(def.index as usize) } /// Transform from substitutions for a child of `source_ancestor` @@ -130,6 +154,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let types = self.types.fold_with(folder); + let regions = self.regions.fold_with(folder); + Substs::new(folder.tcx(), types, regions) + } + + fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + folder.fold_substs(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.types.visit_with(visitor) || self.regions.visit_with(visitor) + } +} + impl<'tcx> Encodable for &'tcx Substs<'tcx> { fn encode(&self, s: &mut S) -> Result<(), S::Error> { cstore::tls::with_encoding_context(s, |ecx, rbml_w| { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 51710c13a7dea..641dfa67c5b9e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -693,10 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { return false; } - let types_a = &substs_a.types; - let types_b = &substs_b.types; - - types_a.iter().zip(types_b).all(|(&a, &b)| same_type(a, b)) + substs_a.types().zip(substs_b.types()).all(|(&a, &b)| same_type(a, b)) } _ => { a == b diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 8a9ee45351dfc..5a94ba3cf6cd2 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -79,7 +79,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.push(mt.ty); } ty::TyProjection(ref data) => { - push_reversed(stack, &data.trait_ref.substs.types); + push_reversed(stack, data.trait_ref.substs.types()); } ty::TyTrait(ref obj) => { push_reversed(stack, obj.principal.input_types()); @@ -90,17 +90,17 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | ty::TyAnon(_, ref substs) => { - push_reversed(stack, &substs.types); + push_reversed(stack, substs.types()); } ty::TyClosure(_, ref substs) => { - push_reversed(stack, &substs.func_substs.types); - push_reversed(stack, &substs.upvar_tys); + push_reversed(stack, substs.func_substs.types()); + push_reversed(stack, substs.upvar_tys); } - ty::TyTuple(ref ts) => { + ty::TyTuple(ts) => { push_reversed(stack, ts); } ty::TyFnDef(_, substs, ref ft) => { - push_reversed(stack, &substs.types); + push_reversed(stack, substs.types()); push_sig_subtypes(stack, &ft.sig); } ty::TyFnPtr(ref ft) => { @@ -114,14 +114,17 @@ fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) push_reversed(stack, &sig.0.inputs); } -fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { +fn push_reversed<'a, 'tcx: 'a, I>(stack: &mut Vec>, tys: I) + where I: IntoIterator>, + I::IntoIter: DoubleEndedIterator +{ // We push slices on the stack in reverse order so as to // maintain a pre-order traversal. As of the time of this // writing, the fact that the traversal is pre-order is not // known to be significant to any code, but it seems like the // natural order one would expect (basically, the order of the // types as they are written). - for &ty in tys.iter().rev() { + for &ty in tys.into_iter().rev() { stack.push(ty); } } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 54b19362b1d86..e1a39e6957a49 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -260,8 +260,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); self.out.extend( - trait_ref.substs.types - .iter() + trait_ref.substs.types() .filter(|ty| !ty.has_escaping_regions()) .map(|ty| traits::Obligation::new(cause.clone(), ty::Predicate::WellFormed(ty)))); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 02ad8fb7033ed..c75fbf9579f5c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -22,6 +22,8 @@ use ty::fold::{TypeFolder, TypeVisitor}; use std::cell::Cell; use std::fmt; +use std::usize; + use syntax::abi::Abi; use syntax::parse::token; use syntax::ast::CRATE_NODE_ID; @@ -80,15 +82,17 @@ pub fn parameterized(f: &mut fmt::Formatter, verbose = tcx.sess.verbose(); has_self = generics.has_self; + let mut child_types = 0; if let Some(def_id) = generics.parent { // Methods. assert_eq!(ns, Ns::Value); + child_types = generics.types.len(); generics = tcx.lookup_generics(def_id); num_regions = generics.regions.len(); num_types = generics.types.len(); if has_self { - write!(f, "<{} as ", substs.types[0])?; + write!(f, "<{} as ", substs.type_at(0))?; } item_name = Some(tcx.item_name(did)); @@ -107,8 +111,8 @@ pub fn parameterized(f: &mut fmt::Formatter, if !verbose { if generics.types.last().map_or(false, |def| def.default.is_some()) { if let Some(substs) = tcx.lift(&substs) { - let tps = &substs.types[..num_types]; - for (def, actual) in generics.types.iter().zip(tps).rev() { + let tps = substs.types().rev().skip(child_types); + for (def, actual) in generics.types.iter().rev().zip(tps) { if def.default.subst(tcx, substs) != Some(actual) { break; } @@ -124,7 +128,7 @@ pub fn parameterized(f: &mut fmt::Formatter, if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { let projection_ty = projections[0].ty; - if let TyTuple(ref args) = substs.types[1].sty { + if let TyTuple(ref args) = substs.type_at(1).sty { return fn_sig(f, args, false, projection_ty); } } @@ -139,13 +143,15 @@ pub fn parameterized(f: &mut fmt::Formatter, } }; - let print_regions = |f: &mut fmt::Formatter, start: &str, regions: &[ty::Region]| { + let print_regions = |f: &mut fmt::Formatter, start: &str, regions| { // Don't print any regions if they're all erased. - if regions.iter().all(|r| *r == ty::ReErased) { + if Iterator::all(&mut Clone::clone(®ions), + |r: &ty::Region| *r == ty::ReErased) { return Ok(()); } for region in regions { + let region: &ty::Region = region; start_or_continue(f, start, ", ")?; if verbose { write!(f, "{:?}", region)?; @@ -167,11 +173,12 @@ pub fn parameterized(f: &mut fmt::Formatter, Ok(()) }; - print_regions(f, "<", &substs.regions[..num_regions])?; + print_regions(f, "<", substs.regions().take(num_regions).skip(0))?; - let tps = &substs.types[..num_types]; + let tps = substs.types().take(num_types - num_supplied_defaults) + .skip(has_self as usize); - for &ty in &tps[has_self as usize..tps.len() - num_supplied_defaults] { + for &ty in tps { start_or_continue(f, "<", ", ")?; write!(f, "{}", ty)?; } @@ -197,10 +204,10 @@ pub fn parameterized(f: &mut fmt::Formatter, write!(f, "::{}", item_name)?; } - print_regions(f, "::<", &substs.regions[num_regions..])?; + print_regions(f, "::<", substs.regions().take(usize::MAX).skip(num_regions))?; // FIXME: consider being smart with defaults here too - for ty in &substs.types[num_types..] { + for ty in substs.types().skip(num_types) { start_or_continue(f, "::<", ", ")?; write!(f, "{}", ty)?; } @@ -368,13 +375,6 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { } } -impl<'tcx> fmt::Debug for Substs<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Substs[types={:?}, regions={:?}]", - self.types, self.regions) - } -} - impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ItemSubsts({:?})", self.substs) diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 90fd8a0eb2f65..10f503f4e3699 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -251,11 +251,11 @@ fn enc_opt(w: &mut Cursor>, t: Option, enc_f: F) where pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, substs: &Substs<'tcx>) { write!(w, "["); - for &r in &substs.regions { + for &r in substs.regions() { enc_region(w, cx, r); } write!(w, "|"); - for &ty in &substs.types { + for &ty in substs.types() { enc_ty(w, cx, ty); } write!(w, "]"); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index bcdc0d2ea3f9d..32c78ca4a5ad1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -543,7 +543,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if let Literal::Item { def_id, substs } = constant.literal { // Don't peek inside generic (associated) constants. - if !substs.types.is_empty() { + if substs.types().next().is_some() { self.add_type(constant.ty); } else { let qualif = qualify_const_item_cached(self.tcx, diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 25a1479c28948..9b02cbe6721f3 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -104,8 +104,9 @@ use util::sha2::{Digest, Sha256}; use rustc::middle::{cstore, weak_lang_items}; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; -use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc::ty::{Ty, TyCtxt, TypeFoldable}; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; +use rustc::ty::subst::Substs; use rustc::hir::map::definitions::{DefPath, DefPathData}; use syntax::attr; @@ -126,14 +127,14 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // parameters substituted; this is // included in the hash as a kind of // safeguard. - item_type: ty::Ty<'tcx>, + item_type: Ty<'tcx>, // values for generic type parameters, // if any. - parameters: &[ty::Ty<'tcx>]) + substs: Option<&Substs<'tcx>>) -> String { debug!("get_symbol_hash(def_path={:?}, parameters={:?})", - def_path, parameters); + def_path, substs); let tcx = scx.tcx(); @@ -154,11 +155,13 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, hash_state.input(&encoded_item_type[..]); // also include any type parameters (for generic items) - for t in parameters { - assert!(!t.has_erasable_regions()); - assert!(!t.needs_subst()); - let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); - hash_state.input(&encoded_type[..]); + if let Some(substs) = substs { + for t in substs.types() { + assert!(!t.has_erasable_regions()); + assert!(!t.needs_subst()); + let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); + hash_state.input(&encoded_type[..]); + } } return format!("h{}", truncated_hash_result(&mut *hash_state)); @@ -252,7 +255,7 @@ impl<'a, 'tcx> Instance<'tcx> { // and should not matter anyhow. let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, &substs.types); + let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) @@ -282,14 +285,14 @@ impl ItemPathBuffer for SymbolPathBuffer { } pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - t: ty::Ty<'tcx>, + t: Ty<'tcx>, prefix: &str) -> String { let empty_def_path = DefPath { data: vec![], krate: cstore::LOCAL_CRATE, }; - let hash = get_symbol_hash(scx, &empty_def_path, t, &[]); + let hash = get_symbol_hash(scx, &empty_def_path, t, None); let path = [token::intern_and_get_ident(prefix)]; mangle(path.iter().cloned(), Some(&hash[..])) } @@ -297,7 +300,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, /// Only symbols that are invisible outside their compilation unit should use a /// name generated by this function. pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - t: ty::Ty<'tcx>, + t: Ty<'tcx>, suffix: &str) -> String { let path = [token::intern(&t.to_string()).as_str(), @@ -306,7 +309,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> data: vec![], krate: cstore::LOCAL_CRATE, }; - let hash = get_symbol_hash(ccx.shared(), &def_path, t, &[]); + let hash = get_symbol_hash(ccx.shared(), &def_path, t, None); mangle(path.iter().cloned(), Some(&hash[..])) } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 9aa486dc62811..a30f8f291a677 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -400,9 +400,9 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs); - assert!(!substs.types.needs_infer()); - assert!(!substs.types.has_escaping_regions()); - assert!(!substs.types.has_param_types()); + assert!(!substs.needs_infer()); + assert!(!substs.has_escaping_regions()); + assert!(!substs.has_param_types()); let substs = tcx.normalize_associated_type(&substs); let instance = Instance::new(def_id, substs); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index c5053e4feee62..5055ed86a0386 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -265,7 +265,7 @@ pub fn BuilderRef_res(b: BuilderRef) -> BuilderRef_res { } pub fn validate_substs(substs: &Substs) { - assert!(!substs.types.needs_infer()); + assert!(!substs.needs_infer()); } // Function context. Every LLVM function we create will have one of diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index fccb326b23221..49aa19557309f 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -342,11 +342,10 @@ impl<'tcx> TypeMap<'tcx> { // Add the def-index as the second part output.push_str(&format!("{:x}", def_id.index.as_usize())); - let tps = &substs.types; - if !tps.is_empty() { + if substs.types().next().is_some() { output.push('<'); - for &type_parameter in tps { + for &type_parameter in substs.types() { let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter); let param_type_id = diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 58425cf60d550..72a91f50be35e 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -344,36 +344,34 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, generics: &ty::Generics<'tcx>, - param_substs: &Substs<'tcx>, + substs: &Substs<'tcx>, file_metadata: DIFile, name_to_append_suffix_to: &mut String) -> DIArray { - let actual_types = ¶m_substs.types; - - if actual_types.is_empty() { + if substs.types().next().is_none() { return create_DIArray(DIB(cx), &[]); } name_to_append_suffix_to.push('<'); - for (i, &actual_type) in actual_types.iter().enumerate() { + for (i, &actual_type) in substs.types().enumerate() { + if i != 0 { + name_to_append_suffix_to.push_str(","); + } + let actual_type = cx.tcx().normalize_associated_type(&actual_type); // Add actual type name to <...> clause of function name let actual_type_name = compute_debuginfo_type_name(cx, actual_type, true); name_to_append_suffix_to.push_str(&actual_type_name[..]); - - if i != actual_types.len() - 1 { - name_to_append_suffix_to.push_str(","); - } } name_to_append_suffix_to.push('>'); // Again, only create type information if full debuginfo is enabled let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { let names = get_type_parameter_names(cx, generics); - actual_types.iter().zip(names).map(|(ty, name)| { + substs.types().zip(names).map(|(ty, name)| { let actual_type = cx.tcx().normalize_associated_type(ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); let name = CString::new(name.as_str().as_bytes()).unwrap(); diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 2a996ca75a37e..9337f7e58ffcc 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -175,13 +175,13 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, substs: &Substs<'tcx>, output: &mut String) { - if substs.types.is_empty() { + if substs.types().next().is_none() { return; } output.push('<'); - for &type_parameter in &substs.types { + for &type_parameter in substs.types() { push_debuginfo_type_name(cx, type_parameter, true, output); output.push_str(", "); } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 7faff98aea442..8bef7584db9e2 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -146,12 +146,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, Call(bcx, llfn, &[], call_debug_location) } (_, "size_of") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } (_, "size_of_val") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); if !type_is_sized(tcx, tp_ty) { let (llsize, _) = glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]); @@ -162,11 +162,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } (_, "min_align_of") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); C_uint(ccx, type_of::align_of(ccx, tp_ty)) } (_, "min_align_of_val") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); if !type_is_sized(tcx, tp_ty) { let (_, llalign) = glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]); @@ -176,12 +176,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } (_, "pref_align_of") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)) } (_, "drop_in_place") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); let is_sized = type_is_sized(tcx, tp_ty); let ptr = if is_sized { llargs[0] @@ -199,15 +199,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) } (_, "type_name") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); let ty_name = token::intern_and_get_ident(&tp_ty.to_string()); C_str_slice(ccx, ty_name) } (_, "type_id") => { - C_u64(ccx, ccx.tcx().type_id_hash(substs.types[0])) + C_u64(ccx, ccx.tcx().type_id_hash(substs.type_at(0))) } (_, "init") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); if !type_is_zero_size(ccx, tp_ty) { // Just zero out the stack slot. (See comment on base::memzero for explanation) init_zero_mem(bcx, llresult, tp_ty); @@ -219,7 +219,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) } (_, "needs_drop") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty)) } @@ -238,7 +238,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, false, false, - substs.types[0], + substs.type_at(0), llargs[1], llargs[0], llargs[2], @@ -248,7 +248,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, true, false, - substs.types[0], + substs.type_at(0), llargs[1], llargs[0], llargs[2], @@ -257,7 +257,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "write_bytes") => { memset_intrinsic(bcx, false, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], @@ -268,7 +268,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, false, true, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], @@ -278,7 +278,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, true, true, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], @@ -287,14 +287,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "volatile_set_memory") => { memset_intrinsic(bcx, true, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], call_debug_location) } (_, "volatile_load") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); let mut ptr = llargs[0]; if let Some(ty) = fn_ty.ret.cast { ptr = PointerCast(bcx, ptr, ty.ptr_to()); @@ -306,7 +306,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, to_immediate(bcx, load, tp_ty) }, (_, "volatile_store") => { - let tp_ty = substs.types[0]; + let tp_ty = substs.type_at(0); if type_is_fat_ptr(bcx.tcx(), tp_ty) { VolatileStore(bcx, llargs[1], get_dataptr(bcx, llargs[0])); VolatileStore(bcx, llargs[2], get_meta(bcx, llargs[0])); @@ -406,7 +406,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }, (_, "discriminant_value") => { - let val_ty = substs.types[0]; + let val_ty = substs.type_at(0); match val_ty.sty { ty::TyEnum(..) => { let repr = adt::represent_type(ccx, val_ty); @@ -458,7 +458,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, match split[1] { "cxchg" | "cxchgweak" => { - let sty = &substs.types[0].sty; + let sty = &substs.type_at(0).sty; if int_type_width_signed(sty, ccx).is_some() { let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False }; let val = AtomicCmpXchg(bcx, llargs[0], llargs[1], llargs[2], @@ -477,7 +477,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "load" => { - let sty = &substs.types[0].sty; + let sty = &substs.type_at(0).sty; if int_type_width_signed(sty, ccx).is_some() { AtomicLoad(bcx, llargs[0], order) } else { @@ -490,7 +490,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "store" => { - let sty = &substs.types[0].sty; + let sty = &substs.type_at(0).sty; if int_type_width_signed(sty, ccx).is_some() { AtomicStore(bcx, llargs[1], llargs[0], order); } else { @@ -529,7 +529,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => ccx.sess().fatal("unknown atomic operation") }; - let sty = &substs.types[0].sty; + let sty = &substs.type_at(0).sty; if int_type_width_signed(sty, ccx).is_some() { AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order) } else { diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 97c77ee3d8c72..103afd827de93 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -307,7 +307,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: Name) -> ImplMethod<'tcx> { - assert!(!substs.types.needs_infer()); + assert!(!substs.needs_infer()); let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let trait_def = tcx.lookup_trait_def(trait_def_id); diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 020ac8d643b86..0ffb83067f91c 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -32,7 +32,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { impl<'tcx> Instance<'tcx> { pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> Instance<'tcx> { - assert!(substs.regions.iter().all(|&r| r == ty::ReErased)); + assert!(substs.regions().all(|&r| r == ty::ReErased)); Instance { def: def_id, substs: substs } } pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> { diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 87d0ea0fe81f3..7341e8db41de5 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -342,7 +342,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, TransItem::DropGlue(..) => unreachable!(), // Is there any benefit to using ExternalLinkage?: TransItem::Fn(ref instance) => { - if instance.substs.types.is_empty() { + if instance.substs.types().next().is_none() { // This is a non-generic functions, we always // make it visible externally on the chance that // it might be used in another codegen unit. @@ -487,7 +487,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // DefId, we use the location of the impl after all. if tcx.trait_of_item(instance.def).is_some() { - let self_ty = instance.substs.types[0]; + let self_ty = instance.substs.type_at(0); // This is an implementation of a trait method. return characteristic_def_id_of_type(self_ty).or(Some(instance.def)); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 90dcc3a61fd7e..93302ab3b3be1 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -171,8 +171,8 @@ impl<'a, 'tcx> TransItem<'tcx> { instance: Instance<'tcx>, linkage: llvm::Linkage, symbol_name: &str) { - assert!(!instance.substs.types.needs_infer() && - !instance.substs.types.has_param_types()); + assert!(!instance.substs.needs_infer() && + !instance.substs.has_param_types()); let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; let item_ty = ccx.tcx().erase_regions(&item_ty); @@ -244,7 +244,7 @@ impl<'a, 'tcx> TransItem<'tcx> { pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { match *self { TransItem::Fn(ref instance) => { - !instance.substs.types.is_empty() || { + instance.substs.types().next().is_some() || { let attributes = tcx.get_attrs(instance.def); attr::requests_inline(&attributes[..]) } @@ -264,8 +264,9 @@ impl<'a, 'tcx> TransItem<'tcx> { pub fn is_instantiated_only_on_demand(&self) -> bool { match *self { - TransItem::Fn(ref instance) => !instance.def.is_local() || - !instance.substs.types.is_empty(), + TransItem::Fn(ref instance) => { + !instance.def.is_local() || instance.substs.types().next().is_some() + } TransItem::DropGlue(..) => true, TransItem::Static(..) => false, } @@ -273,7 +274,9 @@ impl<'a, 'tcx> TransItem<'tcx> { pub fn is_generic_fn(&self) -> bool { match *self { - TransItem::Fn(ref instance) => !instance.substs.types.is_empty(), + TransItem::Fn(ref instance) => { + instance.substs.types().next().is_some() + } TransItem::DropGlue(..) | TransItem::Static(..) => false, } @@ -374,7 +377,7 @@ impl<'a, 'tcx> TransItem<'tcx> { /// Same as `unique_type_name()` but with the result pushed onto the given /// `output` parameter. pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - t: ty::Ty<'tcx>, + t: Ty<'tcx>, output: &mut String) { match t.sty { ty::TyBool => output.push_str("bool"), @@ -396,7 +399,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs) => { push_item_name(tcx, adt_def.did, output); - push_type_params(tcx, &substs.types, &[], output); + push_type_params(tcx, substs, &[], output); }, ty::TyTuple(component_types) => { output.push('('); @@ -446,7 +449,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyTrait(ref trait_data) => { push_item_name(tcx, trait_data.principal.def_id(), output); push_type_params(tcx, - &trait_data.principal.skip_binder().substs.types, + trait_data.principal.skip_binder().substs, &trait_data.projection_bounds, output); }, @@ -494,7 +497,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push_str("{"); output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); output.push_str("}"); - push_type_params(tcx, &closure_substs.func_substs.types, &[], output); + push_type_params(tcx, closure_substs.func_substs, &[], output); } ty::TyError | ty::TyInfer(_) | @@ -529,16 +532,16 @@ fn push_item_name(tcx: TyCtxt, } fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - types: &[Ty<'tcx>], + substs: &Substs<'tcx>, projections: &[ty::PolyExistentialProjection<'tcx>], output: &mut String) { - if types.is_empty() && projections.is_empty() { + if substs.types().next().is_none() && projections.is_empty() { return; } output.push('<'); - for &type_parameter in types { + for &type_parameter in substs.types() { push_unique_type_name(tcx, type_parameter, output); output.push_str(", "); } @@ -562,7 +565,7 @@ fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, output: &mut String) { push_item_name(tcx, instance.def, output); - push_type_params(tcx, &instance.substs.types, &[], output); + push_type_params(tcx, instance.substs, &[], output); } pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String { @@ -572,7 +575,7 @@ pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String { } pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: ty::Ty<'tcx>) + ty: Ty<'tcx>) -> String { let mut output = String::new(); push_unique_type_name(tcx, ty, &mut output); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6862002ed83b2..b47d2cd0f204b 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -17,6 +17,7 @@ use common::*; use machine; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::subst::Substs; use type_::Type; @@ -256,7 +257,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, def.did, &substs.types); + let name = llvm_type_name(cx, def.did, substs); adt::incomplete_type_of(cx, &repr, &name[..]) } ty::TyClosure(..) => { @@ -330,7 +331,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // in *after* placing it into the type cache. This prevents // infinite recursion with recursive struct types. let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, def.did, &substs.types); + let name = llvm_type_name(cx, def.did, substs); adt::incomplete_type_of(cx, &repr, &name[..]) } } @@ -367,10 +368,10 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, did: DefId, - tps: &[Ty<'tcx>]) + substs: &Substs<'tcx>) -> String { let base = cx.tcx().item_path_str(did); - let strings: Vec = tps.iter().map(|t| t.to_string()).collect(); + let strings: Vec = substs.types().map(|t| t.to_string()).collect(); let tstr = if strings.is_empty() { base } else { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f6984f42cab34..72f81c7d48da8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -937,8 +937,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == self.tcx().lang_items.owned_box() { - assert_eq!(substs.types.len(), 1); - return self.tcx().mk_box(substs.types[0]); + assert_eq!(substs.types().count(), 1); + return self.tcx().mk_box(substs.type_at(0)); } decl_ty.subst(self.tcx(), substs) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 377ca5eaebe30..46e8c27f6d33b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } - let arg_param_ty = trait_ref.substs().types[1]; + let arg_param_ty = trait_ref.substs().type_at(1); let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 82545d564a20c..4e48838f85cfb 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -438,7 +438,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( ty::TyStruct(def, substs) if def.is_phantom_data() => { // PhantomData - behaves identically to T - let ity = substs.types[0]; + let ity = substs.type_at(0); iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 9e0b38fd9fe51..8b757309f4887 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -328,18 +328,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // // FIXME -- permit users to manually specify lifetimes Substs::for_item(self.tcx, method.def_id, |def, _| { - if let Some(&r) = substs.regions.get(def.index as usize) { - r + let i = def.index as usize; + if i < substs.regions().count() { + substs.region_at(i) } else { self.region_var_for_def(self.span, def) } }, |def, cur_substs| { - if let Some(&ty) = substs.types.get(def.index as usize) { - ty + let i = def.index as usize; + if i < substs.types().count() { + substs.type_at(i) } else if supplied_method_types.is_empty() { self.type_var_for_def(self.span, def, cur_substs) } else { - supplied_method_types[def.index as usize - substs.types.len()] + supplied_method_types[i - substs.types().count()] } }) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c306463ec1de0..d8ff9b4057f34 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -519,9 +519,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_ref.substs, m); assert_eq!(m.generics.parent_types as usize, - trait_ref.substs.types.len()); + trait_ref.substs.types().count()); assert_eq!(m.generics.parent_regions as usize, - trait_ref.substs.regions.len()); + trait_ref.substs.regions().count()); } // Because this trait derives from a where-clause, it @@ -529,7 +529,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // artifacts. This means it is safe to put into the // `WhereClauseCandidate` and (eventually) into the // `WhereClausePick`. - assert!(!trait_ref.substs.types.needs_infer()); + assert!(!trait_ref.substs.needs_infer()); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -1220,8 +1220,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - assert_eq!(substs.types.len(), method.generics.parent_types as usize); - assert_eq!(substs.regions.len(), method.generics.parent_regions as usize); + assert_eq!(substs.types().count(), method.generics.parent_types as usize); + assert_eq!(substs.regions().count(), method.generics.parent_regions as usize); if self.mode == Mode::Path { return impl_ty; @@ -1236,16 +1236,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { xform_self_ty.subst(self.tcx, substs) } else { let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { - if let Some(&r) = substs.regions.get(def.index as usize) { - r + let i = def.index as usize; + if i < substs.regions().count() { + substs.region_at(i) } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. ty::ReErased } }, |def, cur_substs| { - if let Some(&ty) = substs.types.get(def.index as usize) { - ty + let i = def.index as usize; + if i < substs.types().count() { + substs.type_at(i) } else { self.type_var_for_def(self.span, def, cur_substs) } @@ -1324,7 +1326,7 @@ impl<'tcx> Candidate<'tcx> { // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(!trait_ref.substs().types.needs_infer()); + assert!(!trait_ref.substs().needs_infer()); WhereClausePick(trait_ref.clone()) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 16300d869abf5..f2ed3e37c1a28 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1899,7 +1899,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Registers obligations that all types appearing in `substs` are well-formed. pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr) { - for &ty in &substs.types { + for &ty in substs.types() { self.register_wf_obligation(ty, expr.span, traits::MiscObligation); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 859d5ff0543d0..a596b3cdcbb81 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1445,11 +1445,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for ®ion in &substs.regions { + for ®ion in substs.regions() { self.sub_regions(origin.clone(), expr_region, region); } - for &ty in &substs.types { + for &ty in substs.types() { let ty = self.resolve_type(ty); self.type_must_outlive(origin.clone(), ty, expr_region); } @@ -1575,11 +1575,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if env_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); - for &component_ty in &projection_ty.trait_ref.substs.types { + for &component_ty in projection_ty.trait_ref.substs.types() { self.type_must_outlive(origin.clone(), component_ty, region); } - for &r in &projection_ty.trait_ref.substs.regions { + for &r in projection_ty.trait_ref.substs.regions() { self.sub_regions(origin.clone(), region, r); } @@ -1597,10 +1597,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { let unique_bound = env_bounds[0]; debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); - if projection_ty.trait_ref.substs.regions - .iter() - .any(|r| env_bounds.contains(r)) - { + if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(r)) { debug!("projection_must_outlive: unique declared bound appears in trait ref"); self.sub_regions(origin.clone(), region, unique_bound); return; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bcad7dd3bd0fa..ecec4913fb7dc 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -597,7 +597,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait impl: take implied bounds from all types that // appear in the trait reference. let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); - trait_ref.substs.types.to_vec() + trait_ref.substs.types().cloned().collect() } None => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index cfc1292c34b78..3e5623404ed35 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -103,7 +103,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } let free_substs = fcx.parameter_environment.free_substs; - for (i, r) in free_substs.regions.iter().enumerate() { + for (i, r) in free_substs.regions().enumerate() { match *r { ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d00cbf0221e0e..4362e040d2661 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let source = tcx.lookup_item_type(impl_did).ty; let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); - let target = trait_ref.substs.types[1]; + let target = trait_ref.substs.type_at(1); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8a8232535c775..2a989105c9cb4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -172,7 +172,7 @@ fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id, item_substs); - assert!(!item_substs.substs.types.needs_infer()); + assert!(!item_substs.substs.needs_infer()); ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2e655ce38bcc..51a697dad2fd6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -642,8 +642,8 @@ impl Clean for hir::TyParamBound { fn external_path_params(cx: &DocContext, trait_did: Option, has_self: bool, bindings: Vec, substs: &Substs) -> PathParameters { - let lifetimes = substs.regions.iter().filter_map(|v| v.clean(cx)).collect(); - let types = substs.types[has_self as usize..].to_vec(); + let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect(); + let types = substs.types().skip(has_self as usize).cloned().collect::>(); match (trait_did, cx.tcx_opt()) { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C @@ -737,12 +737,11 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { let path = external_path(cx, &tcx.item_name(self.def_id).as_str(), Some(self.def_id), true, vec![], self.substs); - debug!("ty::TraitRef\n substs.types: {:?}\n", - &self.input_types()[1..]); + debug!("ty::TraitRef\n subst: {:?}\n", self.substs); // collect any late bound regions let mut late_bounds = vec![]; - for &ty_s in &self.input_types()[1..] { + for &ty_s in self.input_types().skip(1) { if let ty::TyTuple(ts) = ty_s.sty { for &ty_s in ts { if let ty::TyRef(ref reg, _) = ty_s.sty { @@ -775,9 +774,9 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { impl<'tcx> Clean>> for Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { let mut v = Vec::new(); - v.extend(self.regions.iter().filter_map(|r| r.clean(cx)) + v.extend(self.regions().filter_map(|r| r.clean(cx)) .map(RegionBound)); - v.extend(self.types.iter().map(|t| TraitBound(PolyTrait { + v.extend(self.types().map(|t| TraitBound(PolyTrait { trait_: t.clean(cx), lifetimes: vec![] }, hir::TraitBoundModifier::None))); From dffd238f8b3195982427ba14bc01d47c6da6aedf Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 25 Aug 2016 23:58:52 +0300 Subject: [PATCH 300/768] rustc: pass ty::Region behind an interned 'tcx reference. --- src/librustc/infer/bivariate.rs | 3 +- src/librustc/infer/combine.rs | 4 +- src/librustc/infer/equate.rs | 3 +- src/librustc/infer/error_reporting.rs | 22 +- src/librustc/infer/freshen.rs | 6 +- src/librustc/infer/glb.rs | 3 +- src/librustc/infer/higher_ranked/mod.rs | 66 ++-- src/librustc/infer/lub.rs | 3 +- src/librustc/infer/mod.rs | 25 +- .../infer/region_inference/graphviz.rs | 24 +- src/librustc/infer/region_inference/mod.rs | 346 ++++++++++-------- src/librustc/infer/resolve.rs | 16 +- src/librustc/infer/sub.rs | 3 +- src/librustc/middle/cstore.rs | 2 - src/librustc/middle/expr_use_visitor.rs | 30 +- src/librustc/middle/free_region.rs | 24 +- src/librustc/middle/mem_categorization.rs | 32 +- src/librustc/mir/repr.rs | 2 +- src/librustc/mir/tcx.rs | 3 +- src/librustc/mir/visit.rs | 4 +- src/librustc/traits/fulfill.rs | 9 +- src/librustc/traits/select.rs | 11 +- src/librustc/ty/_match.rs | 3 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/error.rs | 12 +- src/librustc/ty/flags.rs | 6 +- src/librustc/ty/fold.rs | 78 ++-- src/librustc/ty/mod.rs | 59 +-- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 16 +- src/librustc/ty/structural_impls.rs | 50 +-- src/librustc/ty/sty.rs | 15 +- src/librustc/ty/subst.rs | 16 +- src/librustc/ty/util.rs | 6 +- src/librustc/ty/wf.rs | 12 +- src/librustc/util/ppaux.rs | 18 +- src/librustc_borrowck/borrowck/check_loans.rs | 2 +- .../borrowck/gather_loans/lifetime.rs | 21 +- .../borrowck/gather_loans/mod.rs | 8 +- .../borrowck/gather_loans/restrictions.rs | 6 +- src/librustc_borrowck/borrowck/mod.rs | 29 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_driver/test.rs | 27 +- src/librustc_metadata/astencode.rs | 21 +- src/librustc_metadata/csearch.rs | 7 - src/librustc_metadata/decoder.rs | 17 +- src/librustc_metadata/tydecode.rs | 14 +- src/librustc_metadata/tyencode.rs | 6 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 16 +- src/librustc_mir/hair/cx/pattern.rs | 2 +- src/librustc_mir/hair/mod.rs | 8 +- src/librustc_passes/consts.rs | 2 +- src/librustc_passes/rvalues.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/context.rs | 4 +- src/librustc_trans/meth.rs | 2 +- src/librustc_typeck/astconv.rs | 52 +-- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/coercion.rs | 5 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 10 +- src/librustc_typeck/check/regionck.rs | 96 ++--- src/librustc_typeck/check/upvar.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 17 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 8 +- .../constrained_type_params.rs | 4 +- src/librustc_typeck/rscope.rs | 6 +- src/librustc_typeck/variance/constraints.rs | 4 +- src/librustdoc/clean/mod.rs | 6 +- 75 files changed, 711 insertions(+), 664 deletions(-) diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index 125f815feda6f..4acb8b807d594 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -106,7 +106,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } } - fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> { + fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> { Ok(a) } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index b4818f963b3ba..5ce30484ede00 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -329,8 +329,8 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx } } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { // Never make variables for regions bound within the type itself, // nor for erased regions. ty::ReLateBound(..) | diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index e06f7303acb29..bf247acec5a2d 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -79,7 +79,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } } - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 1e053d6bfdab2..9169d299e040b 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, err: &mut DiagnosticBuilder, prefix: &str, - region: ty::Region, + region: &'tcx ty::Region, suffix: &str) { fn item_scope_tag(item: &hir::Item) -> &'static str { match item.node { @@ -120,7 +120,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Some(span)) } - let (description, span) = match region { + let (description, span) = match *region { ty::ReScope(scope) => { let new_string; let unknown_scope = || { @@ -405,12 +405,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn free_regions_from_same_fn<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - sub: Region, - sup: Region) + sub: &'tcx Region, + sup: &'tcx Region) -> Option { debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup); let (scope_id, fr1, fr2) = match (sub, sup) { - (ReFree(fr1), ReFree(fr2)) => { + (&ReFree(fr1), &ReFree(fr2)) => { if fr1.scope != fr2.scope { return None } @@ -602,7 +602,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, bound_kind: GenericKind<'tcx>, - sub: Region) + sub: &'tcx Region) { // FIXME: it would be better to report the first error message // with the span of the parameter itself, rather than the span @@ -616,7 +616,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { format!("the associated type `{}`", p), }; - let mut err = match sub { + let mut err = match *sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? let mut err = struct_span_err!(self.tcx.sess, @@ -667,8 +667,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn report_concrete_failure(&self, origin: SubregionOrigin<'tcx>, - sub: Region, - sup: Region) + sub: &'tcx Region, + sup: &'tcx Region) -> DiagnosticBuilder<'tcx> { match origin { infer::Subtype(trace) => { @@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn report_sub_sup_conflict(&self, var_origin: RegionVariableOrigin, sub_origin: SubregionOrigin<'tcx>, - sub_region: Region, + sub_region: &'tcx Region, sup_origin: SubregionOrigin<'tcx>, - sup_region: Region) { + sup_region: &'tcx Region) { let mut err = self.report_inference_failure(var_origin); self.tcx.note_and_explain_region(&mut err, diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index ecd9759c721b2..beda734ee0d56 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -83,8 +83,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { self.infcx.tcx } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { ty::ReEarlyBound(..) | ty::ReLateBound(..) => { // leave bound regions alone @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::ReEmpty | ty::ReErased => { // replace all free regions with 'erased - ty::ReErased + self.tcx().mk_region(ty::ReErased) } } } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 5dd85a31a9a20..a5709e1880801 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -57,7 +57,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> lattice::super_lattice_tys(self, a, b) } - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 743d6135fbb5b..90be5e935baf1 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -164,7 +164,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { .map(|(&skol, &(br, ref regions))| { let representative = regions.iter() - .filter(|r| !skol_resolution_map.contains_key(r)) + .filter(|&&r| !skol_resolution_map.contains_key(r)) .cloned() .next() .unwrap_or_else(|| { // [1] @@ -268,9 +268,9 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, - r0: ty::Region) - -> ty::Region { + a_map: &FnvHashMap, + r0: &'tcx ty::Region) + -> &'tcx ty::Region { // Regions that pre-dated the LUB computation stay as they are. if !is_var_in_set(new_vars, r0) { assert!(!r0.is_bound()); @@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("generalize_region(r0={:?}): \ replacing with {:?}, tainted={:?}", r0, *a_br, tainted); - return ty::ReLateBound(debruijn, *a_br); + return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br)); } } @@ -364,10 +364,12 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, + a_map: &FnvHashMap, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], - r0: ty::Region) -> ty::Region { + r0: &'tcx ty::Region) + -> &'tcx ty::Region { if !is_var_in_set(new_vars, r0) { assert!(!r0.is_bound()); return r0; @@ -419,7 +421,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { if a_r.is_some() && b_r.is_some() && only_new_vars { // Related to exactly one bound variable from each fn: - return rev_lookup(span, a_map, a_r.unwrap()); + return rev_lookup(infcx, span, a_map, a_r.unwrap()); } else if a_r.is_none() && b_r.is_none() { // Not related to bound variables from either fn: assert!(!r0.is_bound()); @@ -430,13 +432,14 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } } - fn rev_lookup(span: Span, - a_map: &FnvHashMap, - r: ty::Region) -> ty::Region + fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + span: Span, + a_map: &FnvHashMap, + r: &'tcx ty::Region) -> &'tcx ty::Region { for (a_br, a_r) in a_map { if *a_r == r { - return ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br); + return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br)); } } span_bug!( @@ -445,19 +448,21 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { r); } - fn fresh_bound_variable(infcx: &InferCtxt, debruijn: ty::DebruijnIndex) -> ty::Region { + fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + debruijn: ty::DebruijnIndex) + -> &'tcx ty::Region { infcx.region_vars.new_bound(debruijn) } } } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &FnvHashMap) + map: &FnvHashMap) -> Vec { map.iter() - .map(|(_, r)| match *r { + .map(|(_, &r)| match *r { ty::ReVar(r) => { r } - r => { + _ => { span_bug!( fields.trace.origin.span(), "found non-region-vid: {:?}", @@ -467,8 +472,8 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, .collect() } -fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { - match r { +fn is_var_in_set(new_vars: &[ty::RegionVid], r: &ty::Region) -> bool { + match *r { ty::ReVar(ref v) => new_vars.iter().any(|x| x == v), _ => false } @@ -479,13 +484,13 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, mut fldr: F) -> T where T: TypeFoldable<'tcx>, - F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, + F: FnMut(&'tcx ty::Region, ty::DebruijnIndex) -> &'tcx ty::Region, { tcx.fold_regions(unbound_value, &mut false, |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, // because the ones at the current level should have been replaced // with fresh variables - assert!(match region { + assert!(match *region { ty::ReLateBound(..) => false, _ => true }); @@ -497,9 +502,9 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn tainted_regions(&self, snapshot: &CombinedSnapshot, - r: ty::Region, + r: &'tcx ty::Region, directions: TaintDirections) - -> FnvHashSet { + -> FnvHashSet<&'tcx ty::Region> { self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions) } @@ -596,7 +601,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn skolemize_late_bound_regions(&self, binder: &ty::Binder, snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap) + -> (T, SkolemizationMap<'tcx>) where T : TypeFoldable<'tcx> { let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { @@ -619,7 +624,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn leak_check(&self, overly_polymorphic: bool, span: Span, - skol_map: &SkolemizationMap, + skol_map: &SkolemizationMap<'tcx>, snapshot: &CombinedSnapshot) -> RelateResult<'tcx, ()> { @@ -673,7 +678,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for &tainted_region in &incoming_taints { // Each skolemized should only be relatable to itself // or new variables: - match tainted_region { + match *tainted_region { ty::ReVar(vid) => { if new_vars.contains(&vid) { warnings.extend( @@ -742,7 +747,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// to the depth of the predicate, in this case 1, so that the final /// predicate is `for<'a> &'a int : Clone`. pub fn plug_leaks(&self, - skol_map: SkolemizationMap, + skol_map: SkolemizationMap<'tcx>, snapshot: &CombinedSnapshot, value: &T) -> T where T : TypeFoldable<'tcx> @@ -755,7 +760,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // region back to the `ty::BoundRegion` that it originally // represented. Because `leak_check` passed, we know that // these taint sets are mutually disjoint. - let inv_skol_map: FnvHashMap = + let inv_skol_map: FnvHashMap<&'tcx ty::Region, ty::BoundRegion> = skol_map .iter() .flat_map(|(&skol_br, &skol)| { @@ -794,7 +799,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // (which ought not to escape the snapshot, but we // don't check that) or itself assert!( - match r { + match *r { ty::ReVar(_) => true, ty::ReSkolemized(_, ref br1) => br == br1, _ => false, @@ -802,7 +807,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "leak-check would have us replace {:?} with {:?}", r, br); - ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + self.tcx.mk_region(ty::ReLateBound( + ty::DebruijnIndex::new(current_depth - 1), br.clone())) } } }); @@ -826,7 +832,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// /// Note: popping also occurs implicitly as part of `leak_check`. pub fn pop_skolemized(&self, - skol_map: SkolemizationMap, + skol_map: SkolemizationMap<'tcx>, snapshot: &CombinedSnapshot) { debug!("pop_skolemized({:?})", skol_map); diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index ad1b32ffaeb32..7d352be67d32b 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -57,7 +57,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> lattice::super_lattice_tys(self, a, b) } - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1b65b5dae0748..9854cd95397b7 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -177,7 +177,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap = FnvHashMap; +pub type SkolemizationMap<'tcx> = FnvHashMap; /// Why did we require that the two types be related? /// @@ -1123,8 +1123,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_regions(&self, origin: SubregionOrigin<'tcx>, - a: ty::Region, - b: ty::Region) { + a: &'tcx ty::Region, + b: &'tcx ty::Region) { debug!("sub_regions({:?} <: {:?})", a, b); self.region_vars.make_subregion(origin, a, b); } @@ -1147,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn region_outlives_predicate(&self, span: Span, - predicate: &ty::PolyRegionOutlivesPredicate) + predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { @@ -1190,8 +1190,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .new_key(None) } - pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region { - ty::ReVar(self.region_vars.new_region_var(origin)) + pub fn next_region_var(&self, origin: RegionVariableOrigin) + -> &'tcx ty::Region { + self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(origin))) } /// Create a region inference variable for the given @@ -1199,7 +1200,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn region_var_for_def(&self, span: Span, def: &ty::RegionParameterDef) - -> ty::Region { + -> &'tcx ty::Region { self.next_region_var(EarlyBoundRegion(span, def.name)) } @@ -1245,7 +1246,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } - pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { + pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> &'tcx ty::Region { self.region_vars.new_bound(debruijn) } @@ -1530,7 +1531,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, FnvHashMap) + -> (T, FnvHashMap) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( @@ -1576,8 +1577,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn verify_generic_bound(&self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, - a: ty::Region, - bound: VerifyBound) { + a: &'tcx ty::Region, + bound: VerifyBound<'tcx>) { debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, @@ -1666,7 +1667,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.region_maps.temporary_scope(rvalue_id) } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 905ad7c0faa23..1c64ebc0537ae 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -123,7 +123,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, graph_name: String, - map: &'a FnvHashMap>, + map: &'a FnvHashMap, SubregionOrigin<'tcx>>, node_ids: FnvHashMap, } @@ -135,8 +135,8 @@ enum Node { // type Edge = Constraint; #[derive(Clone, PartialEq, Eq, Debug, Copy)] -enum Edge { - Constraint(Constraint), +enum Edge<'tcx> { + Constraint(Constraint<'tcx>), EnclScope(CodeExtent, CodeExtent), } @@ -177,7 +177,7 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { type Node = Node; - type Edge = Edge; + type Edge = Edge<'tcx>; fn graph_id(&self) -> dot::Id { dot::Id::new(&*self.graph_name).unwrap() } @@ -214,11 +214,11 @@ fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { Constraint::ConstrainVarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), Constraint::ConstrainRegSubVar(r_1, rv_2) => - (Node::Region(r_1), Node::RegionVid(rv_2)), + (Node::Region(*r_1), Node::RegionVid(rv_2)), Constraint::ConstrainVarSubReg(rv_1, r_2) => - (Node::RegionVid(rv_1), Node::Region(r_2)), + (Node::RegionVid(rv_1), Node::Region(*r_2)), Constraint::ConstrainRegSubReg(r_1, r_2) => - (Node::Region(r_1), Node::Region(r_2)), + (Node::Region(*r_1), Node::Region(*r_2)), } } @@ -234,7 +234,7 @@ fn edge_to_nodes(e: &Edge) -> (Node, Node) { impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { type Node = Node; - type Edge = Edge; + type Edge = Edge<'tcx>; fn nodes(&self) -> dot::Nodes { let mut set = FnvHashSet(); for node in self.node_ids.keys() { @@ -243,26 +243,26 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { debug!("constraint graph has {} nodes", set.len()); set.into_iter().collect() } - fn edges(&self) -> dot::Edges { + fn edges(&self) -> dot::Edges> { debug!("constraint graph has {} edges", self.map.len()); let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup))); debug!("region graph has {} edges", v.len()); Cow::Owned(v) } - fn source(&self, edge: &Edge) -> Node { + fn source(&self, edge: &Edge<'tcx>) -> Node { let (n1, _) = edge_to_nodes(edge); debug!("edge {:?} has source {:?}", edge, n1); n1 } - fn target(&self, edge: &Edge) -> Node { + fn target(&self, edge: &Edge<'tcx>) -> Node { let (_, n2) = edge_to_nodes(edge); debug!("edge {:?} has target {:?}", edge, n2); n2 } } -pub type ConstraintMap<'tcx> = FnvHashMap>; +pub type ConstraintMap<'tcx> = FnvHashMap, SubregionOrigin<'tcx>>; fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, map: &ConstraintMap<'tcx>, diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index d3b4afa2cee79..b3693ae1e21ad 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -39,22 +39,22 @@ mod graphviz; // A constraint that influences the inference process. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum Constraint { +pub enum Constraint<'tcx> { // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), // Concrete region is subregion of region variable - ConstrainRegSubVar(Region, RegionVid), + ConstrainRegSubVar(&'tcx Region, RegionVid), // Region variable is subregion of concrete region. This does not // directly affect inference, but instead is checked after // inference is complete. - ConstrainVarSubReg(RegionVid, Region), + ConstrainVarSubReg(RegionVid, &'tcx Region), // A constraint where neither side is a variable. This does not // directly affect inference, but instead is checked after // inference is complete. - ConstrainRegSubReg(Region, Region), + ConstrainRegSubReg(&'tcx Region, &'tcx Region), } // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or @@ -66,8 +66,8 @@ pub enum Constraint { pub struct Verify<'tcx> { kind: GenericKind<'tcx>, origin: SubregionOrigin<'tcx>, - region: Region, - bound: VerifyBound, + region: &'tcx Region, + bound: VerifyBound<'tcx>, } #[derive(Copy, Clone, PartialEq, Eq)] @@ -80,36 +80,36 @@ pub enum GenericKind<'tcx> { // particular region (let's call it `'min`) meets some bound. // The bound is described the by the following grammar: #[derive(Debug)] -pub enum VerifyBound { +pub enum VerifyBound<'tcx> { // B = exists {R} --> some 'r in {R} must outlive 'min // // Put another way, the subject value is known to outlive all // regions in {R}, so if any of those outlives 'min, then the // bound is met. - AnyRegion(Vec), + AnyRegion(Vec<&'tcx Region>), // B = forall {R} --> all 'r in {R} must outlive 'min // // Put another way, the subject value is known to outlive some // region in {R}, so if all of those outlives 'min, then the bound // is met. - AllRegions(Vec), + AllRegions(Vec<&'tcx Region>), // B = exists {B} --> 'min must meet some bound b in {B} - AnyBound(Vec), + AnyBound(Vec>), // B = forall {B} --> 'min must meet all bounds b in {B} - AllBounds(Vec), + AllBounds(Vec>), } #[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct TwoRegions { - a: Region, - b: Region, +pub struct TwoRegions<'tcx> { + a: &'tcx Region, + b: &'tcx Region, } #[derive(Copy, Clone, PartialEq)] -pub enum UndoLogEntry { +pub enum UndoLogEntry<'tcx> { /// Pushed when we start a snapshot. OpenSnapshot, @@ -122,7 +122,7 @@ pub enum UndoLogEntry { AddVar(RegionVid), /// We added the given `constraint` - AddConstraint(Constraint), + AddConstraint(Constraint<'tcx>), /// We added the given `verify` AddVerify(usize), @@ -131,7 +131,7 @@ pub enum UndoLogEntry { AddGiven(ty::FreeRegion, ty::RegionVid), /// We added a GLB/LUB "combinaton variable" - AddCombination(CombineMapType, TwoRegions), + AddCombination(CombineMapType, TwoRegions<'tcx>), /// During skolemization, we sometimes purge entries from the undo /// log in a kind of minisnapshot (unlike other snapshots, this @@ -153,13 +153,13 @@ pub enum RegionResolutionError<'tcx> { /// `ConcreteFailure(o, a, b)`: /// /// `o` requires that `a <= b`, but this does not hold - ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), + ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region), /// `GenericBoundFailure(p, s, a) /// /// The parameter/associated-type `p` must be known to outlive the lifetime /// `a` (but none of the known bounds are sufficient). - GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region), + GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, &'tcx Region), /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: /// @@ -168,9 +168,9 @@ pub enum RegionResolutionError<'tcx> { /// `sub_r <= sup_r` does not hold. SubSupConflict(RegionVariableOrigin, SubregionOrigin<'tcx>, - Region, + &'tcx Region, SubregionOrigin<'tcx>, - Region), + &'tcx Region), /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive /// more specific errors message by suggesting to the user where they @@ -182,7 +182,7 @@ pub enum RegionResolutionError<'tcx> { #[derive(Clone, Debug)] pub enum ProcessedErrorOrigin<'tcx> { - ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), + ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region), VariableFailure(RegionVariableOrigin), } @@ -213,7 +213,7 @@ impl SameRegions { } } -pub type CombineMap = FnvHashMap; +pub type CombineMap<'tcx> = FnvHashMap, RegionVid>; pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -222,7 +222,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // Constraints of the form `A <= B` introduced by the region // checker. Here at least one of `A` and `B` must be a region // variable. - constraints: RefCell>>, + constraints: RefCell, SubregionOrigin<'tcx>>>, // A "verify" is something that we need to verify after inference is // done, but which does not directly affect inference in any way. @@ -250,8 +250,8 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // a bit of a hack but seems to work. givens: RefCell>, - lubs: RefCell, - glbs: RefCell, + lubs: RefCell>, + glbs: RefCell>, skolemization_count: Cell, bound_count: Cell, @@ -264,12 +264,12 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // otherwise we end up adding entries for things like the lower // bound on a variable and so forth, which can never be rolled // back. - undo_log: RefCell>, + undo_log: RefCell>>, unification_table: RefCell>, // This contains the results of inference. It begins as an empty // option and only acquires a value after inference is complete. - values: RefCell>>, + values: RefCell>>>, } pub struct RegionSnapshot { @@ -303,14 +303,14 @@ impl TaintDirections { } } -struct TaintSet { +struct TaintSet<'tcx> { directions: TaintDirections, - regions: FnvHashSet + regions: FnvHashSet<&'tcx ty::Region> } -impl TaintSet { +impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { fn new(directions: TaintDirections, - initial_region: ty::Region) + initial_region: &'tcx ty::Region) -> Self { let mut regions = FnvHashSet(); regions.insert(initial_region); @@ -318,8 +318,9 @@ impl TaintSet { } fn fixed_point(&mut self, - undo_log: &[UndoLogEntry], - verifys: &[Verify]) { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + undo_log: &[UndoLogEntry<'tcx>], + verifys: &[Verify<'tcx>]) { let mut prev_len = 0; while prev_len < self.len() { debug!("tainted: prev_len = {:?} new_len = {:?}", @@ -330,19 +331,21 @@ impl TaintSet { for undo_entry in undo_log { match undo_entry { &AddConstraint(ConstrainVarSubVar(a, b)) => { - self.add_edge(ReVar(a), ReVar(b)); + self.add_edge(tcx.mk_region(ReVar(a)), + tcx.mk_region(ReVar(b))); } &AddConstraint(ConstrainRegSubVar(a, b)) => { - self.add_edge(a, ReVar(b)); + self.add_edge(a, tcx.mk_region(ReVar(b))); } &AddConstraint(ConstrainVarSubReg(a, b)) => { - self.add_edge(ReVar(a), b); + self.add_edge(tcx.mk_region(ReVar(a)), b); } &AddConstraint(ConstrainRegSubReg(a, b)) => { self.add_edge(a, b); } &AddGiven(a, b) => { - self.add_edge(ReFree(a), ReVar(b)); + self.add_edge(tcx.mk_region(ReFree(a)), + tcx.mk_region(ReVar(b))); } &AddVerify(i) => { verifys[i].bound.for_each_region(&mut |b| { @@ -359,7 +362,7 @@ impl TaintSet { } } - fn into_set(self) -> FnvHashSet { + fn into_set(self) -> FnvHashSet<&'tcx ty::Region> { self.regions } @@ -368,8 +371,8 @@ impl TaintSet { } fn add_edge(&mut self, - source: ty::Region, - target: ty::Region) { + source: &'tcx ty::Region, + target: &'tcx ty::Region) { if self.directions.incoming { if self.regions.contains(&target) { self.regions.insert(source); @@ -450,7 +453,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { .rollback_to(snapshot.region_snapshot); } - pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry) { + pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry<'tcx>) { match undo_entry { OpenSnapshot => { panic!("Failure to observe stack discipline"); @@ -529,13 +532,14 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// The `snapshot` argument to this function is not really used; /// it's just there to make it explicit which snapshot bounds the /// skolemized region that results. It should always be the top-most snapshot. - pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region { + pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) + -> &'tcx Region { assert!(self.in_snapshot()); assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); let sc = self.skolemization_count.get(); self.skolemization_count.set(sc + 1); - ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br) + self.tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)) } /// Removes all the edges to/from the skolemized regions that are @@ -543,7 +547,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// completes to remove all trace of the skolemized regions /// created in that time. pub fn pop_skolemized(&self, - skols: &FnvHashSet, + skols: &FnvHashSet<&'tcx ty::Region>, snapshot: &RegionSnapshot) { debug!("pop_skolemized_regions(skols={:?})", skols); @@ -566,7 +570,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { skols.len()); debug_assert! { skols.iter() - .all(|k| match *k { + .all(|&k| match *k { ty::ReSkolemized(index, _) => index.index >= first_to_pop && index.index < last_to_pop, @@ -597,9 +601,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { self.skolemization_count.set(snapshot.skolemization_count); return; - fn kill_constraint(skols: &FnvHashSet, - undo_entry: &UndoLogEntry) - -> bool { + fn kill_constraint<'tcx>(skols: &FnvHashSet<&'tcx ty::Region>, + undo_entry: &UndoLogEntry<'tcx>) + -> bool { match undo_entry { &AddConstraint(ConstrainVarSubVar(_, _)) => false, @@ -626,7 +630,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } - pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region { + pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> &'tcx Region { // Creates a fresh bound variable for use in GLB computations. // See discussion of GLB computation in the large comment at // the top of this file for more details. @@ -652,14 +656,14 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { bug!("rollover in RegionInference new_bound()"); } - ReLateBound(debruijn, BrFresh(sc)) + self.tcx.mk_region(ReLateBound(debruijn, BrFresh(sc))) } fn values_are_none(&self) -> bool { self.values.borrow().is_none() } - fn add_constraint(&self, constraint: Constraint, origin: SubregionOrigin<'tcx>) { + fn add_constraint(&self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -704,20 +708,26 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) { + pub fn make_eqregion(&self, + origin: SubregionOrigin<'tcx>, + sub: &'tcx Region, + sup: &'tcx Region) { if sub != sup { // Eventually, it would be nice to add direct support for // equating regions. self.make_subregion(origin.clone(), sub, sup); self.make_subregion(origin, sup, sub); - if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) { + if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) { self.unification_table.borrow_mut().union(sub, sup); } } } - pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) { + pub fn make_subregion(&self, + origin: SubregionOrigin<'tcx>, + sub: &'tcx Region, + sup: &'tcx Region) { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -727,26 +737,26 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { origin); match (sub, sup) { - (ReEarlyBound(..), _) | - (ReLateBound(..), _) | - (_, ReEarlyBound(..)) | - (_, ReLateBound(..)) => { + (&ReEarlyBound(..), _) | + (&ReLateBound(..), _) | + (_, &ReEarlyBound(..)) | + (_, &ReLateBound(..)) => { span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup); } - (_, ReStatic) => { + (_, &ReStatic) => { // all regions are subregions of static, so we can ignore this } - (ReVar(sub_id), ReVar(sup_id)) => { + (&ReVar(sub_id), &ReVar(sup_id)) => { self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } - (r, ReVar(sup_id)) => { - self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); + (_, &ReVar(sup_id)) => { + self.add_constraint(ConstrainRegSubVar(sub, sup_id), origin); } - (ReVar(sub_id), r) => { - self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); + (&ReVar(sub_id), _) => { + self.add_constraint(ConstrainVarSubReg(sub_id, sup), origin); } _ => { self.add_constraint(ConstrainRegSubReg(sub, sup), origin); @@ -758,8 +768,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn verify_generic_bound(&self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, - sub: Region, - bound: VerifyBound) { + sub: &'tcx Region, + bound: VerifyBound<'tcx>) { self.add_verify(Verify { kind: kind, origin: origin, @@ -768,29 +778,43 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { }); } - pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region { + pub fn lub_regions(&self, + origin: SubregionOrigin<'tcx>, + a: &'tcx Region, + b: &'tcx Region) + -> &'tcx Region { // cannot add constraints once regions are resolved assert!(self.values_are_none()); debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b); - if a == ty::ReStatic || b == ty::ReStatic { - ReStatic // nothing lives longer than static - } else if a == b { - a // LUB(a,a) = a - } else { - self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { - this.make_subregion(origin.clone(), old_r, new_r) - }) + match (a, b) { + (r @ &ReStatic, _) | (_, r @ &ReStatic) => { + r // nothing lives longer than static + } + + _ if a == b => { + a // LUB(a,a) = a + } + + _ => { + self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { + this.make_subregion(origin.clone(), old_r, new_r) + }) + } } } - pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region { + pub fn glb_regions(&self, + origin: SubregionOrigin<'tcx>, + a: &'tcx Region, + b: &'tcx Region) + -> &'tcx Region { // cannot add constraints once regions are resolved assert!(self.values_are_none()); debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b); match (a, b) { - (ReStatic, r) | (r, ReStatic) => { + (&ReStatic, r) | (r, &ReStatic) => { r // static lives longer than everything else } @@ -806,7 +830,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - pub fn resolve_var(&self, rid: RegionVid) -> ty::Region { + pub fn resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region { match *self.values.borrow() { None => { span_bug!((*self.var_origins.borrow())[rid.index as usize].span(), @@ -814,18 +838,19 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { been computed!") } Some(ref values) => { - let r = lookup(values, rid); + let r = lookup(self.tcx, values, rid); debug!("resolve_var({:?}) = {:?}", rid, r); r } } } - pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region { - ty::ReVar(self.unification_table.borrow_mut().find_value(rid).min_vid) + pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region { + let vid = self.unification_table.borrow_mut().find_value(rid).min_vid; + self.tcx.mk_region(ty::ReVar(vid)) } - fn combine_map(&self, t: CombineMapType) -> &RefCell { + fn combine_map(&self, t: CombineMapType) -> &RefCell> { match t { Glb => &self.glbs, Lub => &self.lubs, @@ -834,26 +859,26 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn combine_vars(&self, t: CombineMapType, - a: Region, - b: Region, + a: &'tcx Region, + b: &'tcx Region, origin: SubregionOrigin<'tcx>, mut relate: F) - -> Region - where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region, Region) + -> &'tcx Region + where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, &'tcx Region, &'tcx Region) { let vars = TwoRegions { a: a, b: b }; if let Some(&c) = self.combine_map(t).borrow().get(&vars) { - return ReVar(c); + return self.tcx.mk_region(ReVar(c)); } let c = self.new_region_var(MiscVariable(origin.span())); self.combine_map(t).borrow_mut().insert(vars, c); if self.in_snapshot() { self.undo_log.borrow_mut().push(AddCombination(t, vars)); } - relate(self, a, ReVar(c)); - relate(self, b, ReVar(c)); + relate(self, a, self.tcx.mk_region(ReVar(c))); + relate(self, b, self.tcx.mk_region(ReVar(c))); debug!("combine_vars() c={:?}", c); - ReVar(c) + self.tcx.mk_region(ReVar(c)) } pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec { @@ -878,9 +903,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// related to other regions. pub fn tainted(&self, mark: &RegionSnapshot, - r0: Region, + r0: &'tcx Region, directions: TaintDirections) - -> FnvHashSet { + -> FnvHashSet<&'tcx ty::Region> { debug!("tainted(mark={:?}, r0={:?}, directions={:?})", mark, r0, directions); @@ -888,7 +913,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // edges and add any new regions we find to result_set. This // is not a terribly efficient implementation. let mut taint_set = TaintSet::new(directions, r0); - taint_set.fixed_point(&self.undo_log.borrow()[mark.length..], + taint_set.fixed_point(self.tcx, + &self.undo_log.borrow()[mark.length..], &self.verifys.borrow()); debug!("tainted: result={:?}", taint_set.regions); return taint_set.into_set(); @@ -910,26 +936,30 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { errors } - fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region { + fn lub_concrete_regions(&self, + free_regions: &FreeRegionMap, + a: &'tcx Region, + b: &'tcx Region) + -> &'tcx Region { match (a, b) { - (ReLateBound(..), _) | - (_, ReLateBound(..)) | - (ReEarlyBound(..), _) | - (_, ReEarlyBound(..)) | - (ReErased, _) | - (_, ReErased) => { + (&ReLateBound(..), _) | + (_, &ReLateBound(..)) | + (&ReEarlyBound(..), _) | + (_, &ReEarlyBound(..)) | + (&ReErased, _) | + (_, &ReErased) => { bug!("cannot relate region: LUB({:?}, {:?})", a, b); } - (ReStatic, _) | (_, ReStatic) => { - ReStatic // nothing lives longer than static + (r @ &ReStatic, _) | (_, r @ &ReStatic) => { + r // nothing lives longer than static } - (ReEmpty, r) | (r, ReEmpty) => { + (&ReEmpty, r) | (r, &ReEmpty) => { r // everything lives longer than empty } - (ReVar(v_id), _) | (_, ReVar(v_id)) => { + (&ReVar(v_id), _) | (_, &ReVar(v_id)) => { span_bug!((*self.var_origins.borrow())[v_id.index as usize].span(), "lub_concrete_regions invoked with non-concrete \ regions: {:?}, {:?}", @@ -937,9 +967,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { b); } - (ReFree(ref fr), ReScope(s_id)) | - (ReScope(s_id), ReFree(ref fr)) => { - let f = ReFree(*fr); + (&ReFree(fr), &ReScope(s_id)) | + (&ReScope(s_id), &ReFree(fr)) => { // A "free" region can be interpreted as "some region // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: @@ -949,33 +978,34 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // if the free region's scope `fr.scope_id` is bigger than // the scope region `s_id`, then the LUB is the free // region itself: - f + self.tcx.mk_region(ReFree(fr)) } else { // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: - ReStatic + self.tcx.mk_region(ReStatic) } } - (ReScope(a_id), ReScope(b_id)) => { + (&ReScope(a_id), &ReScope(b_id)) => { // The region corresponding to an outer block is a // subtype of the region corresponding to an inner // block. - ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id)) + self.tcx.mk_region(ReScope( + self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))) } - (ReFree(a_fr), ReFree(b_fr)) => { - free_regions.lub_free_regions(a_fr, b_fr) + (&ReFree(a_fr), &ReFree(b_fr)) => { + self.tcx.mk_region(free_regions.lub_free_regions(a_fr, b_fr)) } // For these types, we cannot define any additional // relationship: - (ReSkolemized(..), _) | - (_, ReSkolemized(..)) => { + (&ReSkolemized(..), _) | + (_, &ReSkolemized(..)) => { if a == b { a } else { - ReStatic + self.tcx.mk_region(ReStatic) } } } @@ -985,24 +1015,24 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // ______________________________________________________________________ #[derive(Copy, Clone, Debug)] -pub enum VarValue { - Value(Region), +pub enum VarValue<'tcx> { + Value(&'tcx Region), ErrorValue, } struct RegionAndOrigin<'tcx> { - region: Region, + region: &'tcx Region, origin: SubregionOrigin<'tcx>, } -type RegionGraph = graph::Graph<(), Constraint>; +type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>; impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn infer_variable_values(&self, free_regions: &FreeRegionMap, errors: &mut Vec>, subject: ast::NodeId) - -> Vec { + -> Vec> { let mut var_data = self.construct_var_data(); // Dorky hack to cause `dump_constraints` to only get called @@ -1020,9 +1050,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { var_data } - fn construct_var_data(&self) -> Vec { + fn construct_var_data(&self) -> Vec> { (0..self.num_vars() as usize) - .map(|_| Value(ty::ReEmpty)) + .map(|_| Value(self.tcx.mk_region(ty::ReEmpty))) .collect() } @@ -1059,7 +1089,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue]) { + fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue<'tcx>]) { self.iterate_until_fixed_point("Expansion", |constraint, origin| { debug!("expansion: constraint={:?} origin={:?}", constraint, origin); @@ -1089,9 +1119,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn expand_node(&self, free_regions: &FreeRegionMap, - a_region: Region, + a_region: &'tcx Region, b_vid: RegionVid, - b_data: &mut VarValue) + b_data: &mut VarValue<'tcx>) -> bool { debug!("expand_node({:?}, {:?} == {:?})", a_region, @@ -1099,7 +1129,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { b_data); // Check if this relationship is implied by a given. - match a_region { + match *a_region { ty::ReFree(fr) => { if self.givens.borrow().contains(&(fr, b_vid)) { debug!("given"); @@ -1136,7 +1166,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// and check that they are satisfied. fn collect_errors(&self, free_regions: &FreeRegionMap, - var_data: &mut Vec, + var_data: &mut Vec>, errors: &mut Vec>) { let constraints = self.constraints.borrow(); for (constraint, origin) in constraints.iter() { @@ -1192,7 +1222,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { for verify in self.verifys.borrow().iter() { debug!("collect_errors: verify={:?}", verify); - let sub = normalize(var_data, verify.region); + let sub = normalize(self.tcx, var_data, verify.region); if verify.bound.is_met(self.tcx, free_regions, var_data, sub) { continue; } @@ -1213,8 +1243,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// and create a `RegionResolutionError` for each of them. fn collect_var_errors(&self, free_regions: &FreeRegionMap, - var_data: &[VarValue], - graph: &RegionGraph, + var_data: &[VarValue<'tcx>], + graph: &RegionGraph<'tcx>, errors: &mut Vec>) { debug!("collect_var_errors"); @@ -1271,7 +1301,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - fn construct_graph(&self) -> RegionGraph { + fn construct_graph(&self) -> RegionGraph<'tcx> { let num_vars = self.num_vars(); let constraints = self.constraints.borrow(); @@ -1315,7 +1345,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn collect_error_for_expanding_node(&self, free_regions: &FreeRegionMap, - graph: &RegionGraph, + graph: &RegionGraph<'tcx>, dup_vec: &mut [u32], node_idx: RegionVid, errors: &mut Vec>) { @@ -1339,9 +1369,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // the user will more likely get a specific suggestion. fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { match (a.region, b.region) { - (ReFree(..), ReFree(..)) => Equal, - (ReFree(..), _) => Less, - (_, ReFree(..)) => Greater, + (&ReFree(..), &ReFree(..)) => Equal, + (&ReFree(..), _) => Less, + (_, &ReFree(..)) => Greater, (_, _) => Equal, } } @@ -1378,7 +1408,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } fn collect_concrete_regions(&self, - graph: &RegionGraph, + graph: &RegionGraph<'tcx>, orig_node_idx: RegionVid, dir: Direction, dup_vec: &mut [u32]) @@ -1423,7 +1453,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn process_edges<'a, 'gcx, 'tcx>(this: &RegionVarBindings<'a, 'gcx, 'tcx>, state: &mut WalkState<'tcx>, - graph: &RegionGraph, + graph: &RegionGraph<'tcx>, source_vid: RegionVid, dir: Direction) { debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); @@ -1460,7 +1490,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } fn iterate_until_fixed_point(&self, tag: &str, mut body: F) - where F: FnMut(&Constraint, &SubregionOrigin<'tcx>) -> bool + where F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool { let mut iteration = 0; let mut changed = true; @@ -1481,17 +1511,23 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } -fn normalize(values: &Vec, r: ty::Region) -> ty::Region { - match r { - ty::ReVar(rid) => lookup(values, rid), +fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + values: &Vec>, + r: &'tcx ty::Region) + -> &'tcx ty::Region { + match *r { + ty::ReVar(rid) => lookup(tcx, values, rid), _ => r, } } -fn lookup(values: &Vec, rid: ty::RegionVid) -> ty::Region { +fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + values: &Vec>, + rid: ty::RegionVid) + -> &'tcx ty::Region { match values[rid.index as usize] { Value(r) => r, - ErrorValue => ReStatic, // Previously reported error. + ErrorValue => tcx.mk_region(ReStatic), // Previously reported error. } } @@ -1535,8 +1571,8 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> { } } -impl<'a, 'gcx, 'tcx> VerifyBound { - fn for_each_region(&self, f: &mut FnMut(ty::Region)) { +impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> { + fn for_each_region(&self, f: &mut FnMut(&'tcx ty::Region)) { match self { &VerifyBound::AnyRegion(ref rs) | &VerifyBound::AllRegions(ref rs) => for &r in rs { @@ -1552,7 +1588,7 @@ impl<'a, 'gcx, 'tcx> VerifyBound { pub fn must_hold(&self) -> bool { match self { - &VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic), + &VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic), &VerifyBound::AllRegions(ref bs) => bs.is_empty(), &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()), &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()), @@ -1562,13 +1598,13 @@ impl<'a, 'gcx, 'tcx> VerifyBound { pub fn cannot_hold(&self) -> bool { match self { &VerifyBound::AnyRegion(ref bs) => bs.is_empty(), - &VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty), + &VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty), &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()), &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()), } } - pub fn or(self, vb: VerifyBound) -> VerifyBound { + pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { if self.must_hold() || vb.cannot_hold() { self } else if self.cannot_hold() || vb.must_hold() { @@ -1578,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> VerifyBound { } } - pub fn and(self, vb: VerifyBound) -> VerifyBound { + pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { if self.must_hold() && vb.must_hold() { self } else if self.cannot_hold() && vb.cannot_hold() { @@ -1590,18 +1626,18 @@ impl<'a, 'gcx, 'tcx> VerifyBound { fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, free_regions: &FreeRegionMap, - var_values: &Vec, - min: ty::Region) + var_values: &Vec>, + min: &'tcx ty::Region) -> bool { match self { &VerifyBound::AnyRegion(ref rs) => rs.iter() - .map(|&r| normalize(var_values, r)) + .map(|&r| normalize(tcx, var_values, r)) .any(|r| free_regions.is_subregion_of(tcx, min, r)), &VerifyBound::AllRegions(ref rs) => rs.iter() - .map(|&r| normalize(var_values, r)) + .map(|&r| normalize(tcx, var_values, r)) .all(|r| free_regions.is_subregion_of(tcx, min, r)), &VerifyBound::AnyBound(ref bs) => diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 5f550b427e21a..357a03a2ffd7c 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -72,10 +72,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv } } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid), - _ => r, + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { + ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid), + _ => r, } } } @@ -138,10 +138,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> } } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { - ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid), - _ => r, + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { + ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid), + _ => r, } } } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 2f7f5254727db..159de2faced57 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -107,7 +107,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } } - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); // FIXME -- we have more fine-grained information available diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 92e1b0681cc7e..381a86a42d482 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -198,7 +198,6 @@ pub trait CrateStore<'tcx> { fn is_default_impl(&self, impl_did: DefId) -> bool; fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool; fn is_foreign_item(&self, did: DefId) -> bool; - fn is_static_method(&self, did: DefId) -> bool; fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; fn is_typedef(&self, did: DefId) -> bool; @@ -391,7 +390,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { bug!("is_extern_item") } fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } - fn is_static_method(&self, did: DefId) -> bool { bug!("is_static_method") } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 87463055a276a..798702e6fd657 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -76,7 +76,7 @@ pub trait Delegate<'tcx> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt<'tcx>, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, bk: ty::BorrowKind, loan_cause: LoanCause); @@ -301,11 +301,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { for arg in &decl.inputs { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); - let fn_body_scope = self.tcx().region_maps.node_extent(body.id); + let fn_body_scope_r = self.tcx().node_scope_region(body.id); let arg_cmt = self.mc.cat_rvalue( arg.id, arg.pat.span, - ty::ReScope(fn_body_scope), // Args live only as long as the fn body. + fn_body_scope_r, // Args live only as long as the fn body. arg_ty); self.walk_irrefutable_pat(arg_cmt, &arg.pat); @@ -352,7 +352,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn borrow_expr(&mut self, expr: &hir::Expr, - r: ty::Region, + r: &'tcx ty::Region, bk: ty::BorrowKind, cause: LoanCause) { debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})", @@ -431,7 +431,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprMatch(ref discr, ref arms, _) => { let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); - self.borrow_expr(&discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant); + let r = self.tcx().mk_region(ty::ReEmpty); + self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); // treatment of the discriminant is handled while walking the arms. for arm in arms { @@ -449,7 +450,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let expr_ty = return_if_err!(self.mc.infcx.node_ty(expr.id)); - if let ty::TyRef(&r, _) = expr_ty.sty { + if let ty::TyRef(r, _) = expr_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); self.borrow_expr(&base, r, bk, AddrOf); } @@ -557,7 +558,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let callee_ty = return_if_err!(self.mc.infcx.expr_ty_adjusted(callee)); debug!("walk_callee: callee={:?} callee_ty={:?}", callee, callee_ty); - let call_scope = self.tcx().region_maps.node_extent(call.id); match callee_ty.sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { self.consume_expr(callee); @@ -578,14 +578,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; match overloaded_call_type { FnMutOverloadedCall => { + let call_scope_r = self.tcx().node_scope_region(call.id); self.borrow_expr(callee, - ty::ReScope(call_scope), + call_scope_r, ty::MutBorrow, ClosureInvocation); } FnOverloadedCall => { + let call_scope_r = self.tcx().node_scope_region(call.id); self.borrow_expr(callee, - ty::ReScope(call_scope), + call_scope_r, ty::ImmBorrow, ClosureInvocation); } @@ -761,7 +763,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; let bk = ty::BorrowKind::from_mutbl(m); self.delegate.borrow(expr.id, expr.span, cmt, - *r, bk, AutoRef); + r, bk, AutoRef); } } } @@ -822,7 +824,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.delegate.borrow(expr.id, expr.span, cmt_base, - *r, + r, ty::BorrowKind::from_mutbl(m), AutoRef); } @@ -835,7 +837,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Converting from a &T to *T (or &mut T to *mut T) is // treated as borrowing it for the enclosing temporary // scope. - let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); + let r = self.tcx().node_scope_region(expr.id); self.delegate.borrow(expr.id, expr.span, @@ -890,7 +892,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // methods are implicitly autoref'd which sadly does not use // adjustments, so we must hardcode the borrow here. - let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); + let r = self.tcx().node_scope_region(expr.id); let bk = ty::ImmBorrow; for &arg in &rhs { @@ -979,7 +981,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // It is also a borrow or copy/move of the value being matched. match bmode { hir::BindByRef(m) => { - if let ty::TyRef(&r, _) = pat_ty.sty { + if let ty::TyRef(r, _) = pat_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding); } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index e4ce89767139a..8193d062631c1 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -37,7 +37,7 @@ impl FreeRegionMap { for implied_bound in implied_bounds { debug!("implied bound: {:?}", implied_bound); match *implied_bound { - ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => { + ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), &ty::ReFree(free_b)) => { self.relate_free_regions(free_a, free_b); } ImpliedBound::RegionSubRegion(..) | @@ -65,9 +65,9 @@ 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)) => { + (&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); } @@ -122,26 +122,26 @@ impl FreeRegionMap { /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs. pub fn is_subregion_of(&self, tcx: TyCtxt, - sub_region: ty::Region, - super_region: ty::Region) + sub_region: &ty::Region, + super_region: &ty::Region) -> bool { let result = sub_region == super_region || { match (sub_region, super_region) { - (ty::ReEmpty, _) | - (_, ty::ReStatic) => + (&ty::ReEmpty, _) | + (_, &ty::ReStatic) => true, - (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => + (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) => tcx.region_maps.is_subscope_of(sub_scope, super_scope), - (ty::ReScope(sub_scope), ty::ReFree(fr)) => + (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => tcx.region_maps.is_subscope_of(sub_scope, fr.scope) || self.is_static(fr), - (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => + (&ty::ReFree(sub_fr), &ty::ReFree(super_fr)) => self.sub_free_region(sub_fr, super_fr), - (ty::ReStatic, ty::ReFree(sup_fr)) => + (&ty::ReStatic, &ty::ReFree(sup_fr)) => self.is_static(sup_fr), _ => diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 676e456dcea94..a74bdb02044de 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -90,11 +90,11 @@ use std::rc::Rc; #[derive(Clone, PartialEq)] pub enum Categorization<'tcx> { - Rvalue(ty::Region), // temporary val, argument is its scope + Rvalue(&'tcx ty::Region), // temporary val, argument is its scope StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable - Deref(cmt<'tcx>, usize, PointerKind), // deref of a ptr + Deref(cmt<'tcx>, usize, PointerKind<'tcx>), // deref of a ptr Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1) @@ -110,18 +110,18 @@ pub struct Upvar { // different kinds of pointers: #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub enum PointerKind { +pub enum PointerKind<'tcx> { /// `Box` Unique, /// `&T` - BorrowedPtr(ty::BorrowKind, ty::Region), + BorrowedPtr(ty::BorrowKind, &'tcx ty::Region), /// `*T` UnsafePtr(hir::Mutability), /// Implicit deref of the `&T` that results from an overloaded index `[]`. - Implicit(ty::BorrowKind, ty::Region), + Implicit(ty::BorrowKind, &'tcx ty::Region), } // We use the term "interior" to mean "something reachable from the @@ -198,8 +198,8 @@ pub type cmt<'tcx> = Rc>; // We pun on *T to mean both actual deref of a ptr as well // as accessing of components: #[derive(Copy, Clone)] -pub enum deref_kind { - deref_ptr(PointerKind), +pub enum deref_kind<'tcx> { + deref_ptr(PointerKind<'tcx>), deref_interior(InteriorKind), } @@ -216,7 +216,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { ty::TyRef(r, mt) => { let kind = ty::BorrowKind::from_mutbl(mt.mutbl); - Ok(deref_ptr(BorrowedPtr(kind, *r))) + Ok(deref_ptr(BorrowedPtr(kind, r))) } ty::TyRawPtr(ref mt) => { @@ -767,13 +767,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; // Region of environment pointer - let env_region = ty::ReFree(ty::FreeRegion { + let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion { // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. scope: self.tcx().region_maps.item_extent(fn_body_id), bound_region: ty::BrEnv - }); + })); let env_ptr = BorrowedPtr(env_borrow_kind, env_region); @@ -817,11 +817,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { /// Returns the lifetime of a temporary created by expr with id `id`. /// This could be `'static` if `id` is part of a constant expression. - pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region { - match self.infcx.temporary_scope(id) { + pub fn temporary_scope(&self, id: ast::NodeId) -> &'tcx ty::Region { + self.tcx().mk_region(match self.infcx.temporary_scope(id) { Some(scope) => ty::ReScope(scope), None => ty::ReStatic - } + }) } pub fn cat_rvalue_node(&self, @@ -845,7 +845,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) { self.temporary_scope(id) } else { - ty::ReStatic + self.tcx().mk_region(ty::ReStatic) }; let ret = self.cat_rvalue(id, span, re, expr_ty); debug!("cat_rvalue_node ret {:?}", ret); @@ -855,7 +855,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn cat_rvalue(&self, cmt_id: ast::NodeId, span: Span, - temp_scope: ty::Region, + temp_scope: &'tcx ty::Region, expr_ty: Ty<'tcx>) -> cmt<'tcx> { let ret = Rc::new(cmt_ { id:cmt_id, @@ -1480,7 +1480,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str { } } -impl fmt::Debug for PointerKind { +impl<'tcx> fmt::Debug for PointerKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Unique => write!(f, "Box"), diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index f511d820fac58..059fcfdca8a00 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -911,7 +911,7 @@ pub enum Rvalue<'tcx> { Repeat(Operand<'tcx>, TypedConstVal<'tcx>), /// &x or &mut x - Ref(Region, BorrowKind, Lvalue<'tcx>), + Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>), /// length of a [X] or [X;n] value Len(Lvalue<'tcx>), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index cf91229f1c713..76e5f8598c1c5 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -145,8 +145,7 @@ impl<'tcx> Rvalue<'tcx> { } &Rvalue::Ref(reg, bk, ref lv) => { let lv_ty = lv.ty(mir, tcx).to_ty(tcx); - Some(tcx.mk_ref( - tcx.mk_region(reg), + Some(tcx.mk_ref(reg, ty::TypeAndMut { ty: lv_ty, mutbl: bk.to_mutbl_lossy() diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ead8de86dbae4..f608185157a4e 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -724,7 +724,7 @@ make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); #[derive(Copy, Clone, Debug)] -pub enum LvalueContext { +pub enum LvalueContext<'tcx> { // Appears as LHS of an assignment Store, @@ -738,7 +738,7 @@ pub enum LvalueContext { Inspect, // Being borrowed - Borrow { region: Region, kind: BorrowKind }, + Borrow { region: &'tcx Region, kind: BorrowKind }, // Being sliced -- this should be same as being borrowed, probably Slice { from_start: usize, from_end: usize }, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 76477d3df9360..a0e25d54a1321 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -93,7 +93,7 @@ pub struct FulfillmentContext<'tcx> { #[derive(Clone)] pub struct RegionObligation<'tcx> { - pub sub_region: ty::Region, + pub sub_region: &'tcx ty::Region, pub sup_type: Ty<'tcx>, pub cause: ObligationCause<'tcx>, } @@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { pub fn register_region_obligation(&mut self, t_a: Ty<'tcx>, - r_b: ty::Region, + r_b: &'tcx ty::Region, cause: ObligationCause<'tcx>) { register_region_obligation(t_a, r_b, cause, &mut self.region_obligations); @@ -580,7 +580,8 @@ fn process_predicate<'a, 'gcx, 'tcx>( // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. Some(t_a) => { - register_region_obligation(t_a, ty::ReStatic, + let r_static = selcx.tcx().mk_region(ty::ReStatic); + register_region_obligation(t_a, r_static, obligation.cause.clone(), region_obligations); Ok(Some(vec![])) @@ -690,7 +691,7 @@ fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>, } fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, - r_b: ty::Region, + r_b: &'tcx ty::Region, cause: ObligationCause<'tcx>, region_obligations: &mut NodeMap>>) { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f2ea14f17961f..8adf6e19f39d7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1247,7 +1247,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_bound: ty::PolyTraitRef<'tcx>, skol_trait_ref: ty::TraitRef<'tcx>, - skol_map: &infer::SkolemizationMap, + skol_map: &infer::SkolemizationMap<'tcx>, snapshot: &infer::CombinedSnapshot) -> bool { @@ -2264,7 +2264,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>, cause: ObligationCause<'tcx>, recursion_depth: usize, - skol_map: infer::SkolemizationMap, + skol_map: infer::SkolemizationMap<'tcx>, snapshot: &infer::CombinedSnapshot) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { @@ -2662,7 +2662,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { impl_def_id: DefId, obligation: &TraitObligation<'tcx>, snapshot: &infer::CombinedSnapshot) - -> (Normalized<'tcx, &'tcx Substs<'tcx>>, infer::SkolemizationMap) + -> (Normalized<'tcx, &'tcx Substs<'tcx>>, + infer::SkolemizationMap<'tcx>) { match self.match_impl(impl_def_id, obligation, snapshot) { Ok((substs, skol_map)) => (substs, skol_map), @@ -2679,7 +2680,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &TraitObligation<'tcx>, snapshot: &infer::CombinedSnapshot) -> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>, - infer::SkolemizationMap), ()> + infer::SkolemizationMap<'tcx>), ()> { let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); @@ -2872,7 +2873,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { recursion_depth: usize, def_id: DefId, // of impl or trait substs: &Substs<'tcx>, // for impl or trait - skol_map: infer::SkolemizationMap, + skol_map: infer::SkolemizationMap<'tcx>, snapshot: &infer::CombinedSnapshot) -> Vec> { diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index 39dba57c47b7c..b1846e0394148 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -52,7 +52,8 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { self.relate(a, b) } - fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2cae19d95ccbb..e4e69c395a6fb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -213,7 +213,7 @@ pub struct Tables<'tcx> { pub method_map: ty::MethodMap<'tcx>, /// Borrows - pub upvar_capture_map: ty::UpvarCaptureMap, + pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, /// Records the type of each closure. The def ID is the ID of the /// expression defining the closure. @@ -1157,7 +1157,12 @@ impl_interners!('tcx, bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| { keep_local(&fty.sig) }) -> BareFnTy<'tcx>, - region: mk_region(Region, keep_local) -> Region + region: mk_region(Region, |r| { + match r { + &ty::ReVar(_) | &ty::ReSkolemized(..) => true, + _ => false + } + }) -> Region ); impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 32c87fb615a53..3d60d326b2b0f 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -41,11 +41,11 @@ pub enum TypeError<'tcx> { FixedArraySize(ExpectedFound), TyParamSize(ExpectedFound), ArgCount, - RegionsDoesNotOutlive(Region, Region), - RegionsNotSame(Region, Region), - RegionsNoOverlap(Region, Region), - RegionsInsufficientlyPolymorphic(BoundRegion, Region), - RegionsOverlyPolymorphic(BoundRegion, Region), + RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), + RegionsNotSame(&'tcx Region, &'tcx Region), + RegionsNoOverlap(&'tcx Region, &'tcx Region), + RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region), + RegionsOverlyPolymorphic(BoundRegion, &'tcx Region), Sorts(ExpectedFound>), IntegerAsChar, IntMismatch(ExpectedFound), @@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.note_and_explain_region(db, "concrete lifetime that was found is ", conc_region, ""); } - RegionsOverlyPolymorphic(_, ty::ReVar(_)) => { + RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => { // don't bother to print out the message below for // inference variables, it's not very illuminating. } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index c7300946eade8..20235cf6d79d6 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -137,7 +137,7 @@ impl FlagComputation { } &ty::TyRef(r, ref m) => { - self.add_region(*r); + self.add_region(r); self.add_ty(m.ty); } @@ -176,8 +176,8 @@ impl FlagComputation { self.add_bound_computation(&computation); } - fn add_region(&mut self, r: ty::Region) { - match r { + fn add_region(&mut self, r: &ty::Region) { + match *r { ty::ReVar(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 2e114a801d6ed..2c18d1d52547f 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -169,7 +169,7 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { fty.super_fold_with(self) } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { r.super_fold_with(self) } @@ -188,7 +188,7 @@ pub trait TypeVisitor<'tcx> : Sized { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region) -> bool { + fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { r.super_visit_with(self) } } @@ -222,13 +222,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// whether any late-bound regions were skipped pub fn collect_regions(self, value: &T, - region_set: &mut FnvHashSet) + region_set: &mut FnvHashSet<&'tcx ty::Region>) -> bool where T : TypeFoldable<'tcx> { let mut have_bound_regions = false; - self.fold_regions(value, &mut have_bound_regions, - |r, d| { region_set.insert(r.from_depth(d)); r }); + self.fold_regions(value, &mut have_bound_regions, |r, d| { + region_set.insert(self.mk_region(r.from_depth(d))); + r + }); have_bound_regions } @@ -240,7 +242,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { skipped_regions: &mut bool, mut f: F) -> T - where F : FnMut(ty::Region, u32) -> ty::Region, + where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region, T : TypeFoldable<'tcx>, { value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) @@ -260,14 +262,14 @@ pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, current_depth: u32, - fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a), + fld_r: &'a mut (FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region + 'a), } impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx> - where F : FnMut(ty::Region, u32) -> ty::Region + where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region { RegionFolder { tcx: tcx, @@ -288,8 +290,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { t } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", r, self.current_depth); @@ -313,16 +315,16 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, - fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a), - map: FnvHashMap + fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a), + map: FnvHashMap } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, FnvHashMap) - where F : FnMut(ty::BoundRegion) -> ty::Region, + -> (T, FnvHashMap) + where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region, T : TypeFoldable<'tcx>, { let mut replacer = RegionReplacer::new(self, &mut f); @@ -340,7 +342,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { where T : TypeFoldable<'tcx> { self.replace_late_bound_regions(value, |br| { - ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br}) + self.mk_region(ty::ReFree(ty::FreeRegion { + scope: all_outlive_scope, + bound_region: br + })) }).0 } @@ -353,11 +358,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let bound0_value = bound2_value.skip_binder().skip_binder(); let value = self.fold_regions(bound0_value, &mut false, |region, current_depth| { - match region { + match *region { ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { // should be true if no escaping regions from bound2_value assert!(debruijn.depth - current_depth <= 1); - ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br) + self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)) } _ => { region @@ -411,7 +416,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> { - self.replace_late_bound_regions(value, |_| ty::ReErased).0 + self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0 } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are @@ -428,7 +433,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut counter = 0; Binder(self.replace_late_bound_regions(sig, |_| { counter += 1; - ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter)) + self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))) }).0) } } @@ -436,7 +441,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'gcx, 'tcx> - where F : FnMut(ty::BoundRegion) -> ty::Region + where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region { RegionReplacer { tcx: tcx, @@ -465,22 +470,22 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { t.super_fold_with(self) } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { + fn fold_region(&mut self, r:&'tcx ty::Region) -> &'tcx ty::Region { + match *r { ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { let fld_r = &mut self.fld_r; let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); - if let ty::ReLateBound(debruijn1, br) = region { + if let ty::ReLateBound(debruijn1, br) = *region { // If the callback returns a late-bound region, // that region should always use depth 1. Then we // adjust it to the correct depth. assert_eq!(debruijn1.depth, 1); - ty::ReLateBound(debruijn, br) + self.tcx.mk_region(ty::ReLateBound(debruijn, br)) } else { region } } - r => r + _ => r } } } @@ -528,7 +533,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { u.super_fold_with(self) } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { // because late-bound regions affect subtyping, we can't // erase the bound/free distinction, but we can replace // all free regions with 'erased. @@ -537,9 +542,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // type system never "sees" those, they get substituted // away. In trans, they will always be erased to 'erased // whenever a substitution occurs. - match r { + match *r { ty::ReLateBound(..) => r, - _ => ty::ReErased + _ => self.tcx().mk_region(ty::ReErased) } } } @@ -574,7 +579,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, value, amount); value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - shift_region(region, amount) + tcx.mk_region(shift_region(*region, amount)) })) } @@ -616,7 +621,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { t.region_depth > self.depth } - fn visit_region(&mut self, r: ty::Region) -> bool { + fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { r.escapes_depth(self.depth) } } @@ -630,17 +635,18 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { t.flags.get().intersects(self.flags) } - fn visit_region(&mut self, r: ty::Region) -> bool { + fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) { // does this represent a region that cannot be named // in a global way? used in fulfillment caching. - match r { + match *r { ty::ReStatic | ty::ReEmpty | ty::ReErased => {} _ => return true, } } - if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) { - match r { + if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER | + ty::TypeFlags::KEEP_IN_LOCAL_TCX) { + match *r { ty::ReVar(_) | ty::ReSkolemized(..) => { return true } _ => {} } @@ -688,8 +694,8 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region) -> bool { - match r { + fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + match *r { ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { self.regions.insert(br); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 571ad3ca8b9aa..3079deff1b641 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -343,7 +343,7 @@ pub struct Method<'tcx> { pub generics: &'tcx Generics<'tcx>, pub predicates: GenericPredicates<'tcx>, pub fty: &'tcx BareFnTy<'tcx>, - pub explicit_self: ExplicitSelfCategory, + pub explicit_self: ExplicitSelfCategory<'tcx>, pub vis: Visibility, pub defaultness: hir::Defaultness, pub def_id: DefId, @@ -355,7 +355,7 @@ impl<'tcx> Method<'tcx> { generics: &'tcx ty::Generics<'tcx>, predicates: GenericPredicates<'tcx>, fty: &'tcx BareFnTy<'tcx>, - explicit_self: ExplicitSelfCategory, + explicit_self: ExplicitSelfCategory<'tcx>, vis: Visibility, defaultness: hir::Defaultness, def_id: DefId, @@ -658,28 +658,28 @@ pub enum BorrowKind { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. #[derive(PartialEq, Clone, Debug, Copy)] -pub enum UpvarCapture { +pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases /// depending on inference. ByValue, /// Upvar is captured by reference. - ByRef(UpvarBorrow), + ByRef(UpvarBorrow<'tcx>), } #[derive(PartialEq, Clone, Copy)] -pub struct UpvarBorrow { +pub struct UpvarBorrow<'tcx> { /// The kind of borrow: by-ref upvars have access to shared /// immutable borrows, which are not part of the normal language /// syntax. pub kind: BorrowKind, /// Region of the resulting reference. - pub region: ty::Region, + pub region: &'tcx ty::Region, } -pub type UpvarCaptureMap = FnvHashMap; +pub type UpvarCaptureMap<'tcx> = FnvHashMap>; #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { @@ -700,7 +700,7 @@ pub enum IntVarValue { /// this is `None`, then the default is inherited from the /// surrounding context. See RFC #599 for details. #[derive(Copy, Clone)] -pub enum ObjectLifetimeDefault { +pub enum ObjectLifetimeDefault<'tcx> { /// Require an explicit annotation. Occurs when multiple /// `T:'a` constraints are found. Ambiguous, @@ -709,7 +709,7 @@ pub enum ObjectLifetimeDefault { BaseDefault, /// Use the given region as the default. - Specific(Region), + Specific(&'tcx Region), } #[derive(Clone)] @@ -719,18 +719,18 @@ pub struct TypeParameterDef<'tcx> { pub index: u32, pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, - pub object_lifetime_default: ObjectLifetimeDefault, + pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, } #[derive(Clone)] -pub struct RegionParameterDef { +pub struct RegionParameterDef<'tcx> { pub name: Name, pub def_id: DefId, pub index: u32, - pub bounds: Vec, + pub bounds: Vec<&'tcx ty::Region>, } -impl RegionParameterDef { +impl<'tcx> RegionParameterDef<'tcx> { pub fn to_early_bound_region(&self) -> ty::Region { ty::ReEarlyBound(ty::EarlyBoundRegion { index: self.index, @@ -750,7 +750,7 @@ pub struct Generics<'tcx> { pub parent: Option, pub parent_regions: u32, pub parent_types: u32, - pub regions: Vec, + pub regions: Vec>, pub types: Vec>, pub has_self: bool, } @@ -812,7 +812,7 @@ pub enum Predicate<'tcx> { Equate(PolyEquatePredicate<'tcx>), /// where 'a : 'b - RegionOutlives(PolyRegionOutlivesPredicate), + RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), /// where T : 'a TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), @@ -991,8 +991,9 @@ pub type PolyEquatePredicate<'tcx> = ty::Binder>; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; -pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; +pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region, + &'tcx ty::Region>; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx ty::Region>; /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: @@ -1081,7 +1082,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { } } -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { Predicate::RegionOutlives(self.clone()) } @@ -1237,7 +1238,7 @@ pub struct ParameterEnvironment<'tcx> { /// indicates it must outlive at least the function body (the user /// may specify stronger requirements). This field indicates the /// region of the callee. - pub implicit_region_bound: ty::Region, + pub implicit_region_bound: &'tcx ty::Region, /// Obligations that the caller must satisfy. This is basically /// the set of bounds on the in-scope type parameters, translated @@ -2825,7 +2826,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::ParameterEnvironment { free_substs: Substs::empty(self), caller_bounds: Vec::new(), - implicit_region_bound: ty::ReEmpty, + implicit_region_bound: self.mk_region(ty::ReEmpty), free_id_outlive: free_id_outlive } } @@ -2841,8 +2842,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| { // map bound 'a => free 'a - ReFree(FreeRegion { scope: free_id_outlive, - bound_region: def.to_bound_region() }) + self.global_tcx().mk_region(ReFree(FreeRegion { + scope: free_id_outlive, + bound_region: def.to_bound_region() + })) }, |def, _| { // map T => T self.global_tcx().mk_param_from_def(def) @@ -2892,7 +2895,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let unnormalized_env = ty::ParameterEnvironment { free_substs: free_substs, - implicit_region_bound: ty::ReScope(free_id_outlive), + implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)), caller_bounds: predicates, free_id_outlive: free_id_outlive, }; @@ -2901,6 +2904,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) } + pub fn node_scope_region(self, id: NodeId) -> &'tcx Region { + self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) + } + pub fn is_method_call(self, expr_id: NodeId) -> bool { self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) } @@ -2910,7 +2917,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { autoderefs)) } - pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option { + pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option> { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } @@ -2936,10 +2943,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// The category of explicit self. #[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum ExplicitSelfCategory { +pub enum ExplicitSelfCategory<'tcx> { Static, ByValue, - ByReference(Region, hir::Mutability), + ByReference(&'tcx Region, hir::Mutability), ByBox, } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index ee431681ad100..4d5b38212f600 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -17,7 +17,7 @@ use ty::{self, Ty, TypeFoldable}; #[derive(Debug)] pub enum Component<'tcx> { - Region(ty::Region), + Region(&'tcx ty::Region), Param(ty::ParamTy), UnresolvedInferenceVariable(ty::InferTy), @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec) { +fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec<&'tcx ty::Region>) { for r in regions { if !r.is_bound() { out.push(Component::Region(r)); diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 481e8c97974ac..8aa390cdd64e2 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -71,8 +71,8 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; - fn regions(&mut self, a: ty::Region, b: ty::Region) - -> RelateResult<'tcx, ty::Region>; + fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region>; fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> @@ -471,9 +471,9 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) => { - let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?; + let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?; let mt = relation.relate(a_mt, b_mt)?; - Ok(tcx.mk_ref(tcx.mk_region(r), mt)) + Ok(tcx.mk_ref(r, mt)) } (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) => @@ -569,11 +569,11 @@ impl<'tcx> Relate<'tcx> for &'tcx Substs<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Region { +impl<'tcx> Relate<'tcx> for &'tcx ty::Region { fn relate<'a, 'gcx, R>(relation: &mut R, - a: &ty::Region, - b: &ty::Region) - -> RelateResult<'tcx, ty::Region> + a: &&'tcx ty::Region, + b: &&'tcx ty::Region) + -> RelateResult<'tcx, &'tcx ty::Region> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { relation.regions(*a, *b) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9ccf817a53624..705cca056f24c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -72,13 +72,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec { } } -impl<'tcx> Lift<'tcx> for ty::Region { - type Lifted = Self; - fn lift_to_tcx(&self, _: TyCtxt) -> Option { - Some(*self) - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { type Lifted = ty::TraitRef<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -315,13 +308,21 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { FixedArraySize(x) => FixedArraySize(x), TyParamSize(x) => TyParamSize(x), ArgCount => ArgCount, - RegionsDoesNotOutlive(a, b) => RegionsDoesNotOutlive(a, b), - RegionsNotSame(a, b) => RegionsNotSame(a, b), - RegionsNoOverlap(a, b) => RegionsNoOverlap(a, b), + RegionsDoesNotOutlive(a, b) => { + return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)) + } + RegionsNotSame(a, b) => { + return tcx.lift(&(a, b)).map(|(a, b)| RegionsNotSame(a, b)) + } + RegionsNoOverlap(a, b) => { + return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b)) + } RegionsInsufficientlyPolymorphic(a, b) => { - RegionsInsufficientlyPolymorphic(a, b) + return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) + } + RegionsOverlyPolymorphic(a, b) => { + return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) } - RegionsOverlyPolymorphic(a, b) => RegionsOverlyPolymorphic(a, b), IntegerAsChar => IntegerAsChar, IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), @@ -654,7 +655,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::Region { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { *self } @@ -672,25 +673,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { - *self - } - - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let region = folder.fold_region(**self); - folder.tcx().mk_region(region) - } - - fn super_visit_with>(&self, _visitor: &mut V) -> bool { - false - } - - fn visit_with>(&self, visitor: &mut V) -> bool { - visitor.visit_region(**self) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ClosureSubsts { @@ -766,7 +748,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault { +impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { ty::ObjectLifetimeDefault::Ambiguous => @@ -788,7 +770,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault { } } -impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef { +impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::RegionParameterDef { name: self.name, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 3f8d55b4634e0..5e0f3bc5e26f7 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -294,7 +294,7 @@ impl<'tcx> Decodable for ClosureSubsts<'tcx> { #[derive(Clone, PartialEq, Eq, Hash)] pub struct TraitObject<'tcx> { pub principal: PolyExistentialTraitRef<'tcx>, - pub region_bound: ty::Region, + pub region_bound: &'tcx ty::Region, pub builtin_bounds: BuiltinBounds, pub projection_bounds: Vec>, } @@ -676,6 +676,15 @@ pub enum Region { ReErased, } +impl<'tcx> Decodable for &'tcx Region { + fn decode(d: &mut D) -> Result<&'tcx Region, D::Error> { + let r = Decodable::decode(d)?; + cstore::tls::with_decoding_context(d, |dcx, _| { + Ok(dcx.tcx().mk_region(r)) + }) + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct EarlyBoundRegion { pub index: u32, @@ -1207,10 +1216,10 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { /// Returns the regions directly referenced from this type (but /// not types reachable from this type via `walk_tys`). This /// ignores late-bound regions binders. - pub fn regions(&self) -> Vec { + pub fn regions(&self) -> Vec<&'tcx ty::Region> { match self.sty { TyRef(region, _) => { - vec![*region] + vec![region] } TyTrait(ref obj) => { let mut v = vec![obj.region_bound]; diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 96f4bda361b63..b20c17c8a6677 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { mut mk_region: FR, mut mk_type: FT) -> &'tcx Substs<'tcx> - where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region, + where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { let defs = tcx.lookup_generics(def_id); let num_regions = defs.parent_regions as usize + defs.regions.len(); @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { defs: &ty::Generics<'tcx>, mk_region: &mut FR, mk_type: &mut FT) - where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region, + where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { if let Some(def_id) = defs.parent { let parent_defs = tcx.lookup_generics(def_id); @@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn region_at(&self, i: usize) -> ty::Region { + pub fn region_at(&self, i: usize) -> &'tcx ty::Region { self.regions[i] } @@ -132,7 +132,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region { + pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> &'tcx ty::Region { self.region_at(def.index as usize) } @@ -255,13 +255,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { t } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { // Note: This routine only handles regions that are bound on // type declarations and other outer declarations, not those // bound in *fn types*. Region substitution of the bound // regions that appear in a function signature is done using // the specialized routine `ty::replace_late_regions()`. - match r { + match *r { ty::ReEarlyBound(data) => { match self.substs.regions.get(data.index as usize) { Some(&r) => { @@ -394,8 +394,8 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { result } - fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region { - ty::fold::shift_region(region, self.region_binders_passed) + fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region { + self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 641dfa67c5b9e..96f432587b10e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn required_region_bounds(self, erased_self_ty: Ty<'tcx>, predicates: Vec>) - -> Vec { + -> Vec<&'tcx ty::Region> { debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", erased_self_ty, predicates); @@ -496,8 +496,8 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { ty.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region) -> bool { - match r { + fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + match *r { ty::ReStatic | ty::ReErased => { self.hash::(0); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index e1a39e6957a49..1f166cb192fa3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -115,9 +115,9 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. #[derive(Debug)] pub enum ImpliedBound<'tcx> { - RegionSubRegion(ty::Region, ty::Region), - RegionSubParam(ty::Region, ty::ParamTy), - RegionSubProjection(ty::Region, ty::ProjectionTy<'tcx>), + RegionSubRegion(&'tcx ty::Region, &'tcx ty::Region), + RegionSubParam(&'tcx ty::Region, ty::ParamTy), + RegionSubProjection(&'tcx ty::Region, ty::ProjectionTy<'tcx>), } /// Compute the implied bounds that a callee/impl can assume based on @@ -196,7 +196,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( /// this down to determine what relationships would have to hold for /// `T: 'a` to hold. We get to assume that the caller has validated /// those relationships. -fn implied_bounds_from_components<'tcx>(sub_region: ty::Region, +fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region, sup_components: Vec>) -> Vec> { @@ -363,7 +363,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { cause, ty::Predicate::TypeOutlives( ty::Binder( - ty::OutlivesPredicate(mt.ty, *r))))); + ty::OutlivesPredicate(mt.ty, r))))); } } @@ -534,7 +534,7 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, principal: ty::PolyExistentialTraitRef<'tcx>, others: ty::BuiltinBounds) - -> Vec + -> Vec<&'tcx ty::Region> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index c75fbf9579f5c..4b6234e8815ef 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -247,7 +247,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, let new_value = tcx.replace_late_bound_regions(&value, |br| { let _ = start_or_continue(f, "for<", ", "); - ty::ReLateBound(ty::DebruijnIndex::new(1), match br { + let br = match br { ty::BrNamed(_, name, _) => { let _ = write!(f, "{}", name); br @@ -261,7 +261,8 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, name, ty::Issue32330::WontChange) } - }) + }; + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) }).0; start_or_continue(f, "", "> ")?; @@ -351,7 +352,7 @@ impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> { } } -impl fmt::Debug for ty::RegionParameterDef { +impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "RegionParameterDef({}, {:?}, {}, {:?})", self.name, @@ -598,7 +599,7 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault { +impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"), @@ -793,13 +794,14 @@ impl<'tcx> fmt::Display for ty::Binder> { } } -impl<'tcx> fmt::Display for ty::Binder, ty::Region>> { +impl<'tcx> fmt::Display for ty::Binder, &'tcx ty::Region>> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) } } -impl fmt::Display for ty::Binder> { +impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) } @@ -973,7 +975,7 @@ impl fmt::Debug for ty::UpvarId { } } -impl fmt::Debug for ty::UpvarBorrow { +impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UpvarBorrow({:?}, {:?})", self.kind, self.region) @@ -997,7 +999,7 @@ impl fmt::Display for ty::InferTy { } } -impl fmt::Display for ty::ExplicitSelfCategory { +impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match *self { ty::ExplicitSelfCategory::Static => "static", diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index c1f162e5772bf..e86fa9a05f372 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt<'tcx>, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 667bf16874ec4..9f95175d59d43 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -28,7 +28,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span: Span, cause: euv::LoanCause, cmt: mc::cmt<'tcx>, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, _: ty::BorrowKind) -> Result<(),()> { //! Reports error if `loan_region` is larger than S @@ -56,7 +56,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { span: Span, cause: euv::LoanCause, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, cmt_original: mc::cmt<'tcx> } @@ -92,7 +92,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn check_scope(&self, max_scope: ty::Region) -> R { + fn check_scope(&self, max_scope: &'tcx ty::Region) -> R { //! Reports an error if `loan_region` is larger than `max_scope` if !self.bccx.is_subregion_of(self.loan_region, max_scope) { @@ -102,7 +102,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn scope(&self, cmt: &mc::cmt) -> ty::Region { + fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region { //! Returns the maximal region scope for the which the //! lvalue `cmt` is guaranteed to be valid without any //! rooting etc, and presuming `cmt` is not mutated. @@ -112,16 +112,15 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { temp_scope } Categorization::Upvar(..) => { - ty::ReScope(self.item_scope) - } - Categorization::StaticItem => { - ty::ReStatic + self.bccx.tcx.mk_region(ty::ReScope(self.item_scope)) } Categorization::Local(local_id) => { - ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id)) + self.bccx.tcx.mk_region(ty::ReScope( + self.bccx.tcx.region_maps.var_scope(local_id))) } + Categorization::StaticItem | Categorization::Deref(_, _, mc::UnsafePtr(..)) => { - ty::ReStatic + self.bccx.tcx.mk_region(ty::ReStatic) } Categorization::Deref(_, _, mc::BorrowedPtr(_, r)) | Categorization::Deref(_, _, mc::Implicit(_, r)) => { @@ -135,7 +134,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn report_error(&self, code: bckerr_code) { + fn report_error(&self, code: bckerr_code<'tcx>) { self.bccx.report(BckError { cmt: self.cmt_original.clone(), span: self.span, cause: BorrowViolation(self.cause), diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index c982fc091d24c..a255564f01e25 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt<'tcx>, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { @@ -307,7 +307,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { borrow_span: Span, cmt: mc::cmt<'tcx>, req_kind: ty::BorrowKind, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, cause: euv::LoanCause) { debug!("guarantee_valid(borrow_id={}, cmt={:?}, \ req_mutbl={:?}, loan_region={:?})", @@ -318,7 +318,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { // a loan for the empty region can never be dereferenced, so // it is always safe - if loan_region == ty::ReEmpty { + if *loan_region == ty::ReEmpty { return; } @@ -358,7 +358,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } RestrictionResult::SafeIf(loan_path, restricted_paths) => { - let loan_scope = match loan_region { + let loan_scope = match *loan_region { ty::ReScope(scope) => scope, ty::ReFree(ref fr) => fr.scope, diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 3d9df4c8bd008..d08f792b30c14 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -31,7 +31,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span: Span, cause: euv::LoanCause, cmt: mc::cmt<'tcx>, - loan_region: ty::Region) + loan_region: &'tcx ty::Region) -> RestrictionResult<'tcx> { let ctxt = RestrictionsContext { bccx: bccx, @@ -49,7 +49,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, struct RestrictionsContext<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, span: Span, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, cause: euv::LoanCause, } @@ -157,7 +157,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { fn extend(&self, result: RestrictionResult<'tcx>, cmt: &mc::cmt<'tcx>, - elem: LoanPathElem) -> RestrictionResult<'tcx> { + elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> { match result { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..5826064c267a0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -365,7 +365,7 @@ pub enum LoanPathKind<'tcx> { LpVar(ast::NodeId), // `x` in README.md LpUpvar(ty::UpvarId), // `x` captured by-value into closure LpDowncast(Rc>, DefId), // `x` downcast to particular enum variant - LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem) + LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem<'tcx>) } impl<'tcx> LoanPath<'tcx> { @@ -410,8 +410,8 @@ impl ToInteriorKind for mc::InteriorKind { // `enum E { X { foo: u32 }, Y { foo: u32 }}` // each `foo` is qualified by the definitition id of the variant (`X` or `Y`). #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum LoanPathElem { - LpDeref(mc::PointerKind), +pub enum LoanPathElem<'tcx> { + LpDeref(mc::PointerKind<'tcx>), LpInterior(Option, InteriorKind), } @@ -564,10 +564,11 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { // Errors that can occur #[derive(PartialEq)] -pub enum bckerr_code { +pub enum bckerr_code<'tcx> { err_mutbl, - err_out_of_scope(ty::Region, ty::Region, euv::LoanCause), // superscope, subscope, loan cause - err_borrowed_pointer_too_short(ty::Region, ty::Region), // loan, ptr + /// superscope, subscope, loan cause + err_out_of_scope(&'tcx ty::Region, &'tcx ty::Region, euv::LoanCause), + err_borrowed_pointer_too_short(&'tcx ty::Region, &'tcx ty::Region), // loan, ptr } // Combination of an error code and the categorization of the expression @@ -577,7 +578,7 @@ pub struct BckError<'tcx> { span: Span, cause: AliasableViolationKind, cmt: mc::cmt<'tcx>, - code: bckerr_code + code: bckerr_code<'tcx> } #[derive(Copy, Clone, Debug, PartialEq)] @@ -605,7 +606,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.free_region_map = old_free_region_map; } - pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region) + pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region) -> bool { self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) @@ -614,9 +615,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn report(&self, err: BckError<'tcx>) { // Catch and handle some particular cases. match (&err.code, &err.cause) { - (&err_out_of_scope(ty::ReScope(_), ty::ReStatic, _), + (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _), &BorrowViolation(euv::ClosureCapture(span))) | - (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..), _), + (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _), &BorrowViolation(euv::ClosureCapture(span))) => { return self.report_out_of_scope_escaping_closure_capture(&err, span); } @@ -965,8 +966,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .emit(); } - fn region_end_span(&self, region: ty::Region) -> Option { - match region { + fn region_end_span(&self, region: &'tcx ty::Region) -> Option { + match *region { ty::ReScope(scope) => { match scope.span(&self.tcx.region_maps, &self.tcx.map) { Some(s) => { @@ -1194,8 +1195,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } -fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option { - match region { +fn statement_scope_span(tcx: TyCtxt, region: &ty::Region) -> Option { + match *region { ty::ReScope(scope) => { match tcx.map.find(scope.node_id(&tcx.region_maps)) { Some(hir_map::NodeStmt(stmt)) => Some(stmt.span), diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 3c82358542876..82c142c919e34 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -1172,7 +1172,7 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { _: NodeId, span: Span, _: cmt, - _: Region, + _: &'tcx Region, kind: BorrowKind, _: LoanCause) { match kind { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 32d0bbbfdb6b7..a99262d30eee3 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -283,25 +283,26 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn re_early_bound(&self, index: u32, name: &'static str) - -> ty::Region { + -> &'tcx ty::Region { let name = token::intern(name); - ty::ReEarlyBound(ty::EarlyBoundRegion { + self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { index: index, name: name, - }) + })) } - pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region { - ty::ReLateBound(debruijn, ty::BrAnon(id)) + pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) + -> &'tcx ty::Region { + self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id))) } - pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) + pub fn t_rptr(&self, r: &'tcx ty::Region) -> Ty<'tcx> { + self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> { let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)); - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } pub fn t_rptr_late_bound_with_debruijn(&self, @@ -309,7 +310,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { debruijn: ty::DebruijnIndex) -> Ty<'tcx> { let r = self.re_late_bound_with_debruijn(id, debruijn); - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> { @@ -317,16 +318,16 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) } - pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region { - ty::ReFree(ty::FreeRegion { + pub fn re_free(&self, nid: ast::NodeId, id: u32) -> &'tcx ty::Region { + self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: self.tcx().region_maps.item_extent(nid), bound_region: ty::BrAnon(id), - }) + })) } pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> { let r = self.re_free(nid, id); - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } pub fn t_rptr_static(&self) -> Ty<'tcx> { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index ad52d346857ff..0236f9c413ddc 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -517,7 +517,7 @@ pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { // Encoding and decoding the side tables trait rbml_writer_helpers<'tcx> { - fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); + fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, substs: &Substs<'tcx>); @@ -531,7 +531,7 @@ trait rbml_writer_helpers<'tcx> { } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { - fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) { + fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region) { self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor, &ecx.ty_str_ctxt(), r))); @@ -617,7 +617,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { &adjustment::AutoPtr(r, m) => { this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, - |this| Ok(this.emit_region(ecx, *r))); + |this| Ok(this.emit_region(ecx, r))); this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } @@ -824,7 +824,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { f: F) -> R where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R; - fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region; + fn read_region<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> &'tcx ty::Region; fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -835,8 +835,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::Predicate<'tcx>; fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> &'tcx Substs<'tcx>; - fn read_upvar_capture(&mut self, dcx: &DecodeContext) - -> ty::UpvarCapture; + fn read_upvar_capture<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::UpvarCapture<'tcx>; fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> adjustment::AutoAdjustment<'tcx>; fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -908,7 +908,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { str } } - fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region { + fn read_region<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> &'tcx ty::Region { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode // context. However, we do not bother, because region types @@ -948,7 +948,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { .parse_substs()) }).unwrap() } - fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture { + fn read_upvar_capture<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::UpvarCapture<'tcx> { self.read_enum("UpvarCapture", |this| { let variants = ["ByValue", "ByRef"]; this.read_enum_variant(&variants, |this, i| { @@ -1032,7 +1033,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_enum_variant(&variants, |this, i| { Ok(match i { 0 => { - let r: ty::Region = + let r: &'tcx ty::Region = this.read_enum_variant_arg(0, |this| { Ok(this.read_region(dcx)) }).unwrap(); @@ -1041,7 +1042,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Decodable::decode(this) }).unwrap(); - adjustment::AutoPtr(dcx.tcx.mk_region(r), m) + adjustment::AutoPtr(r, m) } 1 => { let m: hir::Mutability = diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 94426dcbf1d8d..d5c3a4a6bb0dc 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -291,13 +291,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_foreign_item(&cdata, did.index) } - fn is_static_method(&self, def: DefId) -> bool - { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::is_static_method(&cdata, def.index) - } - fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { self.do_is_statically_included_foreign_item(id) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b0335258b4041..ccd8bb70f652d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -859,7 +859,8 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, } } -fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { +fn get_explicit_self<'a, 'tcx>(item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::ExplicitSelfCategory<'tcx> { fn get_mutability(ch: u8) -> hir::Mutability { match ch as char { 'i' => hir::MutImmutable, @@ -879,7 +880,7 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { // FIXME(#4846) expl. region '&' => { ty::ExplicitSelfCategory::ByReference( - ty::ReEmpty, + tcx.mk_region(ty::ReEmpty), get_mutability(string.as_bytes()[1])) } _ => bug!("unknown self type code: `{}`", explicit_self_kind as char) @@ -905,16 +906,6 @@ pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name { item_name(doc) } -pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool { - let doc = cdata.lookup_item(id); - match item_sort(doc) { - Some('r') | Some('p') => { - get_explicit_self(doc) == ty::ExplicitSelfCategory::Static - } - _ => false - } -} - pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { let item_doc = cdata.lookup_item(id); @@ -959,7 +950,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a "the type {:?} of the method {:?} is not a function?", ity, name) }; - let explicit_self = get_explicit_self(item_doc); + let explicit_self = get_explicit_self(item_doc, tcx); ty::MethodTraitItem(Rc::new(ty::Method::new(name, generics, diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index c76cf23639237..3b022448efa5d 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -207,8 +207,8 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - pub fn parse_region(&mut self) -> ty::Region { - match self.next() { + pub fn parse_region(&mut self) -> &'tcx ty::Region { + self.tcx.mk_region(match self.next() { 'b' => { assert_eq!(self.next(), '['); let id = ty::DebruijnIndex::new(self.parse_u32()); @@ -245,7 +245,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { 'e' => ty::ReEmpty, 'E' => ty::ReErased, _ => bug!("parse_region: bad input") - } + }) } fn parse_scope(&mut self) -> region::CodeExtent { @@ -403,9 +403,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { '~' => return tcx.mk_box(self.parse_ty()), '*' => return tcx.mk_ptr(self.parse_mt()), '&' => { - let r = self.parse_region(); - let mt = self.parse_mt(); - return tcx.mk_ref(tcx.mk_region(r), mt); + return tcx.mk_ref(self.parse_region(), self.parse_mt()); } 'V' => { let t = self.parse_ty(); @@ -657,7 +655,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { + fn parse_region_param_def(&mut self) -> ty::RegionParameterDef<'tcx> { let name = self.parse_name(':'); let def_id = self.parse_def(); let index = self.parse_u32(); @@ -681,7 +679,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } - fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault { + fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault<'tcx> { match self.next() { 'a' => ty::ObjectLifetimeDefault::Ambiguous, 'b' => ty::ObjectLifetimeDefault::BaseDefault, diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 10f503f4e3699..f502ec4554328 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -133,7 +133,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyRawPtr(mt) => { write!(w, "*"); enc_mt(w, cx, mt); } ty::TyRef(r, mt) => { write!(w, "&"); - enc_region(w, cx, *r); + enc_region(w, cx, r); enc_mt(w, cx, mt); } ty::TyArray(t, sz) => { @@ -286,8 +286,8 @@ pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, } } -pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: ty::Region) { - match r { +pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: &ty::Region) { + match *r { ty::ReLateBound(id, br) => { write!(w, "b[{}|", id.depth); enc_bound_region(w, cx, br); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index ec390704d0789..1b64b4d0b5317 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -278,7 +278,7 @@ struct Binding<'tcx> { var_id: NodeId, var_ty: Ty<'tcx>, mutability: Mutability, - binding_mode: BindingMode, + binding_mode: BindingMode<'tcx>, } #[derive(Clone, Debug)] diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index a61fdb79df822..6e8a5771eea94 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -108,7 +108,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }), span: expr.span, kind: ExprKind::Borrow { - region: *region, + region: region, borrow_kind: to_borrow_kind(mutbl), arg: expr.to_ref() } @@ -137,7 +137,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ty: adjusted_ty, span: self.span, kind: ExprKind::Borrow { - region: *r, + region: r, borrow_kind: to_borrow_kind(m), arg: expr.to_ref(), }, @@ -154,7 +154,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }), span: self.span, kind: ExprKind::Borrow { - region: *region, + region: region, borrow_kind: to_borrow_kind(m), arg: expr.to_ref(), }, @@ -310,7 +310,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, _ => span_bug!(expr.span, "type of & not region"), }; ExprKind::Borrow { - region: *region, + region: region, borrow_kind: to_borrow_kind(mutbl), arg: expr.to_ref(), } @@ -842,8 +842,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Deref { arg: Expr { temp_lifetime: temp_lifetime, - ty: cx.tcx.mk_ref( - cx.tcx.mk_region(borrow.region), + ty: cx.tcx.mk_ref(borrow.region, ty::TypeAndMut { ty: var_ty, mutbl: borrow.kind.to_mutbl_lossy() @@ -907,8 +906,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } PassArgs::ByRef => { - let scope = cx.tcx.region_maps.node_extent(expr.id); - let region = cx.tcx.mk_region(ty::ReScope(scope)); + let region = cx.tcx.node_scope_region(expr.id); let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); argrefs.extend( args.iter() @@ -922,7 +920,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime: temp_lifetime, ty: adjusted_ty, span: expr.span, - kind: ExprKind::Borrow { region: *region, + kind: ExprKind::Borrow { region: region, borrow_kind: BorrowKind::Shared, arg: arg.to_ref() } }.to_ref() diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index c54c8bfb5981e..0bd22cd2d9308 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -161,7 +161,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { let id = self.cx.tcx.expect_def(pat.id).var_id(); let var_ty = self.cx.tcx.node_id_to_type(pat.id); let region = match var_ty.sty { - ty::TyRef(&r, _) => Some(r), + ty::TyRef(r, _) => Some(r), _ => None, }; let (mutability, mode) = match bm { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2a5b7d0fb2902..353f243335302 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -193,7 +193,7 @@ pub enum ExprKind<'tcx> { id: DefId, }, Borrow { - region: Region, + region: &'tcx Region, borrow_kind: BorrowKind, arg: ExprRef<'tcx>, }, @@ -284,7 +284,7 @@ pub enum PatternKind<'tcx> { Binding { mutability: Mutability, name: ast::Name, - mode: BindingMode, + mode: BindingMode<'tcx>, var: ast::NodeId, ty: Ty<'tcx>, subpattern: Option>, @@ -332,9 +332,9 @@ pub enum PatternKind<'tcx> { } #[derive(Copy, Clone, Debug)] -pub enum BindingMode { +pub enum BindingMode<'tcx> { ByValue, - ByRef(Region, BorrowKind), + ByRef(&'tcx Region, BorrowKind), } #[derive(Clone, Debug)] diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b116ab7b3161a..4aae6d690c4df 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -683,7 +683,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { borrow_id: ast::NodeId, _borrow_span: Span, cmt: mc::cmt<'tcx>, - _loan_region: ty::Region, + _loan_region: &'tcx ty::Region, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { // Kind of hacky, but we allow Unsafe coercions in constants. diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index 782ee34edd4f9..c3ef5a72a2944 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tc _borrow_id: ast::NodeId, _borrow_span: Span, _cmt: mc::cmt, - _loan_region: ty::Region, + _loan_region: &'tcx ty::Region, _bk: ty::BorrowKind, _loan_cause: euv::LoanCause) { } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 76910304eebb0..b0afc147e6f9d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1235,7 +1235,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. let impl_substs = Substs::for_item(tcx, impl_def_id, - |_, _| ty::ReErased, + |_, _| tcx.mk_region(ty::ReErased), |_, _| tcx.types.err); let mth = meth::get_impl_method(tcx, callee_substs, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 0a295b251b31e..71184dd3f814d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -563,7 +563,9 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { - Substs::for_item(self.tcx(), item_def_id, |_, _| ty::ReErased, |_, _| { + Substs::for_item(self.tcx(), item_def_id, + |_, _| self.tcx().mk_region(ty::ReErased), + |_, _| { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) } diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 103afd827de93..483bc99c310fc 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -265,7 +265,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the method may have some early-bound lifetimes, add // regions for those let method_substs = Substs::for_item(tcx, trait_method_def_id, - |_, _| ty::ReErased, + |_, _| tcx.mk_region(ty::ReErased), |_, _| tcx.types.err); // The substitutions we have are on the impl, so we grab diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 72f81c7d48da8..79c4a9af8295c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -178,8 +178,9 @@ type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec = ty::TyInfer(ty::FreshTy(0)); -pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime) - -> ty::Region { +pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + lifetime: &hir::Lifetime) + -> &'tcx ty::Region { let r = match tcx.named_region_map.defs.get(&lifetime.id) { None => { // should have been recorded by the `resolve_lifetime` pass @@ -238,7 +239,7 @@ pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime) lifetime.id, r); - r + tcx.mk_region(r) } fn report_elision_failure( @@ -313,14 +314,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn opt_ast_region_to_region(&self, rscope: &RegionScope, default_span: Span, - opt_lifetime: &Option) -> ty::Region + opt_lifetime: &Option) -> &'tcx ty::Region { let r = match *opt_lifetime { Some(ref lifetime) => { ast_region_to_region(self.tcx(), lifetime) } - None => match rscope.anon_regions(default_span, 1) { + None => self.tcx().mk_region(match rscope.anon_regions(default_span, 1) { Ok(rs) => rs[0], Err(params) => { let ampersand_span = Span { hi: default_span.lo, ..default_span}; @@ -335,7 +336,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { err.emit(); ty::ReStatic } - } + }) }; debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", @@ -366,7 +367,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); return Substs::for_item(tcx, def_id, |_, _| { - ty::ReStatic + tcx.mk_region(ty::ReStatic) }, |_, _| { tcx.types.err }); @@ -431,7 +432,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); let regions = if expected_num_region_params == supplied_num_region_params { - lifetimes.iter().map(|l| ast_region_to_region(tcx, l)).collect() + lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect() } else { let anon_regions = rscope.anon_regions(span, expected_num_region_params); @@ -472,7 +473,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { - regions[def.index as usize] + tcx.mk_region(regions[def.index as usize]) }, |def, substs| { let i = def.index as usize; @@ -588,7 +589,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { - Ok(possible_implied_output_region.unwrap()) + Ok(*possible_implied_output_region.unwrap()) } else { Err(Some(lifetimes_for_params)) } @@ -1100,7 +1101,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let region_bound = match region_bound { Some(r) => r, None => { - match rscope.object_lifetime_default(span) { + tcx.mk_region(match rscope.object_lifetime_default(span) { Some(r) => r, None => { span_err!(self.tcx().sess, span, E0228, @@ -1108,7 +1109,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { from context; please supply an explicit bound"); ty::ReStatic } - } + }) } }; @@ -1643,7 +1644,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope, ty::ObjectLifetimeDefault::Specific(r)); let t = self.ast_ty_to_ty(rscope1, &mt.ty); - tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) + tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) } hir::TyNever => { tcx.types.never @@ -1801,7 +1802,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { sig: &hir::MethodSig, untransformed_self_ty: Ty<'tcx>, anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { + -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) { self.ty_of_method_or_bare_fn(sig.unsafety, sig.abi, Some(untransformed_self_ty), @@ -1826,7 +1827,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, arg_anon_scope: Option, ret_anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) + -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) { debug!("ty_of_method_or_bare_fn"); @@ -1863,7 +1864,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // reference) in the arguments, then any anonymous regions in the output // have that lifetime. let implied_output_region = match explicit_self_category { - ty::ExplicitSelfCategory::ByReference(region, _) => Ok(region), + ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region), _ => self.find_implied_output_region(&arg_tys, arg_pats) }; @@ -1890,7 +1891,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope: &RegionScope, untransformed_self_ty: Ty<'tcx>, explicit_self: &hir::ExplicitSelf) - -> (Ty<'tcx>, ty::ExplicitSelfCategory) + -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>) { return match explicit_self.node { SelfKind::Value(..) => { @@ -1902,8 +1903,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope, explicit_self.span, lifetime); - (self.tcx().mk_ref( - self.tcx().mk_region(region), + (self.tcx().mk_ref(region, ty::TypeAndMut { ty: untransformed_self_ty, mutbl: mutability @@ -1957,7 +1957,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty::ExplicitSelfCategory::ByValue } else { match explicit_type.sty { - ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl), + ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl), ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox, _ => ty::ExplicitSelfCategory::ByValue, } @@ -2070,7 +2070,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { explicit_region_bounds: &[&hir::Lifetime], principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>, builtin_bounds: ty::BuiltinBounds) - -> Option // if None, use the default + -> Option<&'tcx ty::Region> // if None, use the default { let tcx = self.tcx(); @@ -2093,7 +2093,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if let Err(ErrorReported) = self.ensure_super_predicates(span, principal_trait_ref.def_id()) { - return Some(ty::ReStatic); + return Some(tcx.mk_region(ty::ReStatic)); } // No explicit region bound specified. Therefore, examine trait @@ -2109,8 +2109,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // If any of the derived region bounds are 'static, that is always // the best choice. - if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) { - return Some(ty::ReStatic); + if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { + return Some(tcx.mk_region(ty::ReStatic)); } // Determine whether there is exactly one unique region in the set @@ -2242,7 +2242,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected // and return from functions in multiple places. #[derive(PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub region_bounds: Vec, + pub region_bounds: Vec<&'tcx ty::Region>, pub builtin_bounds: ty::BuiltinBounds, pub trait_bounds: Vec>, pub projection_bounds: Vec>, @@ -2264,7 +2264,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { for ®ion_bound in &self.region_bounds { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions - let region_bound = ty::fold::shift_region(region_bound, 1); + let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1)); vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate()); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 52073359c0fd9..78175c85b19bf 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // and T is the expected type. let region_var = self.next_region_var(infer::PatternRegion(pat.span)); let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; - let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt); + let region_ty = tcx.mk_ref(region_var, mt); // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for @@ -220,7 +220,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let inner_ty = self.next_ty_var(); let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; let region = self.next_region_var(infer::PatternRegion(pat.span)); - let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); + let rptr_ty = tcx.mk_ref(region, mt); self.demand_eqtype(pat.span, expected, rptr_ty); (rptr_ty, inner_ty) } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4a0d529812891..7126478f2c426 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -336,7 +336,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { if r_borrow_var.is_none() { // create var lazilly, at most once let coercion = Coercion(span); let r = self.next_region_var(coercion); - r_borrow_var = Some(self.tcx.mk_region(r)); // [4] above + r_borrow_var = Some(r); // [4] above } r_borrow_var.unwrap() }; @@ -436,8 +436,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let coercion = Coercion(self.origin.span()); let r_borrow = self.next_region_var(coercion); - let region = self.tcx.mk_region(r_borrow); - (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl))) + (mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl))) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4e48838f85cfb..cede9d871ff4d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -412,7 +412,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( ty); cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - ty, ty::ReScope(cx.parent_scope)); + ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); return Ok(()); } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 7f9e715b7fafc..ad48827a1d039 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -37,7 +37,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let i_ty = tcx.lookup_item_type(def_id); let substs = Substs::for_item(tcx, def_id, - |_, _| ty::ReErased, + |_, _| tcx.mk_region(ty::ReErased), |def, _| tcx.mk_param_from_def(def)); let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 8b757309f4887..9197bdaa030cd 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { { let (autoref, unsize) = if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); - let autoref = AutoPtr(self.tcx.mk_region(region), mutbl); + let autoref = AutoPtr(region, mutbl); (Some(autoref), pick.unsize.map(|target| { target.adjust_for_autoref(self.tcx, Some(autoref)) })) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index d8ff9b4057f34..e38d6aa7a00d7 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1242,7 +1242,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. - ty::ReErased + self.tcx.mk_region(ty::ReErased) } }, |def, cur_substs| { let i = def.index as usize; @@ -1264,7 +1264,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty; let substs = Substs::for_item(self.tcx, impl_def_id, - |_, _| ty::ReErased, + |_, _| self.tcx.mk_region(ty::ReErased), |_, _| self.next_ty_var()); (impl_ty, substs) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f2ed3e37c1a28..cc7eadefeb099 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1422,13 +1422,13 @@ impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { // (and anyway, within a fn body the right region may not even // be something the user can write explicitly, since it might // be some expression). - self.next_region_var(infer::MiscVariable(span)) + *self.next_region_var(infer::MiscVariable(span)) } fn anon_regions(&self, span: Span, count: usize) -> Result, Option>> { Ok((0..count).map(|_| { - self.next_region_var(infer::MiscVariable(span)) + *self.next_region_var(infer::MiscVariable(span)) }).collect()) } } @@ -1862,7 +1862,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// outlive the region `r`. pub fn register_region_obligation(&self, ty: Ty<'tcx>, - region: ty::Region, + region: &'tcx ty::Region, cause: traits::ObligationCause<'tcx>) { let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -1893,7 +1893,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_region_obligation(ty, ty::ReEmpty, cause); + self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause); } /// Registers obligations that all types appearing in `substs` are well-formed. @@ -3454,7 +3454,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // value whose address was taken can actually be made to live // as long as it needs to live. let region = self.next_region_var(infer::AddrOfRegion(expr.span)); - tcx.mk_ref(tcx.mk_region(region), tm) + tcx.mk_ref(region, tm) }; self.write_ty(id, oprnd_t); } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index a596b3cdcbb81..5f5cda358ff2f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -169,7 +169,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>, + region_bound_pairs: Vec<(&'tcx ty::Region, GenericKind<'tcx>)>, free_region_map: FreeRegionMap, @@ -324,9 +324,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let call_site_scope = self.call_site_scope.unwrap(); debug!("visit_fn_body body.id {} call_site_scope: {:?}", body.id, call_site_scope); + let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope)); self.type_of_node_must_outlive(infer::CallReturn(span), body.id, - ty::ReScope(call_site_scope)); + call_site_region); self.region_bound_pairs.truncate(old_region_bounds_pairs_len); @@ -407,8 +408,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { for implication in implied_bounds { debug!("implication: {:?}", implication); match implication { - ImpliedBound::RegionSubRegion(ty::ReFree(free_a), - ty::ReVar(vid_b)) => { + ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), + &ty::ReVar(vid_b)) => { self.add_given(free_a, vid_b); } ImpliedBound::RegionSubParam(r_a, param_b) => { @@ -476,9 +477,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // variable's type enclose at least the variable's scope. let var_scope = tcx.region_maps.var_scope(id); + let var_region = self.tcx.mk_region(ty::ReScope(var_scope)); let origin = infer::BindingTypeIsNotValidAtDecl(span); - self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope)); + self.type_of_node_must_outlive(origin, id, var_region); let typ = self.resolve_node_type(id); dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope); @@ -525,7 +527,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { // scope of that expression. This also guarantees basic WF. let expr_ty = self.resolve_node_type(expr.id); // the region corresponding to this expression - let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id)); + let expr_region = self.tcx.node_scope_region(expr.id); self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, expr_region); @@ -713,7 +715,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { None => self.resolve_node_type(base.id) }; if let ty::TyRef(r_ptr, _) = base_ty.sty { - self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr); + self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr); } intravisit::walk_expr(self, expr); @@ -780,9 +782,10 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { let call_site_scope = self.call_site_scope; debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}", ret_expr.id, call_site_scope); + let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap())); self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span), ret_expr.id, - ty::ReScope(call_site_scope.unwrap())); + call_site_region); intravisit::walk_expr(self, expr); } @@ -819,7 +822,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /*From:*/ (&ty::TyRef(from_r, ref from_mt), /*To: */ &ty::TyRef(to_r, ref to_mt)) => { // Target cannot outlive source, naturally. - self.sub_regions(infer::Reborrow(cast_expr.span), *to_r, *from_r); + self.sub_regions(infer::Reborrow(cast_expr.span), to_r, from_r); self.walk_cast(cast_expr, from_mt.ty, to_mt.ty); } @@ -889,7 +892,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // // FIXME(#6268) to support nested method calls, should be callee_id let callee_scope = self.tcx.region_maps.node_extent(call_expr.id); - let callee_region = ty::ReScope(callee_scope); + let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope)); debug!("callee_region={:?}", callee_region); @@ -933,8 +936,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { derefs, derefd_ty); - let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id); - let r_deref_expr = ty::ReScope(s_deref_expr); + let r_deref_expr = self.tcx.node_scope_region(deref_expr.id); for i in 0..derefs { let method_call = MethodCall::autoderef(deref_expr.id, i as u32); debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); @@ -989,7 +991,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if let ty::TyRef(r_ptr, _) = derefd_ty.sty { self.mk_subregion_due_to_dereference(deref_expr.span, - r_deref_expr, *r_ptr); + r_deref_expr, r_ptr); } match derefd_ty.builtin_deref(true, ty::NoPreference) { @@ -1003,8 +1005,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { pub fn mk_subregion_due_to_dereference(&mut self, deref_span: Span, - minimum_lifetime: ty::Region, - maximum_lifetime: ty::Region) { + minimum_lifetime: &'tcx ty::Region, + maximum_lifetime: &'tcx ty::Region) { self.sub_regions(infer::DerefPointer(deref_span), minimum_lifetime, maximum_lifetime) } @@ -1014,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { span: Span) { match cmt.cat { Categorization::Rvalue(region) => { - match region { + match *region { ty::ReScope(rvalue_scope) => { let typ = self.resolve_type(cmt.ty); dropck::check_safety_of_destructor_if_necessary(self, @@ -1023,7 +1025,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { rvalue_scope); } ty::ReStatic => {} - region => { + _ => { span_bug!(span, "unexpected rvalue region in rvalue \ destructor safety checking: `{:?}`", @@ -1049,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match mt.ty.sty { ty::TySlice(_) | ty::TyStr => { self.sub_regions(infer::IndexSlice(index_expr.span), - r_index_expr, *r_ptr); + self.tcx.mk_region(r_index_expr), r_ptr); } _ => {} } @@ -1061,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn type_of_node_must_outlive(&mut self, origin: infer::SubregionOrigin<'tcx>, id: ast::NodeId, - minimum_lifetime: ty::Region) + minimum_lifetime: &'tcx ty::Region) { let tcx = self.tcx; @@ -1132,7 +1134,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let mc = mc::MemCategorizationContext::new(self); for arg in args { let arg_ty = self.node_ty(arg.id); - let re_scope = ty::ReScope(body_scope); + let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty); debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, @@ -1168,7 +1170,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn link_autoref(&self, expr: &hir::Expr, autoderefs: usize, - autoref: &adjustment::AutoRef) + autoref: &adjustment::AutoRef<'tcx>) { debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(self); @@ -1182,8 +1184,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } adjustment::AutoUnsafe(m) => { - let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id)); - self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); + let r = self.tcx.node_scope_region(expr.id); + self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } } } @@ -1197,8 +1199,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { expr, callee_scope); let mc = mc::MemCategorizationContext::new(self); let expr_cmt = ignore_err!(mc.cat_expr(expr)); - let borrow_region = ty::ReScope(callee_scope); - self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); + let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope)); + self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt); } /// Like `link_region()`, except that the region is extracted from the type of `id`, @@ -1212,9 +1214,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { id, mutbl, cmt_borrowed); let rptr_ty = self.resolve_node_type(id); - if let ty::TyRef(&r, _) = rptr_ty.sty { + if let ty::TyRef(r, _) = rptr_ty.sty { debug!("rptr_ty={}", rptr_ty); - self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl), + self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } @@ -1225,14 +1227,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// between regions, as explained in `link_reborrowed_region()`. fn link_region(&self, span: Span, - borrow_region: &ty::Region, + borrow_region: &'tcx ty::Region, borrow_kind: ty::BorrowKind, borrow_cmt: mc::cmt<'tcx>) { let mut borrow_cmt = borrow_cmt; let mut borrow_kind = borrow_kind; let origin = infer::DataBorrowed(borrow_cmt.ty, span); - self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region); + self.type_must_outlive(origin, borrow_cmt.ty, borrow_region); loop { debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", @@ -1322,10 +1324,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// recurse and process `ref_cmt` (see case 2 above). fn link_reborrowed_region(&self, span: Span, - borrow_region: &ty::Region, + borrow_region: &'tcx ty::Region, borrow_kind: ty::BorrowKind, ref_cmt: mc::cmt<'tcx>, - ref_region: ty::Region, + ref_region: &'tcx ty::Region, mut ref_kind: ty::BorrowKind, note: mc::Note) -> Option<(mc::cmt<'tcx>, ty::BorrowKind)> @@ -1364,7 +1366,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("link_reborrowed_region: {:?} <= {:?}", borrow_region, ref_region); - self.sub_regions(cause, *borrow_region, ref_region); + self.sub_regions(cause, borrow_region, ref_region); // If we end up needing to recurse and establish a region link // with `ref_cmt`, calculate what borrow kind we will end up @@ -1436,7 +1438,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { origin: infer::ParameterOrigin, substs: &Substs<'tcx>, expr_span: Span, - expr_region: ty::Region) { + expr_region: &'tcx ty::Region) { debug!("substs_wf_in_scope(substs={:?}, \ expr_region={:?}, \ origin={:?}, \ @@ -1461,7 +1463,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { pub fn type_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, ty: Ty<'tcx>, - region: ty::Region) + region: &'tcx ty::Region) { let ty = self.resolve_type(ty); @@ -1479,7 +1481,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn components_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, components: Vec>, - region: ty::Region) + region: &'tcx ty::Region) { for component in components { let origin = origin.clone(); @@ -1510,7 +1512,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn param_ty_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, - region: ty::Region, + region: &'tcx ty::Region, param_ty: ty::ParamTy) { debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", region, param_ty, origin); @@ -1522,7 +1524,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn projection_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, - region: ty::Region, + region: &'tcx ty::Region, projection_ty: ty::ProjectionTy<'tcx>) { debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", @@ -1552,7 +1554,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // If we know that the projection outlives 'static, then we're // done here. - if env_bounds.contains(&ty::ReStatic) { + if env_bounds.contains(&&ty::ReStatic) { debug!("projection_must_outlive: 'static as declared bound"); return; } @@ -1597,7 +1599,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { let unique_bound = env_bounds[0]; debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); - if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(r)) { + if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(&r)) { debug!("projection_must_outlive: unique declared bound appears in trait ref"); self.sub_regions(origin.clone(), region, unique_bound); return; @@ -1614,7 +1616,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.verify_generic_bound(origin, generic.clone(), region, verify_bound); } - fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound { + fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound<'tcx> { match ty.sty { ty::TyParam(p) => { self.param_bound(p) @@ -1629,7 +1631,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound { + fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { let param_env = &self.parameter_environment; debug!("param_bound(param_ty={:?})", @@ -1647,7 +1649,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn projection_declared_bounds(&self, span: Span, projection_ty: ty::ProjectionTy<'tcx>) - -> Vec + -> Vec<&'tcx ty::Region> { // First assemble bounds from where clauses and traits. @@ -1662,9 +1664,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn projection_bound(&self, span: Span, - declared_bounds: Vec, + declared_bounds: Vec<&'tcx ty::Region>, projection_ty: ty::ProjectionTy<'tcx>) - -> VerifyBound { + -> VerifyBound<'tcx> { debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})", declared_bounds, projection_ty); @@ -1676,7 +1678,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) } - fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound { + fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound<'tcx> { let mut bounds = vec![]; for subty in ty.walk_shallow() { @@ -1698,7 +1700,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>) - -> Vec + -> Vec<&'tcx ty::Region> { let param_env = &self.parameter_environment; @@ -1732,7 +1734,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn declared_projection_bounds_from_trait(&self, span: Span, projection_ty: ty::ProjectionTy<'tcx>) - -> Vec + -> Vec<&'tcx ty::Region> { debug!("projection_bounds(projection_ty={:?})", projection_ty); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 030491b521d95..a85e295784e97 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -252,7 +252,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { match capture { ty::UpvarCapture::ByValue => freevar_ty, ty::UpvarCapture::ByRef(borrow) => - tcx.mk_ref(tcx.mk_region(borrow.region), + tcx.mk_ref(borrow.region, ty::TypeAndMut { ty: freevar_ty, mutbl: borrow.kind.to_mutbl_lossy(), @@ -536,7 +536,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { borrow_id: ast::NodeId, _borrow_span: Span, cmt: mc::cmt<'tcx>, - _loan_region: ty::Region, + _loan_region: &'tcx ty::Region, bk: ty::BorrowKind, _loan_cause: euv::LoanCause) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ecec4913fb7dc..b3f26c6c8386c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -416,7 +416,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { ty::ExplicitSelfCategory::Static => return, ty::ExplicitSelfCategory::ByValue => self_ty, ty::ExplicitSelfCategory::ByReference(region, mutability) => { - fcx.tcx.mk_ref(fcx.tcx.mk_region(region), ty::TypeAndMut { + fcx.tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl: mutability }) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 3e5623404ed35..6a738032adf0a 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -87,7 +87,7 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { // early-bound versions of them, visible from the // outside of the function. This is needed by, and // only populated if there are any `impl Trait`. - free_to_bound_regions: DefIdMap + free_to_bound_regions: DefIdMap<&'gcx ty::Region> } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { @@ -102,16 +102,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { return wbcx; } + let gcx = fcx.tcx.global_tcx(); let free_substs = fcx.parameter_environment.free_substs; for (i, r) in free_substs.regions().enumerate() { match *r { ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. }) => { - let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion { + let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { index: i as u32, name: name, - }); + })); wbcx.free_to_bound_regions.insert(def_id, bound_region); } _ => { @@ -311,9 +312,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // Convert the type from the function into a type valid outside // the function, by replacing free regions with early-bound ones. let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { - match r { + match *r { // 'static is valid everywhere. - ty::ReStatic => ty::ReStatic, + ty::ReStatic => gcx.mk_region(ty::ReStatic), // Free regions that come from early-bound regions are valid. ty::ReFree(ty::FreeRegion { @@ -331,7 +332,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { span_err!(self.tcx().sess, span, E0564, "only named lifetimes are allowed in `impl Trait`, \ but `{}` was found in the type `{}`", r, inside_ty); - ty::ReStatic + gcx.mk_region(ty::ReStatic) } ty::ReVar(_) | @@ -626,12 +627,12 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { } } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(e) => { self.report_error(e); - ty::ReStatic + self.tcx.mk_region(ty::ReStatic) } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 4362e040d2661..c522d9fce0e99 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None), (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => { - infcx.sub_regions(infer::RelateObjectBound(span), *r_b, *r_a); + infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7e1fb32881d6f..2b2b1d3154f5a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1919,7 +1919,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_id: ast::NodeId, param_bounds: &[hir::TyParamBound], where_clause: &hir::WhereClause) - -> ty::ObjectLifetimeDefault + -> ty::ObjectLifetimeDefault<'tcx> { let inline_bounds = from_bounds(ccx, param_bounds); let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); @@ -1937,7 +1937,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, bounds: &[hir::TyParamBound]) - -> Vec + -> Vec<&'tcx ty::Region> { bounds.iter() .filter_map(|bound| { @@ -1954,7 +1954,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_id: ast::NodeId, predicates: &[hir::WherePredicate]) - -> Vec + -> Vec<&'tcx ty::Region> { predicates.iter() .flat_map(|predicate| { @@ -2126,7 +2126,7 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, } Substs::for_item(tcx, def_id, - |def, _| def.to_early_bound_region(), + |def, _| tcx.mk_region(def.to_early_bound_region()), |def, _| tcx.mk_param_from_def(def)) } diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 7d3bd095a3a88..637df52e3cb03 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -58,8 +58,8 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region) -> bool { - match r { + fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + match *r { ty::ReEarlyBound(data) => { self.parameters.push(Parameter::Region(data)); } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 9aca779dd89c4..f5b13c4207d90 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -257,12 +257,12 @@ impl RegionScope for BindingRscope { /// A scope which overrides the default object lifetime but has no other effect. pub struct ObjectLifetimeDefaultRscope<'r> { base_scope: &'r (RegionScope+'r), - default: ty::ObjectLifetimeDefault, + default: ty::ObjectLifetimeDefault<'r>, } impl<'r> ObjectLifetimeDefaultRscope<'r> { pub fn new(base_scope: &'r (RegionScope+'r), - default: ty::ObjectLifetimeDefault) + default: ty::ObjectLifetimeDefault<'r>) -> ObjectLifetimeDefaultRscope<'r> { ObjectLifetimeDefaultRscope { @@ -283,7 +283,7 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { Some(self.base_object_lifetime_default(span)), ty::ObjectLifetimeDefault::Specific(r) => - Some(r), + Some(*r), } } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 536fa629fd611..5fd03cbd054b0 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -483,9 +483,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// context with ambient variance `variance` fn add_constraints_from_region(&mut self, generics: &ty::Generics<'tcx>, - region: ty::Region, + region: &'tcx ty::Region, variance: VarianceTermPtr<'a>) { - match region { + match *region { ty::ReEarlyBound(ref data) => { assert_eq!(generics.parent, None); assert!((data.index as usize) < generics.regions.len()); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 51a697dad2fd6..e0a6f40c86033 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -821,7 +821,7 @@ impl Clean for hir::LifetimeDef { } } -impl Clean for ty::RegionParameterDef { +impl<'tcx> Clean for ty::RegionParameterDef<'tcx> { fn clean(&self, _: &DocContext) -> Lifetime { Lifetime(self.name.to_string()) } @@ -913,7 +913,7 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } } -impl Clean for ty::OutlivesPredicate { +impl<'tcx> Clean for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref a, ref b) = *self; WherePredicate::RegionPredicate { @@ -923,7 +923,7 @@ impl Clean for ty::OutlivesPredicate { } } -impl<'tcx> Clean for ty::OutlivesPredicate, ty::Region> { +impl<'tcx> Clean for ty::OutlivesPredicate, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref ty, ref lt) = *self; From 7a8d4822d8eb922f0cd50e92f420b5f1938db64d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 27 Aug 2016 01:13:48 +0300 Subject: [PATCH 301/768] rustc: use Vec in Substs, where Kind is a &TyS | &Region tagged pointer. --- src/librustc/lib.rs | 1 + src/librustc/middle/cstore.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 54 ++-- src/librustc/traits/fulfill.rs | 4 +- src/librustc/traits/select.rs | 34 ++- src/librustc/traits/util.rs | 8 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/flags.rs | 4 +- src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 43 ++- src/librustc/ty/relate.rs | 25 +- src/librustc/ty/sty.rs | 13 +- src/librustc/ty/subst.rs | 246 +++++++++++++----- src/librustc/ty/util.rs | 2 +- src/librustc/ty/walk.rs | 41 ++- src/librustc/util/ppaux.rs | 21 +- .../borrowck/mir/elaborate_drops.rs | 5 +- src/librustc_driver/test.rs | 9 +- src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/tydecode.rs | 18 +- src/librustc_metadata/tyencode.rs | 16 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/scope.rs | 6 +- src/librustc_mir/hair/cx/mod.rs | 4 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 4 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/trans_item.rs | 2 +- src/librustc_typeck/astconv.rs | 5 +- src/librustc_typeck/check/autoderef.rs | 2 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 7 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 63 ++--- src/librustc_typeck/check/regionck.rs | 8 +- src/librustc_typeck/check/wfcheck.rs | 34 +-- src/librustc_typeck/check/writeback.rs | 7 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 56 ++-- src/librustc_typeck/variance/constraints.rs | 25 +- src/librustc_typeck/variance/solve.rs | 19 +- src/librustc_typeck/variance/terms.rs | 31 +-- src/librustdoc/clean/mod.rs | 4 +- .../compile-fail/variance-associated-types.rs | 4 +- .../compile-fail/variance-object-types.rs | 2 +- .../compile-fail/variance-region-bounds.rs | 4 +- .../compile-fail/variance-regions-direct.rs | 14 +- .../compile-fail/variance-regions-indirect.rs | 10 +- .../compile-fail/variance-trait-bounds.rs | 18 +- .../variance-trait-object-bound.rs | 2 +- .../compile-fail/variance-types-bounds.rs | 20 +- src/test/compile-fail/variance-types.rs | 12 +- 57 files changed, 532 insertions(+), 409 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 48ea953cc1e8b..1e4b2e9116fd2 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -27,6 +27,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(collections)] +#![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(enumset)] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 381a86a42d482..b33bc520fe216 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -149,7 +149,7 @@ pub trait CrateStore<'tcx> { fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind; fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx>; - fn item_variances(&self, def: DefId) -> ty::ItemVariances; + fn item_variances(&self, def: DefId) -> Vec; fn repr_attrs(&self, def: DefId) -> Vec; fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx>; @@ -328,7 +328,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") } fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { bug!("closure_ty") } - fn item_variances(&self, def: DefId) -> ty::ItemVariances { bug!("item_variances") } + fn item_variances(&self, def: DefId) -> Vec { bug!("item_variances") } fn repr_attrs(&self, def: DefId) -> Vec { bug!("repr_attrs") } fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx> { bug!("item_type") } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8369a6c39d54d..ebe4050022153 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -89,9 +89,12 @@ struct LifetimeContext<'a, 'tcx: 'a> { #[derive(PartialEq, Debug)] enum ScopeChain<'a> { - /// EarlyScope(['a, 'b, ...], s) extends s with early-bound - /// lifetimes. - EarlyScope(&'a [hir::LifetimeDef], Scope<'a>), + /// EarlyScope(['a, 'b, ...], start, s) extends s with early-bound + /// lifetimes, with consecutive parameter indices from `start`. + /// That is, 'a has index `start`, 'b has index `start + 1`, etc. + /// Indices before `start` correspond to other generic parameters + /// of a parent item (trait/impl of a method), or `Self` in traits. + EarlyScope(&'a [hir::LifetimeDef], u32, Scope<'a>), /// LateScope(['a, 'b, ...], s) extends s with late-bound /// lifetimes introduced by the declaration binder_id. LateScope(&'a [hir::LifetimeDef], Scope<'a>), @@ -157,7 +160,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { hir::ItemImpl(_, _, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; - this.with(EarlyScope(lifetimes, &ROOT_SCOPE), |old_scope, this| { + let start = if let hir::ItemTrait(..) = item.node { + 1 // Self comes before lifetimes + } else { + 0 + }; + this.with(EarlyScope(lifetimes, start, &ROOT_SCOPE), |old_scope, this| { this.check_lifetime_defs(old_scope, lifetimes); intravisit::walk_item(this, item); }); @@ -461,7 +469,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { FnScope { s, .. } => { scope = s; } RootScope => { return; } - EarlyScope(lifetimes, s) | + EarlyScope(lifetimes, _, s) | LateScope(lifetimes, s) => { for lifetime_def in lifetimes { // FIXME (#24278): non-hygienic comparison @@ -566,8 +574,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .cloned() .partition(|l| self.map.late_bound.contains_key(&l.lifetime.id)); + // Find the start of nested early scopes, e.g. in methods. + let mut start = 0; + if let EarlyScope(..) = *self.scope { + let parent = self.hir_map.expect_item(self.hir_map.get_parent(fn_id)); + if let hir::ItemTrait(..) = parent.node { + start += 1; // Self comes first. + } + match parent.node { + hir::ItemTrait(_, ref generics, _, _) | + hir::ItemImpl(_, _, ref generics, _, _, _) => { + start += generics.lifetimes.len() + generics.ty_params.len(); + } + _ => {} + } + } + let this = self; - this.with(EarlyScope(&early, this.scope), move |old_scope, this| { + this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| { this.with(LateScope(&late, this.scope), move |_, this| { this.check_lifetime_defs(old_scope, &generics.lifetimes); walk(this); @@ -597,19 +621,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break; } - EarlyScope(lifetimes, s) => { + EarlyScope(lifetimes, start, s) => { match search_lifetimes(lifetimes, lifetime_ref) { - Some((mut index, lifetime_def)) => { - // Adjust for nested early scopes, e.g. in methods. - let mut parent = s; - while let EarlyScope(lifetimes, s) = *parent { - index += lifetimes.len() as u32; - parent = s; - } - assert_eq!(*parent, RootScope); - + Some((index, lifetime_def)) => { let decl_id = lifetime_def.id; - let def = DefEarlyBoundRegion(index, decl_id); + let def = DefEarlyBoundRegion(start + index, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -671,7 +687,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break; } - EarlyScope(lifetimes, s) | + EarlyScope(lifetimes, _, s) | LateScope(lifetimes, s) => { search_result = search_lifetimes(lifetimes, lifetime_ref); if search_result.is_some() { @@ -767,7 +783,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - EarlyScope(lifetimes, s) | + EarlyScope(lifetimes, _, s) | LateScope(lifetimes, s) => { if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { signal_shadowing_problem( diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index a0e25d54a1321..6598aacc1d3d2 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -162,7 +162,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { let concrete_ty = ty_scheme.ty.subst(tcx, substs); let predicate = ty::TraitRef { def_id: self.predicate.def_id(), - substs: Substs::new_trait(tcx, vec![], vec![], concrete_ty) + substs: Substs::new_trait(tcx, concrete_ty, &[]) }.to_predicate(); let original_obligation = Obligation::new(self.cause.clone(), @@ -440,7 +440,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't { t.skip_binder() // ok b/c this check doesn't care about regions .input_types() - .map(|t| selcx.infcx().resolve_type_vars_if_possible(t)) + .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false }) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8adf6e19f39d7..b015de79be5c6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -36,7 +36,7 @@ use super::util; use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin}; -use ty::subst::{Subst, Substs}; +use ty::subst::{Kind, Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use traits; use ty::fast_reject; @@ -1933,7 +1933,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // for `PhantomData`, we pass `T` ty::TyStruct(def, substs) if def.is_phantom_data() => { - substs.types().cloned().collect() + substs.types().collect() } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -1982,7 +1982,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_def_id, recursion_depth, normalized_ty, - vec![]); + &[]); obligations.push(skol_obligation); this.infcx().plug_leaks(skol_map, snapshot, &obligations) }) @@ -2180,8 +2180,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let input_types = data.principal.input_types(); let assoc_types = data.projection_bounds.iter() .map(|pb| pb.skip_binder().ty); - let all_types: Vec<_> = input_types.cloned() - .chain(assoc_types) + let all_types: Vec<_> = input_types.chain(assoc_types) .collect(); // reintroduce the two binding levels we skipped, then flatten into one @@ -2598,14 +2597,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // TyError and ensure they do not affect any other fields. // This could be checked after type collection for any struct // with a potentially unsized trailing field. - let types = substs_a.types().enumerate().map(|(i, ty)| { + let params = substs_a.params().iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { - tcx.types.err + Kind::from(tcx.types.err) } else { - ty + k } - }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); + }); + let substs = Substs::new(tcx, params); for &ty in fields.split_last().unwrap().1 { if ty.subst(tcx, substs).references_error() { return Err(Unimplemented); @@ -2618,15 +2617,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Check that the source structure with the target's // type parameters is a subtype of the target. - let types = substs_a.types().enumerate().map(|(i, ty)| { + let params = substs_a.params().iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { - substs_b.type_at(i) + Kind::from(substs_b.type_at(i)) } else { - ty + k } - }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); - let new_struct = tcx.mk_struct(def, substs); + }); + let new_struct = tcx.mk_struct(def, Substs::new(tcx, params)); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) @@ -2639,7 +2637,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.recursion_depth + 1, inner_source, - vec![inner_target])); + &[inner_target])); } _ => bug!() @@ -2753,7 +2751,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.skip_binder().input_types() .zip(impl_trait_ref.input_types()) - .any(|(&obligation_ty, &impl_ty)| { + .any(|(obligation_ty, impl_ty)| { let simplified_obligation_ty = fast_reject::simplify_type(self.tcx(), obligation_ty, true); let simplified_impl_ty = diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 1954ce1993c5e..038de25312d35 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Ok(def_id) => { Ok(ty::TraitRef { def_id: def_id, - substs: Substs::new_trait(self, vec![], vec![], param_ty) + substs: Substs::new_trait(self, param_ty, &[]) }) } Err(e) => { @@ -401,12 +401,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, recursion_depth: usize, param_ty: Ty<'tcx>, - ty_params: Vec>) + ty_params: &[Ty<'tcx>]) -> PredicateObligation<'tcx> { let trait_ref = ty::TraitRef { def_id: trait_def_id, - substs: Substs::new_trait(self, ty_params, vec![], param_ty) + substs: Substs::new_trait(self, param_ty, ty_params) }; predicate_for_trait_ref(cause, trait_ref, recursion_depth) } @@ -496,7 +496,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, - substs: Substs::new_trait(self, vec![arguments_tuple], vec![], self_ty), + substs: Substs::new_trait(self, self_ty, &[arguments_tuple]), }; ty::Binder((trait_ref, sig.0.output)) } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e69c395a6fb..e048e618e84d6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1152,7 +1152,7 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { impl_interners!('tcx, type_list: mk_type_list(Vec>, keep_local) -> [Ty<'tcx>], substs: mk_substs(Substs<'tcx>, |substs: &Substs| { - substs.types().any(keep_local) || substs.regions().any(keep_local) + substs.params().iter().any(keep_local) }) -> Substs<'tcx>, bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| { keep_local(&fty.sig) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 20235cf6d79d6..1afd49ab47fbf 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -208,11 +208,11 @@ impl FlagComputation { } fn add_substs(&mut self, substs: &Substs) { - for &ty in substs.types() { + for ty in substs.types() { self.add_ty(ty); } - for &r in substs.regions() { + for r in substs.regions() { self.add_region(r); } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index d5686906e6a7b..0e8bea86178f3 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -38,7 +38,7 @@ dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc Option> } dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } -dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc } +dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc> } dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3079deff1b641..759dc30037210 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -417,21 +417,6 @@ pub struct AssociatedType<'tcx> { pub container: ImplOrTraitItemContainer, } -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] -pub struct ItemVariances { - pub types: Vec, - pub regions: Vec, -} - -impl ItemVariances { - pub fn empty() -> ItemVariances { - ItemVariances { - types: vec![], - regions: vec![], - } - } -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -755,6 +740,20 @@ pub struct Generics<'tcx> { pub has_self: bool, } +impl<'tcx> Generics<'tcx> { + pub fn parent_count(&self) -> usize { + self.parent_regions as usize + self.parent_types as usize + } + + pub fn own_count(&self) -> usize { + self.regions.len() + self.types.len() + } + + pub fn count(&self) -> usize { + self.parent_count() + self.own_count() + } +} + /// Bounds on generics. #[derive(Clone)] pub struct GenericPredicates<'tcx> { @@ -963,7 +962,7 @@ impl<'tcx> TraitPredicate<'tcx> { DepNode::TraitSelect(self.def_id(), def_ids) } - pub fn input_types(&self) -> slice::Iter> { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { self.trait_ref.input_types() } @@ -1107,7 +1106,7 @@ impl<'tcx> Predicate<'tcx> { pub fn walk_tys(&self) -> IntoIter> { let vec: Vec<_> = match *self { ty::Predicate::Trait(ref data) => { - data.skip_binder().input_types().cloned().collect() + data.skip_binder().input_types().collect() } ty::Predicate::Rfc1592(ref data) => { return data.walk_tys() @@ -1123,9 +1122,7 @@ impl<'tcx> Predicate<'tcx> { } ty::Predicate::Projection(ref data) => { let trait_inputs = data.0.projection_ty.trait_ref.input_types(); - trait_inputs.cloned() - .chain(Some(data.0.ty)) - .collect() + trait_inputs.chain(Some(data.0.ty)).collect() } ty::Predicate::WellFormed(data) => { vec![data] @@ -1208,7 +1205,7 @@ impl<'tcx> TraitRef<'tcx> { self.substs.type_at(0) } - pub fn input_types(&self) -> slice::Iter> { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { // Select only the "input types" from a trait-reference. For // now this is all the types that appear in the // trait-reference, but it should eventually exclude @@ -1865,7 +1862,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { }; let sized_predicate = Binder(TraitRef { def_id: sized_trait, - substs: Substs::new_trait(tcx, vec![], vec![], ty) + substs: Substs::new_trait(tcx, ty, &[]) }).to_predicate(); let predicates = tcx.lookup_predicates(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { @@ -2592,7 +2589,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { || self.lookup_repr_hints(did).contains(&attr::ReprSimd) } - pub fn item_variances(self, item_id: DefId) -> Rc { + pub fn item_variances(self, item_id: DefId) -> Rc> { lookup_locally_or_in_crate_store( "item_variance_map", item_id, &self.item_variance_map, || Rc::new(self.sess.cstore.item_variances(item_id))) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8aa390cdd64e2..5c157ff32e7bb 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -14,7 +14,7 @@ //! type equality, etc. use hir::def_id::DefId; -use ty::subst::Substs; +use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; use std::rc::Rc; @@ -139,7 +139,7 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, } pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, - variances: Option<&ty::ItemVariances>, + variances: Option<&Vec>, a_subst: &'tcx Substs<'tcx>, b_subst: &'tcx Substs<'tcx>) -> RelateResult<'tcx, &'tcx Substs<'tcx>> @@ -147,17 +147,18 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, { let tcx = relation.tcx(); - let types = a_subst.types().zip(b_subst.types()).enumerate().map(|(i, (a_ty, b_ty))| { - let variance = variances.map_or(ty::Invariant, |v| v.types[i]); - relation.relate_with_variance(variance, a_ty, b_ty) - }).collect::>()?; - - let regions = a_subst.regions().zip(b_subst.regions()).enumerate().map(|(i, (a_r, b_r))| { - let variance = variances.map_or(ty::Invariant, |v| v.regions[i]); - relation.relate_with_variance(variance, a_r, b_r) - }).collect::>()?; + let params = a_subst.params().iter().zip(b_subst.params()).enumerate().map(|(i, (a, b))| { + let variance = variances.map_or(ty::Invariant, |v| v[i]); + if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) { + Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?)) + } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) { + Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?)) + } else { + bug!() + } + }); - Ok(Substs::new(tcx, types, regions)) + Substs::maybe_new(tcx, params) } impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5e0f3bc5e26f7..0e3f18c4474ea 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -21,7 +21,6 @@ use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; use std::mem; use std::ops; -use std::slice; use syntax::abi; use syntax::ast::{self, Name}; use syntax::parse::token::keywords; @@ -336,7 +335,7 @@ impl<'tcx> PolyTraitRef<'tcx> { self.0.substs } - pub fn input_types(&self) -> slice::Iter> { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -361,7 +360,7 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types(&self) -> slice::Iter>{ + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { // Select only the "input types" from a trait-reference. For // now this is all the types that appear in the // trait-reference, but it should eventually exclude @@ -377,7 +376,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { self.0.def_id } - pub fn input_types(&self) -> slice::Iter> { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -1229,13 +1228,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyEnum(_, substs) | TyStruct(_, substs) | TyAnon(_, substs) => { - substs.regions().cloned().collect() + substs.regions().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions().cloned().collect() + substs.func_substs.regions().collect() } TyProjection(ref data) => { - data.trait_ref.substs.regions().cloned().collect() + data.trait_ref.substs.regions().collect() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index b20c17c8a6677..0ccfea2330999 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -18,38 +18,151 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; -use std::slice; +use core::nonzero::NonZero; +use std::fmt; +use std::iter; +use std::marker::PhantomData; +use std::mem; + +/// An entity in the Rust typesystem, which can be one of +/// several kinds (only types and lifetimes for now). +/// To reduce memory usage, a `Kind` is a interned pointer, +/// with the lowest 2 bits being reserved for a tag to +/// indicate the type (`Ty` or `Region`) it points to. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct Kind<'tcx> { + ptr: NonZero, + marker: PhantomData<(Ty<'tcx>, &'tcx ty::Region)> +} -/////////////////////////////////////////////////////////////////////////// +const TAG_MASK: usize = 0b11; +const TYPE_TAG: usize = 0b00; +const REGION_TAG: usize = 0b01; + +impl<'tcx> From> for Kind<'tcx> { + fn from(ty: Ty<'tcx>) -> Kind<'tcx> { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); + + let ptr = ty as *const _ as usize; + Kind { + ptr: unsafe { + NonZero::new(ptr | TYPE_TAG) + }, + marker: PhantomData + } + } +} + +impl<'tcx> From<&'tcx ty::Region> for Kind<'tcx> { + fn from(r: &'tcx ty::Region) -> Kind<'tcx> { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(r) & TAG_MASK, 0); + + let ptr = r as *const _ as usize; + Kind { + ptr: unsafe { + NonZero::new(ptr | REGION_TAG) + }, + marker: PhantomData + } + } +} + +impl<'tcx> Kind<'tcx> { + #[inline] + unsafe fn downcast(self, tag: usize) -> Option<&'tcx T> { + let ptr = *self.ptr; + if ptr & TAG_MASK == tag { + Some(&*((ptr & !TAG_MASK) as *const _)) + } else { + None + } + } + + #[inline] + pub fn as_type(self) -> Option> { + unsafe { + self.downcast(TYPE_TAG) + } + } + + #[inline] + pub fn as_region(self) -> Option<&'tcx ty::Region> { + unsafe { + self.downcast(REGION_TAG) + } + } +} + +impl<'tcx> fmt::Debug for Kind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ty) = self.as_type() { + write!(f, "{:?}", ty) + } else if let Some(r) = self.as_region() { + write!(f, "{:?}", r) + } else { + write!(f, "", *self.ptr as *const ()) + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + if let Some(ty) = self.as_type() { + Kind::from(ty.fold_with(folder)) + } else if let Some(r) = self.as_region() { + Kind::from(r.fold_with(folder)) + } else { + bug!() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + if let Some(ty) = self.as_type() { + ty.visit_with(visitor) + } else if let Some(r) = self.as_region() { + r.visit_with(visitor) + } else { + bug!() + } + } +} /// A substitution mapping type/region parameters to new values. #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Substs<'tcx> { - types: Vec>, - regions: Vec, + params: Vec> } impl<'a, 'gcx, 'tcx> Substs<'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - t: Vec>, - r: Vec) - -> &'tcx Substs<'tcx> - { - tcx.mk_substs(Substs { types: t, regions: r }) + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I) + -> &'tcx Substs<'tcx> + where I: IntoIterator> { + tcx.mk_substs(Substs { + params: params.into_iter().collect() + }) + } + + pub fn maybe_new(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I) + -> Result<&'tcx Substs<'tcx>, E> + where I: IntoIterator, E>> { + Ok(tcx.mk_substs(Substs { + params: params.into_iter().collect::>()? + })) } pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mut t: Vec>, - r: Vec, - s: Ty<'tcx>) + s: Ty<'tcx>, + t: &[Ty<'tcx>]) -> &'tcx Substs<'tcx> { - t.insert(0, s); - Substs::new(tcx, t, r) + let t = iter::once(s).chain(t.iter().cloned()); + Substs::new(tcx, t.map(Kind::from)) } pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { - Substs::new(tcx, vec![], vec![]) + Substs::new(tcx, vec![]) } /// Creates a Substs for generic parameter definitions, @@ -65,16 +178,13 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { let defs = tcx.lookup_generics(def_id); - let num_regions = defs.parent_regions as usize + defs.regions.len(); - let num_types = defs.parent_types as usize + defs.types.len(); let mut substs = Substs { - regions: Vec::with_capacity(num_regions), - types: Vec::with_capacity(num_types) + params: Vec::with_capacity(defs.count()) }; substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type); - Substs::new(tcx, substs.types, substs.regions) + tcx.mk_substs(substs) } fn fill_item(&mut self, @@ -89,41 +199,59 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { self.fill_item(tcx, parent_defs, mk_region, mk_type); } + // Handle Self first, before all regions. + let mut types = defs.types.iter(); + if defs.parent.is_none() && defs.has_self { + let def = types.next().unwrap(); + let ty = mk_type(def, self); + assert_eq!(def.index as usize, self.params.len()); + self.params.push(Kind::from(ty)); + } + for def in &defs.regions { let region = mk_region(def, self); - assert_eq!(def.index as usize, self.regions.len()); - self.regions.push(region); + assert_eq!(def.index as usize, self.params.len()); + self.params.push(Kind::from(region)); } - for def in &defs.types { + for def in types { let ty = mk_type(def, self); - assert_eq!(def.index as usize, self.types.len()); - self.types.push(ty); + assert_eq!(def.index as usize, self.params.len()); + self.params.push(Kind::from(ty)); } } pub fn is_noop(&self) -> bool { - self.regions.is_empty() && self.types.is_empty() + self.params.is_empty() } #[inline] - pub fn types(&self) -> slice::Iter> { - self.types.iter() + pub fn params(&self) -> &[Kind<'tcx>] { + &self.params } #[inline] - pub fn regions(&self) -> slice::Iter { - self.regions.iter() + pub fn types(&'a self) -> impl DoubleEndedIterator> + 'a { + self.params.iter().filter_map(|k| k.as_type()) + } + + #[inline] + pub fn regions(&'a self) -> impl DoubleEndedIterator + 'a { + self.params.iter().filter_map(|k| k.as_region()) } #[inline] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - self.types[i] + self.params[i].as_type().unwrap_or_else(|| { + bug!("expected type for param #{} in {:?}", i, self.params); + }) } #[inline] pub fn region_at(&self, i: usize) -> &'tcx ty::Region { - self.regions[i] + self.params[i].as_region().unwrap_or_else(|| { + bug!("expected region for param #{} in {:?}", i, self.params); + }) } #[inline] @@ -146,19 +274,19 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { let defs = tcx.lookup_generics(source_ancestor); - let regions = target_substs.regions.iter() - .chain(&self.regions[defs.regions.len()..]).cloned().collect(); - let types = target_substs.types.iter() - .chain(&self.types[defs.types.len()..]).cloned().collect(); - Substs::new(tcx, types, regions) + tcx.mk_substs(Substs { + params: target_substs.params.iter() + .chain(&self.params[defs.own_count()..]).cloned().collect() + }) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let types = self.types.fold_with(folder); - let regions = self.regions.fold_with(folder); - Substs::new(folder.tcx(), types, regions) + let params = self.params.iter().map(|k| k.fold_with(folder)).collect(); + folder.tcx().mk_substs(Substs { + params: params + }) } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -166,7 +294,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.types.visit_with(visitor) || self.regions.visit_with(visitor) + self.params.visit_with(visitor) } } @@ -263,8 +391,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { // the specialized routine `ty::replace_late_regions()`. match *r { ty::ReEarlyBound(data) => { - match self.substs.regions.get(data.index as usize) { - Some(&r) => { + let r = self.substs.params.get(data.index as usize) + .and_then(|k| k.as_region()); + match r { + Some(r) => { self.shift_region_through_binders(r) } None => { @@ -318,9 +448,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.types.get(p.idx as usize); + let opt_ty = self.substs.params.get(p.idx as usize) + .and_then(|k| k.as_type()); let ty = match opt_ty { - Some(t) => *t, + Some(t) => t, None => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( @@ -331,7 +462,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { source_ty, p.idx, self.root_ty, - self.substs); + self.substs.params); } }; @@ -407,12 +538,11 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { let defs = tcx.lookup_generics(trait_id); - let regions = substs.regions[..defs.regions.len()].to_vec(); - let types = substs.types[..defs.types.len()].to_vec(); + let params = substs.params[..defs.own_count()].iter().cloned(); ty::TraitRef { def_id: trait_id, - substs: Substs::new(tcx, types, regions) + substs: Substs::new(tcx, params) } } } @@ -421,13 +551,13 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_ref: ty::TraitRef<'tcx>) -> ty::ExistentialTraitRef<'tcx> { - let Substs { mut types, regions } = trait_ref.substs.clone(); - - types.remove(0); + // Assert there is a Self. + trait_ref.substs.type_at(0); + let params = trait_ref.substs.params[1..].iter().cloned(); ty::ExistentialTraitRef { def_id: trait_ref.def_id, - substs: Substs::new(tcx, types, regions) + substs: Substs::new(tcx, params) } } } @@ -444,13 +574,11 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { assert!(!self_ty.has_escaping_regions()); self.map_bound(|trait_ref| { - let Substs { mut types, regions } = trait_ref.substs.clone(); - - types.insert(0, self_ty); - + let params = trait_ref.substs.params.iter().cloned(); + let params = iter::once(Kind::from(self_ty)).chain(params); ty::TraitRef { def_id: trait_ref.def_id, - substs: Substs::new(tcx, types, regions) + substs: Substs::new(tcx, params) } }) } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 96f432587b10e..dd5c6a9758abf 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -693,7 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { return false; } - substs_a.types().zip(substs_b.types()).all(|(&a, &b)| same_type(a, b)) + substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type(a, b)) } _ => { a == b diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 5a94ba3cf6cd2..409f5a85997bd 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -67,6 +67,12 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { stack.into_iter() } +// We push types on the stack in reverse order so as to +// maintain a pre-order traversal. As of the time of this +// writing, the fact that the traversal is pre-order is not +// known to be significant to any code, but it seems like the +// natural order one would expect (basically, the order of the +// types as they are written). fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | @@ -79,28 +85,28 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.push(mt.ty); } ty::TyProjection(ref data) => { - push_reversed(stack, data.trait_ref.substs.types()); + stack.extend(data.trait_ref.substs.types().rev()); } ty::TyTrait(ref obj) => { - push_reversed(stack, obj.principal.input_types()); - push_reversed(stack, &obj.projection_bounds.iter().map(|pred| { + stack.extend(obj.principal.input_types().rev()); + stack.extend(obj.projection_bounds.iter().map(|pred| { pred.0.ty - }).collect::>()); + }).rev()); } ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | ty::TyAnon(_, ref substs) => { - push_reversed(stack, substs.types()); + stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { - push_reversed(stack, substs.func_substs.types()); - push_reversed(stack, substs.upvar_tys); + stack.extend(substs.func_substs.types().rev()); + stack.extend(substs.upvar_tys.iter().cloned().rev()); } ty::TyTuple(ts) => { - push_reversed(stack, ts); + stack.extend(ts.iter().cloned().rev()); } ty::TyFnDef(_, substs, ref ft) => { - push_reversed(stack, substs.types()); + stack.extend(substs.types().rev()); push_sig_subtypes(stack, &ft.sig); } ty::TyFnPtr(ref ft) => { @@ -111,20 +117,5 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { stack.push(sig.0.output); - push_reversed(stack, &sig.0.inputs); -} - -fn push_reversed<'a, 'tcx: 'a, I>(stack: &mut Vec>, tys: I) - where I: IntoIterator>, - I::IntoIter: DoubleEndedIterator -{ - // We push slices on the stack in reverse order so as to - // maintain a pre-order traversal. As of the time of this - // writing, the fact that the traversal is pre-order is not - // known to be significant to any code, but it seems like the - // natural order one would expect (basically, the order of the - // types as they are written). - for &ty in tys.into_iter().rev() { - stack.push(ty); - } + stack.extend(sig.0.inputs.iter().cloned().rev()); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4b6234e8815ef..24b68c66e4667 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -143,14 +143,14 @@ pub fn parameterized(f: &mut fmt::Formatter, } }; - let print_regions = |f: &mut fmt::Formatter, start: &str, regions| { + let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| { // Don't print any regions if they're all erased. - if Iterator::all(&mut Clone::clone(®ions), - |r: &ty::Region| *r == ty::ReErased) { + let regions = || substs.regions().skip(skip).take(count); + if regions().all(|r: &ty::Region| *r == ty::ReErased) { return Ok(()); } - for region in regions { + for region in regions() { let region: &ty::Region = region; start_or_continue(f, start, ", ")?; if verbose { @@ -173,12 +173,12 @@ pub fn parameterized(f: &mut fmt::Formatter, Ok(()) }; - print_regions(f, "<", substs.regions().take(num_regions).skip(0))?; + print_regions(f, "<", 0, num_regions)?; let tps = substs.types().take(num_types - num_supplied_defaults) .skip(has_self as usize); - for &ty in tps { + for ty in tps { start_or_continue(f, "<", ", ")?; write!(f, "{}", ty)?; } @@ -204,7 +204,7 @@ pub fn parameterized(f: &mut fmt::Formatter, write!(f, "::{}", item_name)?; } - print_regions(f, "::<", substs.regions().take(usize::MAX).skip(num_regions))?; + print_regions(f, "::<", num_regions, usize::MAX)?; // FIXME: consider being smart with defaults here too for ty in substs.types().skip(num_types) { @@ -655,13 +655,6 @@ impl fmt::Debug for ty::Variance { } } -impl fmt::Debug for ty::ItemVariances { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ItemVariances(types={:?}, regions={:?})", - self.types, self.regions) - } -} - impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "GenericPredicates({:?})", self.predicates) diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 111646912ade3..3ff2fb8e2e527 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -16,7 +16,7 @@ use super::{drop_flag_effects_for_location, on_all_children_bits}; use super::{DropFlagState, MoveDataParamEnv}; use super::patch::MirPatch; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::mir::repr::*; use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; @@ -26,6 +26,7 @@ use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; use std::fmt; +use std::iter; use std::u32; pub struct ElaborateDrops; @@ -859,7 +860,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil())); let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new(tcx, vec![ty], vec![]); + let substs = Substs::new(tcx, iter::once(Kind::from(ty))); let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); self.patch.new_block(BasicBlockData { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index a99262d30eee3..460a6e68a5c5a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -20,13 +20,14 @@ use rustc::middle::region::{self, CodeExtent}; use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::session::{self, config}; +use std::iter; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; @@ -676,7 +677,7 @@ fn subst_ty_renumber_bound() { env.t_fn(&[t_param], env.t_nil()) }; - let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]); + let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1))); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) @@ -711,7 +712,7 @@ fn subst_ty_renumber_some_bounds() { env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) }; - let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]); + let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1))); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = (&'a isize, fn(&'a isize)) @@ -773,7 +774,7 @@ fn subst_region_renumber_region() { env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) }; - let substs = Substs::new(env.infcx.tcx, vec![], vec![re_bound1]); + let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(re_bound1))); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index d5c3a4a6bb0dc..0fd7b683067b7 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -73,7 +73,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::closure_ty(&cdata, def_id.index, tcx) } - fn item_variances(&self, def: DefId) -> ty::ItemVariances { + fn item_variances(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_item_variances(&cdata, def.index) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ccd8bb70f652d..bbda089b1c2a8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -991,7 +991,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) }).collect() } -pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances { +pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { let item_doc = cdata.lookup_item(id); let variance_doc = reader::get_doc(item_doc, tag_item_variances); let mut decoder = reader::Decoder::new(variance_doc); diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 3b022448efa5d..f51299226fe7d 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -20,7 +20,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use middle::region; -use rustc::ty::subst::Substs; +use rustc::ty::subst::{Kind, Substs}; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rbml; @@ -129,19 +129,19 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { - let mut regions = vec![]; - let mut types = vec![]; + let mut params = vec![]; assert_eq!(self.next(), '['); - while self.peek() != '|' { - regions.push(self.parse_region()); - } - assert_eq!(self.next(), '|'); while self.peek() != ']' { - types.push(self.parse_ty()); + let k = match self.next() { + 'r' => Kind::from(self.parse_region()), + 't' => Kind::from(self.parse_ty()), + _ => bug!() + }; + params.push(k); } assert_eq!(self.next(), ']'); - Substs::new(self.tcx, types, regions) + Substs::new(self.tcx, params) } pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> { diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index f502ec4554328..7255eae61d453 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -251,12 +251,16 @@ fn enc_opt(w: &mut Cursor>, t: Option, enc_f: F) where pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, substs: &Substs<'tcx>) { write!(w, "["); - for &r in substs.regions() { - enc_region(w, cx, r); - } - write!(w, "|"); - for &ty in substs.types() { - enc_ty(w, cx, ty); + for &k in substs.params() { + if let Some(ty) = k.as_type() { + write!(w, "t"); + enc_ty(w, cx, ty); + } else if let Some(r) = k.as_region() { + write!(w, "r"); + enc_region(w, cx, r); + } else { + bug!() + } } write!(w, "]"); } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 8c9ed53c8ab4d..bf43bfb326a58 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -293,7 +293,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(ty.is_slice()); let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap(); let ty = mt.ty; - let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, vec![ty]); + let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 2f83c0ef1bebb..0b33e5a145083 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -89,13 +89,15 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; -use rustc::ty::subst::{Substs, Subst}; +use rustc::ty::subst::{Kind, Substs, Subst}; use rustc::ty::{Ty, TyCtxt}; use rustc::mir::repr::*; use syntax_pos::Span; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::fnv::FnvHashMap; +use std::iter; + pub struct Scope<'tcx> { /// the scope-id within the scope_auxiliary id: ScopeId, @@ -789,7 +791,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> TerminatorKind<'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new(tcx, vec![data.item_ty], vec![]); + let substs = Substs::new(tcx, iter::once(Kind::from(data.item_ty))); TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 972e7f5be7075..a38b429333b70 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -144,10 +144,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { trait_def_id: DefId, method_name: &str, self_ty: Ty<'tcx>, - params: Vec>) + params: &[Ty<'tcx>]) -> (Ty<'tcx>, Literal<'tcx>) { let method_name = token::intern(method_name); - let substs = Substs::new_trait(self.tcx, params, vec![], self_ty); + let substs = Substs::new_trait(self.tcx, self_ty, params); for trait_item in self.tcx.trait_items(trait_def_id).iter() { match *trait_item { ty::ImplOrTraitItem::MethodTraitItem(ref method) => { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 165884c8f55a2..5e431193a2c4c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -514,7 +514,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx -> CustomCoerceUnsized { let trait_ref = ty::Binder(ty::TraitRef { def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), - substs: Substs::new_trait(scx.tcx(), vec![target_ty], vec![], source_ty) + substs: Substs::new_trait(scx.tcx(), source_ty, &[target_ty]) }); match fulfill_obligation(scx, DUMMY_SP, trait_ref) { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index b0afc147e6f9d..8dd76535cf811 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -753,7 +753,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, .drop_trait() .unwrap(); - let self_type_substs = Substs::new_trait(scx.tcx(), vec![], vec![], ty); + let self_type_substs = Substs::new_trait(scx.tcx(), ty, &[]); let trait_ref = ty::TraitRef { def_id: drop_trait_def_id, diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 49aa19557309f..67d4a0e044c9c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -345,7 +345,7 @@ impl<'tcx> TypeMap<'tcx> { if substs.types().next().is_some() { output.push('<'); - for &type_parameter in substs.types() { + for type_parameter in substs.types() { let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter); let param_type_id = diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 72a91f50be35e..4d8a9a2ac40d7 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -354,7 +354,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } name_to_append_suffix_to.push('<'); - for (i, &actual_type) in substs.types().enumerate() { + for (i, actual_type) in substs.types().enumerate() { if i != 0 { name_to_append_suffix_to.push_str(","); } @@ -372,7 +372,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { let names = get_type_parameter_names(cx, generics); substs.types().zip(names).map(|(ty, name)| { - let actual_type = cx.tcx().normalize_associated_type(ty); + let actual_type = cx.tcx().normalize_associated_type(&ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); let name = CString::new(name.as_str().as_bytes()).unwrap(); unsafe { diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 9337f7e58ffcc..f757578e6954d 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -181,7 +181,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push('<'); - for &type_parameter in substs.types() { + for type_parameter in substs.types() { push_debuginfo_type_name(cx, type_parameter, true, output); output.push_str(", "); } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6a072c84dd9b3..f29d85f3b52f0 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -302,7 +302,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let trait_ref = ty::Binder(ty::TraitRef { def_id: tcx.lang_items.drop_trait().unwrap(), - substs: Substs::new_trait(tcx, vec![], vec![], t) + substs: Substs::new_trait(tcx, t, &[]) }); let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 93302ab3b3be1..2c91c408487b8 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -541,7 +541,7 @@ fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push('<'); - for &type_parameter in substs.types() { + for type_parameter in substs.types() { push_unique_type_name(tcx, type_parameter, output); output.push_str(", "); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 79c4a9af8295c..f24a7cf2121eb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -473,7 +473,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { - tcx.mk_region(regions[def.index as usize]) + let i = def.index as usize - self_ty.is_some() as usize; + tcx.mk_region(regions[i]) }, |def, substs| { let i = def.index as usize; @@ -482,7 +483,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { return ty; } - let i = i - self_ty.is_some() as usize; + let i = i - self_ty.is_some() as usize - decl_generics.regions.len(); if num_types_provided.map_or(false, |n| i < n) { // A provided type parameter. match *parameters { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 9a3cbabe55331..19261a2447f91 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { Some(f) => f, None => return None }, - substs: Substs::new_trait(tcx, vec![], vec![], self.cur_ty) + substs: Substs::new_trait(tcx, self.cur_ty, &[]) }; let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 7126478f2c426..26a4705528976 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -458,7 +458,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_unsized_did, 0, source, - vec![target])); + &[target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 9197bdaa030cd..be77ca435a18c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -327,21 +327,22 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes + let supplied_start = substs.params().len() + method.generics.regions.len(); Substs::for_item(self.tcx, method.def_id, |def, _| { let i = def.index as usize; - if i < substs.regions().count() { + if i < substs.params().len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.types().count() { + if i < substs.params().len() { substs.type_at(i) } else if supplied_method_types.is_empty() { self.type_var_for_def(self.span, def, cur_substs) } else { - supplied_method_types[i - substs.types().count()] + supplied_method_types[i - supplied_start] } }) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e38d6aa7a00d7..a64982cd1bf81 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1237,7 +1237,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } else { let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { let i = def.index as usize; - if i < substs.regions().count() { + if i < substs.params().len() { substs.region_at(i) } else { // In general, during probe we erase regions. See @@ -1246,7 +1246,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.types().count() { + if i < substs.params().len() { substs.type_at(i) } else { self.type_var_for_def(self.span, def, cur_substs) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 573dae46456ba..f9699a55f5068 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| { let fn_once_substs = - Substs::new_trait(tcx, vec![self.next_ty_var()], vec![], ty); + Substs::new_trait(tcx, ty, &[self.next_ty_var()]); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = Obligation::misc(span, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cc7eadefeb099..e972a5ca7fb38 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -770,7 +770,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } hir::ItemTy(_, ref generics) => { let pty_ty = ccx.tcx.node_id_to_type(it.id); - check_bounds_are_used(ccx, &generics.ty_params, pty_ty); + check_bounds_are_used(ccx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { if m.abi == Abi::RustIntrinsic { @@ -1899,7 +1899,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Registers obligations that all types appearing in `substs` are well-formed. pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr) { - for &ty in substs.types() { + for ty in substs.types() { self.register_wf_obligation(ty, expr.span, traits::MiscObligation); } } @@ -4242,18 +4242,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_path_parameter_count(span, !require_type_space, &mut type_segment); self.check_path_parameter_count(span, true, &mut fn_segment); + let (fn_start, has_self) = match (type_segment, fn_segment) { + (_, Some((_, generics))) => { + (generics.parent_count(), generics.has_self) + } + (Some((_, generics)), None) => { + (generics.own_count(), generics.has_self) + } + (None, None) => (0, false) + }; let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| { let mut i = def.index as usize; - let type_regions = match (type_segment, fn_segment) { - (_, Some((_, generics))) => generics.parent_regions as usize, - (Some((_, generics)), None) => generics.regions.len(), - (None, None) => 0 - }; - let segment = if i < type_regions { + let segment = if i < fn_start { + i -= has_self as usize; type_segment } else { - i -= type_regions; + i -= fn_start; fn_segment }; let lifetimes = match segment.map(|(s, _)| &s.parameters) { @@ -4269,18 +4274,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }, |def, substs| { let mut i = def.index as usize; - let (type_types, has_self) = match (type_segment, fn_segment) { - (_, Some((_, generics))) => { - (generics.parent_types as usize, generics.has_self) - } - (Some((_, generics)), None) => { - (generics.types.len(), generics.has_self) - } - (None, None) => (0, false) - }; - let can_omit = i >= type_types || !require_type_space; - let segment = if i < type_types { + let can_omit = i >= fn_start || !require_type_space; + let segment = if i < fn_start { // Handle Self first, so we can adjust the index to match the AST. if has_self && i == 0 { return opt_self_ty.unwrap_or_else(|| { @@ -4290,7 +4286,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= has_self as usize; type_segment } else { - i -= type_types; + i -= fn_start; fn_segment }; let types = match segment.map(|(s, _)| &s.parameters) { @@ -4299,6 +4295,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => &[] }; + // Skip over the lifetimes in the same segment. + if let Some((_, generics)) = segment { + i -= generics.regions.len(); + } + let omitted = can_omit && types.is_empty(); if let Some(ast_ty) = types.get(i) { // A provided type parameter. @@ -4502,28 +4503,28 @@ pub fn may_break(tcx: TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool { } pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - tps: &[hir::TyParam], + generics: &hir::Generics, ty: Ty<'tcx>) { debug!("check_bounds_are_used(n_tps={}, ty={:?})", - tps.len(), ty); + generics.ty_params.len(), ty); // make a vector of booleans initially false, set to true when used - if tps.is_empty() { return; } - let mut tps_used = vec![false; tps.len()]; + if generics.ty_params.is_empty() { return; } + let mut tps_used = vec![false; generics.ty_params.len()]; for leaf_ty in ty.walk() { if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty { debug!("Found use of ty param num {}", idx); - tps_used[idx as usize] = true; + tps_used[idx as usize - generics.lifetimes.len()] = true; } } - for (i, b) in tps_used.iter().enumerate() { - if !*b { - struct_span_err!(ccx.tcx.sess, tps[i].span, E0091, + for (&used, param) in tps_used.iter().zip(&generics.ty_params) { + if !used { + struct_span_err!(ccx.tcx.sess, param.span, E0091, "type parameter `{}` is unused", - tps[i].name) - .span_label(tps[i].span, &format!("unused type parameter")) + param.name) + .span_label(param.span, &format!("unused type parameter")) .emit(); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 5f5cda358ff2f..cef2bb07e35ca 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1447,11 +1447,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for ®ion in substs.regions() { + for region in substs.regions() { self.sub_regions(origin.clone(), expr_region, region); } - for &ty in substs.types() { + for ty in substs.types() { let ty = self.resolve_type(ty); self.type_must_outlive(origin.clone(), ty, expr_region); } @@ -1577,11 +1577,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if env_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); - for &component_ty in projection_ty.trait_ref.substs.types() { + for component_ty in projection_ty.trait_ref.substs.types() { self.type_must_outlive(origin.clone(), component_ty, region); } - for &r in projection_ty.trait_ref.substs.regions() { + for r in projection_ty.trait_ref.substs.regions() { self.sub_regions(origin.clone(), region, r); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b3f26c6c8386c..38ec7ba686f6f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -457,7 +457,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let variances = self.tcx().item_variances(item_def_id); let mut constrained_parameters: HashSet<_> = - variances.types + variances[ast_generics.lifetimes.len()..] .iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) .map(|(index, _)| self.param_ty(ast_generics, index)) @@ -468,22 +468,22 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { None, &mut constrained_parameters); - for (index, _) in variances.types.iter().enumerate() { - let param_ty = self.param_ty(ast_generics, index); - if constrained_parameters.contains(&Parameter::Type(param_ty)) { - continue; - } - let span = ast_generics.ty_params[index].span; - self.report_bivariance(span, param_ty.name); - } - - for (index, &variance) in variances.regions.iter().enumerate() { - if variance != ty::Bivariant { - continue; - } + for (index, &variance) in variances.iter().enumerate() { + let (span, name) = if index < ast_generics.lifetimes.len() { + if variance != ty::Bivariant { + continue; + } - let span = ast_generics.lifetimes[index].lifetime.span; - let name = ast_generics.lifetimes[index].lifetime.name; + (ast_generics.lifetimes[index].lifetime.span, + ast_generics.lifetimes[index].lifetime.name) + } else { + let index = index - ast_generics.lifetimes.len(); + let param_ty = self.param_ty(ast_generics, index); + if constrained_parameters.contains(&Parameter::Type(param_ty)) { + continue; + } + (ast_generics.ty_params[index].span, param_ty.name) + }; self.report_bivariance(span, name); } } @@ -597,7 +597,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait impl: take implied bounds from all types that // appear in the trait reference. let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); - trait_ref.substs.types().cloned().collect() + trait_ref.substs.types().collect() } None => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 6a738032adf0a..3bd0e890bb811 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -104,7 +104,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let gcx = fcx.tcx.global_tcx(); let free_substs = fcx.parameter_environment.free_substs; - for (i, r) in free_substs.regions().enumerate() { + for (i, k) in free_substs.params().iter().enumerate() { + let r = if let Some(r) = k.as_region() { + r + } else { + continue; + }; match *r { ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index c522d9fce0e99..7d6cee7b3bac1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_node_id); let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, - source, vec![target]); + source, &[target]); fulfill_cx.register_predicate_obligation(&infcx, predicate); // Check that all transitive obligations are satisfied. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2b2b1d3154f5a..0074d3930e29f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1486,6 +1486,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let has_self = opt_self.is_some(); let mut parent_has_self = false; + let mut own_start = has_self as u32; let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| { let generics = generics_of_def_id(ccx, def_id); assert_eq!(generics.parent, None); @@ -1493,6 +1494,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, assert_eq!(generics.parent_types, 0); assert_eq!(has_self, false); parent_has_self = generics.has_self; + own_start = generics.count() as u32; (generics.regions.len() as u32, generics.types.len() as u32) }); @@ -1500,17 +1502,18 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let regions = early_lifetimes.iter().enumerate().map(|(i, l)| { ty::RegionParameterDef { name: l.lifetime.name, - index: parent_regions + i as u32, + index: own_start + i as u32, def_id: tcx.map.local_def_id(l.lifetime.id), bounds: l.bounds.iter().map(|l| { ast_region_to_region(tcx, l) }).collect() } - }).collect(); + }).collect::>(); // Now create the real type parameters. + let type_start = own_start + regions.len() as u32; let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { - let i = parent_types + has_self as u32 + i as u32; + let i = type_start + i as u32; get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults) }); let types: Vec<_> = opt_self.into_iter().chain(types).collect(); @@ -1529,8 +1532,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.alloc_generics(ty::Generics { parent: parent_def_id, - parent_regions: parent_regions as u32, - parent_types: parent_types as u32, + parent_regions: parent_regions, + parent_types: parent_types, regions: regions, types: types, has_self: has_self || parent_has_self @@ -1741,12 +1744,12 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, -> ty::GenericPredicates<'tcx> { let tcx = ccx.tcx; - let (parent_regions, parent_types) = parent.map_or((0, 0), |def_id| { + let parent_count = parent.map_or(0, |def_id| { let generics = generics_of_def_id(ccx, def_id); assert_eq!(generics.parent, None); assert_eq!(generics.parent_regions, 0); assert_eq!(generics.parent_types, 0); - (generics.regions.len() as u32, generics.types.len() as u32) + generics.count() as u32 }); let ref base_predicates = match parent { Some(def_id) => { @@ -1762,10 +1765,29 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, }; let mut predicates = super_predicates; + // Collect the region predicates that were declared inline as + // well. In the case of parameters declared on a fn or method, we + // have to be careful to only iterate over early-bound regions. + let own_start = parent_count + has_self as u32; + let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); + for (index, param) in early_lifetimes.iter().enumerate() { + let index = own_start + index as u32; + let region = ccx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { + index: index, + name: param.lifetime.name + })); + for bound in ¶m.bounds { + let bound_region = ast_region_to_region(ccx.tcx, bound); + let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); + predicates.push(outlives.to_predicate()); + } + } + // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). + let type_start = own_start + early_lifetimes.len() as u32; for (index, param) in ast_generics.ty_params.iter().enumerate() { - let index = parent_types + has_self as u32 + index as u32; + let index = type_start + index as u32; let param_ty = ty::ParamTy::new(index, param.name).to_ty(ccx.tcx); let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), param_ty, @@ -1776,24 +1798,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, predicates.extend(bounds.predicates(ccx.tcx, param_ty)); } - // Collect the region predicates that were declared inline as - // well. In the case of parameters declared on a fn or method, we - // have to be careful to only iterate over early-bound regions. - let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); - for (index, param) in early_lifetimes.iter().enumerate() { - let index = parent_regions + index as u32; - let region = - ty::ReEarlyBound(ty::EarlyBoundRegion { - index: index, - name: param.lifetime.name - }); - for bound in ¶m.bounds { - let bound_region = ast_region_to_region(ccx.tcx, bound); - let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); - predicates.push(outlives.to_predicate()); - } - } - // Add in the bounds that appear in the where-clause let where_clause = &ast_generics.where_clause; for predicate in &where_clause.predicates { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 5fd03cbd054b0..2cf84b5745af4 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -26,7 +26,6 @@ use rustc::hir::intravisit::Visitor; use super::terms::*; use super::terms::VarianceTerm::*; -use super::terms::ParamKind::*; use super::xform::*; pub struct ConstraintContext<'a, 'tcx: 'a> { @@ -209,7 +208,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { fn declared_variance(&self, param_def_id: DefId, item_def_id: DefId, - kind: ParamKind, index: usize) -> VarianceTermPtr<'a> { assert_eq!(param_def_id.krate, item_def_id.krate); @@ -224,11 +222,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // Parameter on an item defined within another crate: // variance already inferred, just look it up. let variances = self.tcx().item_variances(item_def_id); - let variance = match kind { - TypeParam => variances.types[index], - RegionParam => variances.regions[index], - }; - self.constant_term(variance) + self.constant_term(variances[index]) } } @@ -330,7 +324,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyRef(region, ref mt) => { let contra = self.contravariant(variance); - self.add_constraints_from_region(generics, *region, contra); + self.add_constraints_from_region(generics, region, contra); self.add_constraints_from_mt(generics, mt, variance); } @@ -401,8 +395,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyParam(ref data) => { assert_eq!(generics.parent, None); - assert!((data.idx as usize) < generics.types.len()); - let def_id = generics.types[data.idx as usize].def_id; + let mut i = data.idx as usize; + if !generics.has_self || i > 0 { + i -= generics.regions.len(); + } + let def_id = generics.types[i].def_id; let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); match self.terms_cx.inferred_map.get(&node_id) { Some(&index) => { @@ -449,7 +446,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { for p in type_param_defs { let variance_decl = - self.declared_variance(p.def_id, def_id, TypeParam, p.index as usize); + self.declared_variance(p.def_id, def_id, p.index as usize); let variance_i = self.xform(variance, variance_decl); let substs_ty = substs.type_for_def(p); debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}", @@ -459,7 +456,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { for p in region_param_defs { let variance_decl = - self.declared_variance(p.def_id, def_id, RegionParam, p.index as usize); + self.declared_variance(p.def_id, def_id, p.index as usize); let variance_i = self.xform(variance, variance_decl); let substs_r = substs.region_for_def(p); self.add_constraints_from_region(generics, substs_r, variance_i); @@ -488,8 +485,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { match *region { ty::ReEarlyBound(ref data) => { assert_eq!(generics.parent, None); - assert!((data.index as usize) < generics.regions.len()); - let def_id = generics.regions[data.index as usize].def_id; + let i = data.index as usize - generics.has_self as usize; + let def_id = generics.regions[i].def_id; let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); if self.is_to_be_inferred(node_id) { let index = self.inferred_index(node_id); diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index d3b63119bcb32..82b63d0cc0937 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -21,7 +21,6 @@ use std::rc::Rc; use super::constraints::*; use super::terms::*; use super::terms::VarianceTerm::*; -use super::terms::ParamKind::*; use super::xform::*; struct SolveContext<'a, 'tcx: 'a> { @@ -109,24 +108,16 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { while index < num_inferred { let item_id = inferred_infos[index].item_id; - let mut item_variances = ty::ItemVariances::empty(); + let mut item_variances = vec![]; while index < num_inferred && inferred_infos[index].item_id == item_id { let info = &inferred_infos[index]; let variance = solutions[index]; - debug!("Index {} Info {} / {:?} Variance {:?}", - index, info.index, info.kind, variance); - match info.kind { - TypeParam => { - assert_eq!(item_variances.types.len(), info.index); - item_variances.types.push(variance); - } - RegionParam => { - assert_eq!(item_variances.regions.len(), info.index); - item_variances.regions.push(variance); - } - } + debug!("Index {} Info {} Variance {:?}", + index, info.index, variance); + assert_eq!(item_variances.len(), info.index); + item_variances.push(variance); index += 1; } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index d30cbc8f117cf..c0b53787177d5 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -31,7 +31,6 @@ use rustc::hir::intravisit::Visitor; use util::nodemap::NodeMap; use self::VarianceTerm::*; -use self::ParamKind::*; pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>; @@ -61,7 +60,7 @@ pub struct TermsContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub arena: &'a TypedArena>, - pub empty_variances: Rc, + pub empty_variances: Rc>, // For marker types, UnsafeCell, and other lang items where // variance is hardcoded, records the item-id and the hardcoded @@ -76,15 +75,8 @@ pub struct TermsContext<'a, 'tcx: 'a> { pub inferred_infos: Vec> , } -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum ParamKind { - TypeParam, - RegionParam, -} - pub struct InferredInfo<'a> { pub item_id: ast::NodeId, - pub kind: ParamKind, pub index: usize, pub param_id: ast::NodeId, pub term: VarianceTermPtr<'a>, @@ -110,7 +102,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( // cache and share the variance struct used for items with // no type/region parameters - empty_variances: Rc::new(ty::ItemVariances::empty()) + empty_variances: Rc::new(vec![]) }; // See README.md for a discussion on dep-graph management. @@ -162,17 +154,19 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { let inferreds_on_entry = self.num_inferred(); + if has_self { + self.add_inferred(item_id, 0, item_id); + } + for (i, p) in generics.lifetimes.iter().enumerate() { let id = p.lifetime.id; - self.add_inferred(item_id, RegionParam, i, id); + let i = has_self as usize + i; + self.add_inferred(item_id, i, id); } - if has_self { - self.add_inferred(item_id, TypeParam, 0, item_id); - } for (i, p) in generics.ty_params.iter().enumerate() { - let i = has_self as usize + i; - self.add_inferred(item_id, TypeParam, i, p.id); + let i = has_self as usize + generics.lifetimes.len() + i; + self.add_inferred(item_id, i, p.id); } // If this item has no type or lifetime parameters, @@ -194,14 +188,12 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { fn add_inferred(&mut self, item_id: ast::NodeId, - kind: ParamKind, index: usize, param_id: ast::NodeId) { let inf_index = InferredIndex(self.inferred_infos.len()); let term = self.arena.alloc(InferredTerm(inf_index)); let initial_variance = self.pick_initial_variance(item_id, index); self.inferred_infos.push(InferredInfo { item_id: item_id, - kind: kind, index: index, param_id: param_id, term: term, @@ -211,13 +203,12 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { debug!("add_inferred(item_path={}, \ item_id={}, \ - kind={:?}, \ index={}, \ param_id={}, \ inf_index={:?}, \ initial_variance={:?})", self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)), - item_id, kind, index, param_id, inf_index, + item_id, index, param_id, inf_index, initial_variance); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e0a6f40c86033..c8620254b6f42 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -643,7 +643,7 @@ impl Clean for hir::TyParamBound { fn external_path_params(cx: &DocContext, trait_did: Option, has_self: bool, bindings: Vec, substs: &Substs) -> PathParameters { let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect(); - let types = substs.types().skip(has_self as usize).cloned().collect::>(); + let types = substs.types().skip(has_self as usize).collect::>(); match (trait_did, cx.tcx_opt()) { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C @@ -741,7 +741,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { // collect any late bound regions let mut late_bounds = vec![]; - for &ty_s in self.input_types().skip(1) { + for ty_s in self.input_types().skip(1) { if let ty::TyTuple(ts) = ty_s.sty { for &ty_s in ts { if let ty::TyRef(ref reg, _) = ty_s.sty { diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index 5539a26d2a170..7dbfc6ac1257d 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -20,12 +20,12 @@ trait Trait<'a> { } #[rustc_variance] -struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[+], regions=[-]) +struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +] field: (T, &'a ()) } #[rustc_variance] -struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[o], regions=[o]) +struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o] field: >::Type } diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index 2f422bfd38cc7..1f54771e3676a 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -18,7 +18,7 @@ use std::cell::Cell; // For better or worse, associated types are invariant, and hence we // get an invariant result for `'a`. #[rustc_variance] -struct Foo<'a> { //~ ERROR regions=[o] +struct Foo<'a> { //~ ERROR [o] x: Box &'a i32 + 'static> } diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs index 99416057b2540..41d204a541b5a 100644 --- a/src/test/compile-fail/variance-region-bounds.rs +++ b/src/test/compile-fail/variance-region-bounds.rs @@ -13,11 +13,11 @@ #![feature(rustc_attrs)] #[rustc_variance] -trait Foo: 'static { //~ ERROR types=[o] +trait Foo: 'static { //~ ERROR [o] } #[rustc_variance] -trait Bar { //~ ERROR types=[o, o] +trait Bar { //~ ERROR [o, o] fn do_it(&self) where T: 'static; } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 78591063de8ab..bf46edcfab8b1 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -16,7 +16,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -] +struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -] x: &'a isize, y: &'b [isize], c: &'c str @@ -25,7 +25,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +] +struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), c: extern "Rust" fn(&'c str), @@ -34,7 +34,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o] +struct Test4<'a, 'b:'a> { //~ ERROR [-, o] x: &'a mut &'b isize, } @@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o] +struct Test5<'a, 'b:'a> { //~ ERROR [+, o] x: extern "Rust" fn(&'a mut &'b isize), } @@ -52,14 +52,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b:'a> { //~ ERROR regions=[-, o] +struct Test6<'a, 'b:'a> { //~ ERROR [-, o] x: &'a mut extern "Rust" fn(&'b isize), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR regions=[*] +struct Test7<'a> { //~ ERROR [*] //~^ ERROR parameter `'a` is never used x: isize } @@ -67,7 +67,7 @@ struct Test7<'a> { //~ ERROR regions=[*] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index d8af30da163bf..e28828f62e52d 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -15,7 +15,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *] //~^ ERROR parameter `'d` is never used Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), @@ -23,25 +23,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *] } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[*, o, -, +] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +] //~^ ERROR parameter `'w` is never used f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[o, o, *] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *] //~^ ERROR parameter `'c` is never used f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[o, -, *] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *] //~^ ERROR parameter `'c` is never used f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 150a1aa56fe72..4c737a7594d26 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -15,48 +15,48 @@ // influence variance. #[rustc_variance] -trait Getter { //~ ERROR types=[o, o] +trait Getter { //~ ERROR [o, o] fn get(&self) -> T; } #[rustc_variance] -trait Setter { //~ ERROR types=[o, o] +trait Setter { //~ ERROR [o, o] fn get(&self, T); } #[rustc_variance] -struct TestStruct> { //~ ERROR types=[+, +] +struct TestStruct> { //~ ERROR [+, +] t: T, u: U } #[rustc_variance] -enum TestEnum> {//~ ERROR types=[*, +] +enum TestEnum> {//~ ERROR [*, +] //~^ ERROR parameter `U` is never used Foo(T) } #[rustc_variance] -trait TestTrait> { //~ ERROR types=[o, o, o] +trait TestTrait> { //~ ERROR [o, o, o] fn getter(&self, u: U) -> T; } #[rustc_variance] -trait TestTrait2 : Getter { //~ ERROR types=[o, o] +trait TestTrait2 : Getter { //~ ERROR [o, o] } #[rustc_variance] -trait TestTrait3 { //~ ERROR types=[o, o] +trait TestTrait3 { //~ ERROR [o, o] fn getter>(&self); } #[rustc_variance] -struct TestContraStruct> { //~ ERROR types=[*, +] +struct TestContraStruct> { //~ ERROR [*, +] //~^ ERROR parameter `U` is never used t: T } #[rustc_variance] -struct TestBox+Setter> { //~ ERROR types=[*, +] +struct TestBox+Setter> { //~ ERROR [*, +] //~^ ERROR parameter `U` is never used t: T } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index 4244b0e1d8b8b..b120588ecab52 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -21,7 +21,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[-] +struct TOption<'a> { //~ ERROR [-] v: Option>, } diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index c47710d6d376d..2df94cc907a9c 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -14,46 +14,46 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct TestImm { //~ ERROR types=[+, +] +struct TestImm { //~ ERROR [+, +] x: A, y: B, } #[rustc_variance] -struct TestMut { //~ ERROR types=[+, o] +struct TestMut { //~ ERROR [+, o] x: A, y: &'static mut B, } #[rustc_variance] -struct TestIndirect { //~ ERROR types=[+, o] +struct TestIndirect { //~ ERROR [+, o] m: TestMut } #[rustc_variance] -struct TestIndirect2 { //~ ERROR types=[o, o] +struct TestIndirect2 { //~ ERROR [o, o] n: TestMut, m: TestMut } #[rustc_variance] -trait Getter { //~ ERROR types=[o, o] +trait Getter { //~ ERROR [o, o] fn get(&self) -> A; } #[rustc_variance] -trait Setter { //~ ERROR types=[o, o] +trait Setter { //~ ERROR [o, o] fn set(&mut self, a: A); } #[rustc_variance] -trait GetterSetter { //~ ERROR types=[o, o] +trait GetterSetter { //~ ERROR [o, o] fn get(&self) -> A; fn set(&mut self, a: A); } #[rustc_variance] -trait GetterInTypeBound { //~ ERROR types=[o, o] +trait GetterInTypeBound { //~ ERROR [o, o] // Here, the use of `A` in the method bound *does* affect // variance. Think of it as if the method requested a dictionary // for `T:Getter`. Since this dictionary is an input, it is @@ -63,12 +63,12 @@ trait GetterInTypeBound { //~ ERROR types=[o, o] } #[rustc_variance] -trait SetterInTypeBound { //~ ERROR types=[o, o] +trait SetterInTypeBound { //~ ERROR [o, o] fn do_it>(&self); } #[rustc_variance] -struct TestObject { //~ ERROR types=[o, o] +struct TestObject { //~ ERROR [o, o] n: Box+Send>, m: Box+Send>, } diff --git a/src/test/compile-fail/variance-types.rs b/src/test/compile-fail/variance-types.rs index d5164412358fc..7667972c9d251 100644 --- a/src/test/compile-fail/variance-types.rs +++ b/src/test/compile-fail/variance-types.rs @@ -17,32 +17,32 @@ use std::cell::Cell; // not considered bivariant. #[rustc_variance] -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[o, o], regions=[-] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o] t: &'a mut (A,B) } #[rustc_variance] -struct InvariantCell { //~ ERROR types=[o] +struct InvariantCell { //~ ERROR [o] t: Cell } #[rustc_variance] -struct InvariantIndirect { //~ ERROR types=[o] +struct InvariantIndirect { //~ ERROR [o] t: InvariantCell } #[rustc_variance] -struct Covariant { //~ ERROR types=[+] +struct Covariant { //~ ERROR [+] t: A, u: fn() -> A } #[rustc_variance] -struct Contravariant { //~ ERROR types=[-] +struct Contravariant { //~ ERROR [-] t: fn(A) } #[rustc_variance] -enum Enum { //~ ERROR types=[+, -, o] +enum Enum { //~ ERROR [+, -, o] Foo(Covariant), Bar(Contravariant), Zed(Covariant,Contravariant) From 6a5bdb78f15b8e53fa848e31c90298edf6c48d6c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 Aug 2016 17:06:13 -0500 Subject: [PATCH 302/768] add mips64-gnu and mips64el-gnu targets With this commit one can build no_core (and probably no_std as well) Rust programs for these targets. It's not yet possible to cross compile std for these targets because rust-lang/libc doesn't know about the mips64 architecture. These targets have been tested by cross compiling the "smallest hello" program (see code below) and then running it under QEMU. ``` rust #![feature(start)] #![feature(lang_items)] #![feature(no_core)] #![no_core] #[link(name = "c")] extern { fn puts(_: *const u8); } #[start] fn start(_: isize, _: *const *const u8) -> isize { unsafe { let msg = b"Hello, world!\0"; puts(msg as *const _ as *const u8); } 0 } #[lang = "copy"] trait Copy {} #[lang = "sized"] trait Sized {} ``` --- mk/cfg/mips64-unknown-linux-gnuabi64.mk | 1 + mk/cfg/mips64el-unknown-linux-gnuabi64.mk | 1 + .../target/mips64_unknown_linux_gnuabi64.rs | 31 ++++ .../target/mips64el_unknown_linux_gnuabi64.rs | 31 ++++ src/librustc_back/target/mod.rs | 2 + src/librustc_trans/abi.rs | 2 + src/librustc_trans/cabi_mips64.rs | 168 ++++++++++++++++++ src/librustc_trans/cabi_powerpc.rs | 12 +- src/librustc_trans/lib.rs | 1 + 9 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 mk/cfg/mips64-unknown-linux-gnuabi64.mk create mode 100644 mk/cfg/mips64el-unknown-linux-gnuabi64.mk create mode 100644 src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs create mode 100644 src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs create mode 100644 src/librustc_trans/cabi_mips64.rs diff --git a/mk/cfg/mips64-unknown-linux-gnuabi64.mk b/mk/cfg/mips64-unknown-linux-gnuabi64.mk new file mode 100644 index 0000000000000..34aee77ae2107 --- /dev/null +++ b/mk/cfg/mips64-unknown-linux-gnuabi64.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/cfg/mips64el-unknown-linux-gnuabi64.mk b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk new file mode 100644 index 0000000000000..34aee77ae2107 --- /dev/null +++ b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs new file mode 100644 index 0000000000000..7e45b32065360 --- /dev/null +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -0,0 +1,31 @@ +// 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. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + // NOTE(mips64r2) matches C toolchain + cpu: "mips64r2".to_string(), + features: "+mips64r2".to_string(), + max_atomic_width: 64, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs new file mode 100644 index 0000000000000..338a5da1e1d1d --- /dev/null +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -0,0 +1,31 @@ +// 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. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + // NOTE(mips64r2) matches C toolchain + cpu: "mips64r2".to_string(), + features: "+mips64r2".to_string(), + max_atomic_width: 64, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 86cd86d282cf5..3c5ec84a8fa68 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -128,6 +128,8 @@ supported_targets! { ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), + ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), + ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36bad..5e264c80c4c1c 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -21,6 +21,7 @@ use cabi_aarch64; use cabi_powerpc; use cabi_powerpc64; use cabi_mips; +use cabi_mips64; use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; @@ -498,6 +499,7 @@ impl FnType { cabi_arm::compute_abi_info(ccx, self, flavor); }, "mips" => cabi_mips::compute_abi_info(ccx, self), + "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs new file mode 100644 index 0000000000000..d3d3f83eac431 --- /dev/null +++ b/src/librustc_trans/cabi_mips64.rs @@ -0,0 +1,168 @@ +// 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. + +#![allow(non_upper_case_globals)] + +use libc::c_uint; +use std::cmp; +use llvm; +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; +use abi::{ArgType, FnType}; +use context::CrateContext; +use type_::Type; + +fn align_up_to(off: usize, a: usize) -> usize { + return (off + a - 1) / a * a; +} + +fn align(off: usize, ty: Type) -> usize { + let a = ty_align(ty); + return align_up_to(off, a); +} + +fn ty_align(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt) * len + } + _ => bug!("ty_align: unhandled type") + } +} + +fn ty_size(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) + } + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => bug!("ty_size: unhandled type") + } +} + +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(64); + } 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; + let mut align = ty_align(arg.ty); + + align = cmp::min(cmp::max(align, 4), 8); + *offset = align_up_to(*offset, align); + *offset += align_up_to(size, align * 8) / 8; + + 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(64); + } +} + +fn is_reg_ty(ty: Type) -> bool { + return match ty.kind() { + Integer + | Pointer + | Float + | Double + | Vector => true, + _ => false + }; +} + +fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { + if ((align - 1 ) & offset) > 0 { + Some(Type::i32(ccx)) + } else { + None + } +} + +fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { + let int_ty = Type::i32(ccx); + let mut args = Vec::new(); + + let mut n = size / 64; + while n > 0 { + args.push(int_ty); + n -= 1; + } + + let r = size % 64; + if r > 0 { + unsafe { + args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); + } + } + + args +} + +fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { + let size = ty_size(ty) * 8; + Type::struct_(ccx, &coerce_to_int(ccx, size), false) +} + +pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + let mut offset = if fty.ret.is_indirect() { 8 } else { 0 }; + for arg in &mut fty.args { + if arg.is_ignore() { continue; } + classify_arg_ty(ccx, arg, &mut offset); + } +} diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index efbdce67a8b2a..e05c31b1d88cd 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -28,11 +28,7 @@ fn align(off: usize, ty: Type) -> usize { fn ty_align(ty: Type) -> usize { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8 - } - } + Integer => ((ty.int_width() as usize) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -54,11 +50,7 @@ fn ty_align(ty: Type) -> usize { fn ty_size(ty: Type) -> usize { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8 - } - } + Integer => ((ty.int_width() as usize) + 7) / 8, Pointer => 4, Float => 4, Double => 8, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 1286df7b97e67..6ede55d5ff49a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -98,6 +98,7 @@ mod cabi_aarch64; mod cabi_arm; mod cabi_asmjs; mod cabi_mips; +mod cabi_mips64; mod cabi_powerpc; mod cabi_powerpc64; mod cabi_x86; From 027eab2f87d8cd30949e257cb52f520077575ff2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 Aug 2016 21:05:16 -0500 Subject: [PATCH 303/768] initial support for s390x A new target, `s390x-unknown-linux-gnu`, has been added to the compiler and can be used to build no_core/no_std Rust programs. Known limitations: - librustc_trans/cabi_s390x.rs is missing. This means no support for `extern "C" fn`. - No support for this arch in libc. This means std can be cross compiled for this target. --- mk/cfg/s390x-unknown-linux-gnu.mk | 1 + src/bootstrap/native.rs | 2 +- src/librustc_back/target/mod.rs | 1 + .../target/s390x_unknown_linux_gnu.rs | 30 +++++++++++++++++++ src/librustc_llvm/build.rs | 2 +- src/librustc_llvm/lib.rs | 6 ++++ 6 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 mk/cfg/s390x-unknown-linux-gnu.mk create mode 100644 src/librustc_back/target/s390x_unknown_linux_gnu.rs diff --git a/mk/cfg/s390x-unknown-linux-gnu.mk b/mk/cfg/s390x-unknown-linux-gnu.mk new file mode 100644 index 0000000000000..34aee77ae2107 --- /dev/null +++ b/mk/cfg/s390x-unknown-linux-gnu.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a78cef4f409b4..a4518d6ed7619 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) { .out_dir(&dst) .profile(if build.config.llvm_optimize {"Release"} else {"Debug"}) .define("LLVM_ENABLE_ASSERTIONS", assertions) - .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC") + .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ") .define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 86cd86d282cf5..86325cfe5449f 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -132,6 +132,7 @@ supported_targets! { ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), + ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs new file mode 100644 index 0000000000000..895d33d8d755a --- /dev/null +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -0,0 +1,30 @@ +// 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. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_base::opts(); + // NOTE(zEC12) matches C toolchain + base.cpu = "zEC12".to_string(); + base.max_atomic_width = 64; + + Ok(Target { + llvm_target: "s390x-unknown-linux-gnu".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(), + arch: "s390x".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 5f7a0f788ca12..ac83d860b6e90 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -66,7 +66,7 @@ fn main() { let host = env::var("HOST").unwrap(); let is_crossed = target != host; - let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl"]; + let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"]; // FIXME: surely we don't need all these components, right? Stuff like mcjit // or interpreter the compiler itself never uses. diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 6c4e1a54ea728..eb45d3d25c5c0 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -428,6 +428,12 @@ pub fn initialize_available_targets() { LLVMInitializePNaClTargetInfo, LLVMInitializePNaClTarget, LLVMInitializePNaClTargetMC); + init_target!(llvm_component = "systemz", + LLVMInitializeSystemZTargetInfo, + LLVMInitializeSystemZTarget, + LLVMInitializeSystemZTargetMC, + LLVMInitializeSystemZAsmPrinter, + LLVMInitializeSystemZAsmParser); } pub fn last_error() -> Option { From 3e313d9528adc64042012a19cc9a700bff11f19d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 27 Aug 2016 08:51:55 +0300 Subject: [PATCH 304/768] rustc_trans: don't round up the DST prefix size to its alignment. --- src/librustc_trans/common.rs | 13 +------- src/librustc_trans/context.rs | 8 +++++ src/librustc_trans/glue.rs | 21 +++++++++---- src/librustc_trans/type_of.rs | 53 ++++++++++++++------------------ src/test/run-pass/issue-35815.rs | 23 ++++++++++++++ 5 files changed, 70 insertions(+), 48 deletions(-) create mode 100644 src/test/run-pass/issue-35815.rs diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index c5053e4feee62..94e8aed7cb73b 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -124,18 +124,7 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) /// Returns true if the type is represented as a pair of immediates. pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - let tcx = ccx.tcx(); - let layout = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { - match ty.layout(&infcx) { - Ok(layout) => layout, - Err(err) => { - bug!("type_is_imm_pair: layout for `{:?}` failed: {}", - ty, err); - } - } - }); - - match *layout { + match *ccx.layout_of(ty) { Layout::FatPointer { .. } => true, Layout::Univariant { ref variant, .. } => { // There must be only 2 fields. diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 0a295b251b31e..77be9964f68b9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -947,6 +947,14 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { TypeOfDepthLock(self.local()) } + pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout { + self.tcx().normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { + ty.layout(&infcx).unwrap_or_else(|e| { + bug!("failed to get layout for `{}`: {}", ty, e); + }) + }) + } + pub fn check_overflow(&self) -> bool { self.shared.check_overflow } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6a072c84dd9b3..823c23b2e66b3 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -338,13 +338,22 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, ty::TyStruct(def, substs) => { let ccx = bcx.ccx(); // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized. + // Don't use type_of::sizing_type_of because that expects t to be sized, + // and it also rounds up to alignment, which we want to avoid, + // as the unsized field's alignment could be smaller. assert!(!t.is_simd()); - let repr = adt::represent_type(ccx, t); - let sizing_type = adt::sizing_type_of(ccx, &repr, true); - debug!("DST {} sizing_type: {:?}", t, sizing_type); - let sized_size = llsize_of_alloc(ccx, sizing_type); - let sized_align = llalign_of_min(ccx, sizing_type); + let layout = ccx.layout_of(t); + debug!("DST {} layout: {:?}", t, layout); + + let (sized_size, sized_align) = match *layout { + ty::layout::Layout::Univariant { ref variant, .. } => { + (variant.min_size().bytes(), variant.align.abi()) + } + _ => { + bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", + t, layout); + } + }; debug!("DST {} statically sized prefix size: {} align: {}", t, sized_size, sized_align); let sized_size = C_uint(ccx, sized_size); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6862002ed83b2..153df13e048db 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -15,7 +15,6 @@ use abi::FnType; use adt; use common::*; use machine; -use rustc::traits::Reveal; use rustc::ty::{self, Ty, TypeFoldable}; use type_::Type; @@ -124,37 +123,31 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ cx.llsizingtypes().borrow_mut().insert(t, llsizingty); // FIXME(eddyb) Temporary sanity check for ty::layout. - let layout = cx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| { - t.layout(&infcx) - }); - match layout { - Ok(layout) => { - if !type_is_sized(cx.tcx(), t) { - if !layout.is_unsized() { - bug!("layout should be unsized for type `{}` / {:#?}", - t, layout); - } - - // Unsized types get turned into a fat pointer for LLVM. - return llsizingty; - } - let r = layout.size(&cx.tcx().data_layout).bytes(); - let l = machine::llsize_of_alloc(cx, llsizingty); - if r != l { - bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", - r, l, t, layout); - } - let r = layout.align(&cx.tcx().data_layout).abi(); - let l = machine::llalign_of_min(cx, llsizingty) as u64; - if r != l { - bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", - r, l, t, layout); - } - } - Err(e) => { - bug!("failed to get layout for `{}`: {}", t, e); + let layout = cx.layout_of(t); + if !type_is_sized(cx.tcx(), t) { + if !layout.is_unsized() { + bug!("layout should be unsized for type `{}` / {:#?}", + t, layout); } + + // Unsized types get turned into a fat pointer for LLVM. + return llsizingty; + } + + let r = layout.size(&cx.tcx().data_layout).bytes(); + let l = machine::llsize_of_alloc(cx, llsizingty); + if r != l { + bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", + r, l, t, layout); } + + let r = layout.align(&cx.tcx().data_layout).abi(); + let l = machine::llalign_of_min(cx, llsizingty) as u64; + if r != l { + bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", + r, l, t, layout); + } + llsizingty } diff --git a/src/test/run-pass/issue-35815.rs b/src/test/run-pass/issue-35815.rs new file mode 100644 index 0000000000000..619542926500b --- /dev/null +++ b/src/test/run-pass/issue-35815.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +struct Foo { + a: i64, + b: bool, + c: T, +} + +fn main() { + let foo: &Foo = &Foo { a: 1, b: false, c: 2i32 }; + let foo_unsized: &Foo = foo; + assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized)); +} From 1b9e9ab1dc523c4778a2510e4f9e2d470fe7a4a3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 Aug 2016 20:25:59 -0500 Subject: [PATCH 305/768] update libc --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 5066b7dcab7e7..71b5d57ada32c 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b +Subproject commit 71b5d57ada32cc5076791becc3b9019da29dffd4 From 43615a03f31d3c60c4af13a1fe17bd4cf3edad06 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 01:39:29 -0500 Subject: [PATCH 306/768] fix cross compilation of std --- src/liballoc_jemalloc/lib.rs | 3 ++- src/liballoc_system/lib.rs | 3 ++- src/libpanic_unwind/gcc.rs | 2 +- src/libstd/env.rs | 6 ++++++ src/libstd/os/linux/raw.rs | 5 +++++ src/libunwind/libunwind.rs | 3 +++ 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 347e97e6ffc0a..aae0528e42cc9 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -77,7 +77,8 @@ const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", - target_arch = "powerpc64")))] + target_arch = "powerpc64", + target_arch = "mips64")))] const MIN_ALIGN: usize = 16; // MALLOCX_ALIGN(a) macro diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 9eade937bfb4c..2c0c6d068caae 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -32,7 +32,8 @@ target_arch = "asmjs")))] const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", - target_arch = "aarch64")))] + target_arch = "aarch64", + target_arch = "mips64")))] const MIN_ALIGN: usize = 16; #[no_mangle] diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index bd0c2f5126d13..c2e8eccbd22a4 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -124,7 +124,7 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 -#[cfg(any(target_arch = "mips", target_arch = "mipsel"))] +#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 753411991abea..0380965ed2058 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -661,6 +661,7 @@ pub mod consts { /// - arm /// - aarch64 /// - mips + /// - mips64 /// - powerpc /// - powerpc64 #[stable(feature = "env", since = "1.0.0")] @@ -928,6 +929,11 @@ mod arch { pub const ARCH: &'static str = "mips"; } +#[cfg(target_arch = "mips64")] +mod arch { + pub const ARCH: &'static str = "mips64"; +} + #[cfg(target_arch = "powerpc")] mod arch { pub const ARCH: &'static str = "powerpc"; diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index 1be76961fea9e..0f62877500b2c 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -155,6 +155,11 @@ mod arch { } } +#[cfg(target_arch = "mips64")] +mod arch { + pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; +} + #[cfg(target_arch = "aarch64")] mod arch { use os::raw::{c_long, c_int}; diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index 680ad3ecd64a6..8292a68417810 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -56,6 +56,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "mips")] pub const unwinder_private_data_size: usize = 2; +#[cfg(target_arch = "mips64")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] pub const unwinder_private_data_size: usize = 2; From 668d63132e23999f5a74fe65c8c0590a4d9ca215 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 27 Aug 2016 11:33:02 +0530 Subject: [PATCH 307/768] Fixup rustbuild on #35124 --- src/bootstrap/lib.rs | 4 ---- src/bootstrap/step.rs | 7 ++----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b40dbfde4a4a5..9eacb5e3924fa 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -308,10 +308,6 @@ impl Build { doc::rustbook(self, stage, target.target, "nomicon", &doc_out); } - DocStyle { stage } => { - doc::rustbook(self, stage, target.target, "style", - &doc_out); - } DocStandalone { stage } => { doc::standalone(self, stage, target.target, &doc_out); } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 8d3cb36166b70..12929664886c4 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -92,7 +92,6 @@ macro_rules! targets { (doc, Doc { stage: u32 }), (doc_book, DocBook { stage: u32 }), (doc_nomicon, DocNomicon { stage: u32 }), - (doc_style, DocStyle { stage: u32 }), (doc_standalone, DocStandalone { stage: u32 }), (doc_std, DocStd { stage: u32 }), (doc_test, DocTest { stage: u32 }), @@ -366,8 +365,7 @@ impl<'a> Step<'a> { vec![self.libtest(compiler)] } Source::DocBook { stage } | - Source::DocNomicon { stage } | - Source::DocStyle { stage } => { + Source::DocNomicon { stage } => { vec![self.target(&build.config.build).tool_rustbook(stage)] } Source::DocErrorIndex { stage } => { @@ -382,8 +380,7 @@ impl<'a> Step<'a> { Source::Doc { stage } => { let mut deps = vec![ self.doc_book(stage), self.doc_nomicon(stage), - self.doc_style(stage), self.doc_standalone(stage), - self.doc_std(stage), + self.doc_standalone(stage), self.doc_std(stage), self.doc_error_index(stage), ]; From 144e576c87627a01dc6ab387f57a21a03659021d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2016 00:57:54 +0200 Subject: [PATCH 308/768] Use `FnvHashMap` in more places * A step towards #34902 * More stable error messages in some places related to crate loading * Possible slight performance improvements since all `HashMap`s replaced had small keys where `FnvHashMap` should be faster (although I didn't measure) --- src/librustc/infer/freshen.rs | 7 +-- src/librustc/middle/dead.rs | 12 ++--- src/librustc/middle/reachable.rs | 5 +- src/librustc_metadata/loader.rs | 14 +++--- src/librustc_metadata/macro_import.rs | 10 ++-- src/librustc_resolve/assign_ids.rs | 4 +- src/librustc_resolve/lib.rs | 49 +++++++++---------- src/librustc_trans/base.rs | 5 +- src/librustc_typeck/check/intrinsic.rs | 6 +-- src/librustc_typeck/check/method/probe.rs | 10 ++-- src/librustc_typeck/check/mod.rs | 7 ++- src/librustc_typeck/check/wfcheck.rs | 6 +-- src/librustc_typeck/collect.rs | 15 +++--- .../constrained_type_params.rs | 6 +-- 14 files changed, 76 insertions(+), 80 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index beda734ee0d56..f793d489cab06 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -32,7 +32,8 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeFolder; -use std::collections::hash_map::{self, Entry}; +use util::nodemap::FnvHashMap; +use std::collections::hash_map::Entry; use super::InferCtxt; use super::unify_key::ToType; @@ -40,7 +41,7 @@ use super::unify_key::ToType; pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, freshen_count: u32, - freshen_map: hash_map::HashMap>, + freshen_map: FnvHashMap>, } impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { @@ -49,7 +50,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { TypeFreshener { infcx: infcx, freshen_count: 0, - freshen_map: hash_map::HashMap::new(), + freshen_map: FnvHashMap(), } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 37366f38974a4..f44b149a84617 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -22,8 +22,8 @@ use ty::{self, TyCtxt}; use hir::def::Def; use hir::def_id::{DefId}; use lint; +use util::nodemap::FnvHashSet; -use std::collections::HashSet; use syntax::{ast, codemap}; use syntax::attr; use syntax_pos; @@ -48,7 +48,7 @@ fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, struct MarkSymbolVisitor<'a, 'tcx: 'a> { worklist: Vec, tcx: TyCtxt<'a, 'tcx, 'tcx>, - live_symbols: Box>, + live_symbols: Box>, struct_has_extern_repr: bool, ignore_non_const_paths: bool, inherited_pub_visibility: bool, @@ -61,7 +61,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { MarkSymbolVisitor { worklist: worklist, tcx: tcx, - live_symbols: box HashSet::new(), + live_symbols: box FnvHashSet(), struct_has_extern_repr: false, ignore_non_const_paths: false, inherited_pub_visibility: false, @@ -162,7 +162,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn mark_live_symbols(&mut self) { - let mut scanned = HashSet::new(); + let mut scanned = FnvHashSet(); while !self.worklist.is_empty() { let id = self.worklist.pop().unwrap(); if scanned.contains(&id) { @@ -395,7 +395,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels, krate: &hir::Crate) - -> Box> { + -> Box> { let worklist = create_and_seed_worklist(tcx, access_levels, krate); let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist); symbol_visitor.mark_live_symbols(); @@ -413,7 +413,7 @@ fn get_struct_ctor_id(item: &hir::Item) -> Option { struct DeadVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - live_symbols: Box>, + live_symbols: Box>, } impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 6ea0fa20c5726..e29a7cf9d6846 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -22,9 +22,8 @@ use hir::def_id::DefId; use ty::{self, TyCtxt}; use middle::privacy; use session::config; -use util::nodemap::NodeSet; +use util::nodemap::{NodeSet, FnvHashSet}; -use std::collections::HashSet; use syntax::abi::Abi; use syntax::ast; use syntax::attr; @@ -204,7 +203,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Step 2: Mark all symbols that the symbols on the worklist touch. fn propagate(&mut self) { - let mut scanned = HashSet::new(); + let mut scanned = FnvHashSet(); loop { let search_item = match self.worklist.pop() { Some(item) => item, diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 2345cd9a92aea..b2c87db8ef566 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -221,6 +221,7 @@ use rustc::session::Session; use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; use rustc::session::search_paths::PathKind; use rustc::util::common; +use rustc::util::nodemap::FnvHashMap; use rustc_llvm as llvm; use rustc_llvm::{False, ObjectFile, mk_section_iter}; @@ -230,7 +231,6 @@ use syntax_pos::Span; use rustc_back::target::Target; use std::cmp; -use std::collections::HashMap; use std::fmt; use std::fs; use std::io; @@ -413,7 +413,7 @@ impl<'a> Context<'a> { let rlib_prefix = format!("lib{}", self.crate_name); let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name); - let mut candidates = HashMap::new(); + let mut candidates = FnvHashMap(); let mut staticlibs = vec!(); // First, find all possible candidate rlibs and dylibs purely based on @@ -456,7 +456,7 @@ impl<'a> Context<'a> { let hash_str = hash.to_string(); let slot = candidates.entry(hash_str) - .or_insert_with(|| (HashMap::new(), HashMap::new())); + .or_insert_with(|| (FnvHashMap(), FnvHashMap())); let (ref mut rlibs, ref mut dylibs) = *slot; fs::canonicalize(path).map(|p| { if rlib { @@ -477,7 +477,7 @@ impl<'a> Context<'a> { // A Library candidate is created if the metadata for the set of // libraries corresponds to the crate id and hash criteria that this // search is being performed for. - let mut libraries = HashMap::new(); + let mut libraries = FnvHashMap(); for (_hash, (rlibs, dylibs)) in candidates { let mut slot = None; let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot); @@ -527,7 +527,7 @@ impl<'a> Context<'a> { // read the metadata from it if `*slot` is `None`. If the metadata couldn't // be read, it is assumed that the file isn't a valid rust library (no // errors are emitted). - fn extract_one(&mut self, m: HashMap, flavor: CrateFlavor, + fn extract_one(&mut self, m: FnvHashMap, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob)>) -> Option<(PathBuf, PathKind)> { let mut ret: Option<(PathBuf, PathKind)> = None; let mut error = 0; @@ -669,8 +669,8 @@ impl<'a> Context<'a> { // rlibs/dylibs. let sess = self.sess; let dylibname = self.dylibname(); - let mut rlibs = HashMap::new(); - let mut dylibs = HashMap::new(); + let mut rlibs = FnvHashMap(); + let mut dylibs = FnvHashMap(); { let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| { if !loc.exists() { diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index b2a2dcf90fa4b..2cd60f04e69a1 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -14,8 +14,8 @@ use creader::CrateReader; use cstore::CStore; use rustc::session::Session; +use rustc::util::nodemap::{FnvHashSet, FnvHashMap}; -use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; use syntax::attr; @@ -45,13 +45,13 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { span_err!(a, b, E0467, "bad macro reexport"); } -pub type MacroSelection = HashMap; +pub type MacroSelection = FnvHashMap; impl<'a> ext::base::MacroLoader for MacroLoader<'a> { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { // Parse the attributes relating to macros. - let mut import = Some(HashMap::new()); // None => load all - let mut reexport = HashMap::new(); + let mut import = Some(FnvHashMap()); // None => load all + let mut reexport = FnvHashMap(); for attr in &extern_crate.attrs { let mut used = true; @@ -120,7 +120,7 @@ impl<'a> MacroLoader<'a> { } let mut macros = Vec::new(); - let mut seen = HashSet::new(); + let mut seen = FnvHashSet(); for mut def in self.reader.read_exported_macros(vi) { let name = def.ident.name.as_str(); diff --git a/src/librustc_resolve/assign_ids.rs b/src/librustc_resolve/assign_ids.rs index 70e566de8a7be..a9e3c6ffe9ed8 100644 --- a/src/librustc_resolve/assign_ids.rs +++ b/src/librustc_resolve/assign_ids.rs @@ -10,6 +10,7 @@ use Resolver; use rustc::session::Session; +use rustc::util::nodemap::FnvHashMap; use syntax::ast; use syntax::ext::hygiene::Mark; use syntax::fold::{self, Folder}; @@ -17,7 +18,6 @@ use syntax::ptr::P; use syntax::util::move_map::MoveMap; use syntax::util::small_vector::SmallVector; -use std::collections::HashMap; use std::mem; impl<'a> Resolver<'a> { @@ -31,7 +31,7 @@ impl<'a> Resolver<'a> { struct NodeIdAssigner<'a> { sess: &'a Session, - macros_at_scope: &'a mut HashMap>, + macros_at_scope: &'a mut FnvHashMap>, } impl<'a> Folder for NodeIdAssigner<'a> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5641a50ccaccf..6a4a48377c783 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -68,7 +68,6 @@ use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, T use syntax_pos::Span; use errors::DiagnosticBuilder; -use std::collections::{HashMap, HashSet}; use std::cell::{Cell, RefCell}; use std::fmt; use std::mem::replace; @@ -498,7 +497,7 @@ struct BindingInfo { } // Map from the name in a pattern to its binding mode. -type BindingMap = HashMap; +type BindingMap = FnvHashMap; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum PatternSource { @@ -703,14 +702,14 @@ enum ModulePrefixResult<'a> { /// One local scope. #[derive(Debug)] struct Rib<'a> { - bindings: HashMap, + bindings: FnvHashMap, kind: RibKind<'a>, } impl<'a> Rib<'a> { fn new(kind: RibKind<'a>) -> Rib<'a> { Rib { - bindings: HashMap::new(), + bindings: FnvHashMap(), kind: kind, } } @@ -773,7 +772,7 @@ pub struct ModuleS<'a> { // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). extern_crate_id: Option, - resolutions: RefCell>>>, + resolutions: RefCell>>>, no_implicit_prelude: Cell, @@ -797,7 +796,7 @@ impl<'a> ModuleS<'a> { parent_link: parent_link, def: def, extern_crate_id: None, - resolutions: RefCell::new(HashMap::new()), + resolutions: RefCell::new(FnvHashMap()), no_implicit_prelude: Cell::new(false), glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), @@ -930,12 +929,12 @@ impl<'a> NameBinding<'a> { /// Interns the names of the primitive types. struct PrimitiveTypeTable { - primitive_types: HashMap, + primitive_types: FnvHashMap, } impl PrimitiveTypeTable { fn new() -> PrimitiveTypeTable { - let mut table = PrimitiveTypeTable { primitive_types: HashMap::new() }; + let mut table = PrimitiveTypeTable { primitive_types: FnvHashMap() }; table.intern("bool", TyBool); table.intern("char", TyChar); @@ -969,7 +968,7 @@ pub struct Resolver<'a> { // Maps the node id of a statement to the expansions of the `macro_rules!`s // immediately above the statement (if appropriate). - macros_at_scope: HashMap>, + macros_at_scope: FnvHashMap>, graph_root: Module<'a>, @@ -1043,8 +1042,8 @@ pub struct Resolver<'a> { // all imports, but only glob imports are actually interesting). pub glob_map: GlobMap, - used_imports: HashSet<(NodeId, Namespace)>, - used_crates: HashSet, + used_imports: FnvHashSet<(NodeId, Namespace)>, + used_crates: FnvHashSet, pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, @@ -1164,7 +1163,7 @@ impl<'a> Resolver<'a> { session: session, definitions: Definitions::new(), - macros_at_scope: HashMap::new(), + macros_at_scope: FnvHashMap(), // The outermost module has def ID 0; this is not reflected in the // AST. @@ -1199,8 +1198,8 @@ impl<'a> Resolver<'a> { make_glob_map: make_glob_map == MakeGlobMap::Yes, glob_map: NodeMap(), - used_imports: HashSet::new(), - used_crates: HashSet::new(), + used_imports: FnvHashSet(), + used_crates: FnvHashSet(), maybe_unused_trait_imports: NodeSet(), privacy_errors: Vec::new(), @@ -1729,7 +1728,7 @@ impl<'a> Resolver<'a> { match type_parameters { HasTypeParameters(generics, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); - let mut seen_bindings = HashMap::new(); + let mut seen_bindings = FnvHashMap(); for type_parameter in &generics.ty_params { let name = type_parameter.ident.name; debug!("with_type_parameter_rib: {}", type_parameter.id); @@ -1793,7 +1792,7 @@ impl<'a> Resolver<'a> { self.label_ribs.push(Rib::new(rib_kind)); // Add each argument to the rib. - let mut bindings_list = HashMap::new(); + let mut bindings_list = FnvHashMap(); for argument in &declaration.inputs { self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); @@ -1994,7 +1993,7 @@ impl<'a> Resolver<'a> { walk_list!(self, visit_expr, &local.init); // Resolve the pattern. - self.resolve_pattern(&local.pat, PatternSource::Let, &mut HashMap::new()); + self.resolve_pattern(&local.pat, PatternSource::Let, &mut FnvHashMap()); } // build a map from pattern identifiers to binding-info's. @@ -2002,7 +2001,7 @@ impl<'a> Resolver<'a> { // that expands into an or-pattern where one 'x' was from the // user and one 'x' came from the macro. fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { - let mut binding_map = HashMap::new(); + let mut binding_map = FnvHashMap(); pat.walk(&mut |pat| { if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { @@ -2062,7 +2061,7 @@ impl<'a> Resolver<'a> { fn resolve_arm(&mut self, arm: &Arm) { self.value_ribs.push(Rib::new(NormalRibKind)); - let mut bindings_list = HashMap::new(); + let mut bindings_list = FnvHashMap(); for pattern in &arm.pats { self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list); } @@ -2202,7 +2201,7 @@ impl<'a> Resolver<'a> { pat_id: NodeId, outer_pat_id: NodeId, pat_src: PatternSource, - bindings: &mut HashMap) + bindings: &mut FnvHashMap) -> PathResolution { // Add the binding to the local ribs, if it // doesn't already exist in the bindings map. (We @@ -2303,7 +2302,7 @@ impl<'a> Resolver<'a> { pat_src: PatternSource, // Maps idents to the node ID for the // outermost pattern that binds them. - bindings: &mut HashMap) { + bindings: &mut FnvHashMap) { // Visit all direct subpatterns of this pattern. let outer_pat_id = pat.id; pat.walk(&mut |pat| { @@ -3016,7 +3015,7 @@ impl<'a> Resolver<'a> { self.visit_expr(subexpression); self.value_ribs.push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::IfLet, &mut HashMap::new()); + self.resolve_pattern(pattern, PatternSource::IfLet, &mut FnvHashMap()); self.visit_block(if_block); self.value_ribs.pop(); @@ -3026,7 +3025,7 @@ impl<'a> Resolver<'a> { ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); self.value_ribs.push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::WhileLet, &mut HashMap::new()); + self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FnvHashMap()); self.resolve_labeled_block(label.map(|l| l.node), expr.id, block); @@ -3036,7 +3035,7 @@ impl<'a> Resolver<'a> { ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); self.value_ribs.push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::For, &mut HashMap::new()); + self.resolve_pattern(pattern, PatternSource::For, &mut FnvHashMap()); self.resolve_labeled_block(label.map(|l| l.node), expr.id, block); @@ -3297,7 +3296,7 @@ impl<'a> Resolver<'a> { fn report_privacy_errors(&self) { if self.privacy_errors.len() == 0 { return } - let mut reported_spans = HashSet::new(); + let mut reported_spans = FnvHashSet(); for &PrivacyError(span, name, binding) in &self.privacy_errors { if !reported_spans.insert(span) { continue } if binding.is_extern_crate() { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5e431193a2c4c..a183fc0858aa8 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -80,14 +80,13 @@ use type_of; use value::Value; use Disr; use util::sha2::Sha256; -use util::nodemap::{NodeSet, FnvHashSet}; +use util::nodemap::{NodeSet, FnvHashMap, FnvHashSet}; use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; use std::borrow::Cow; use std::cell::{Cell, RefCell}; -use std::collections::HashMap; use std::ptr; use std::rc::Rc; use std::str; @@ -1915,7 +1914,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a } if scx.sess().opts.debugging_opts.print_trans_items.is_some() { - let mut item_to_cgus = HashMap::new(); + let mut item_to_cgus = FnvHashMap(); for cgu in &codegen_units { for (&trans_item, &linkage) in cgu.items() { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index ad48827a1d039..d0b0242544981 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -16,9 +16,9 @@ use rustc::infer::TypeOrigin; use rustc::ty::subst::Substs; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; +use rustc::util::nodemap::FnvHashMap; use {CrateCtxt, require_same_types}; -use std::collections::{HashMap}; use syntax::abi::Abi; use syntax::ast; use syntax::parse::token; @@ -365,7 +365,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, return } - let mut structural_to_nomimal = HashMap::new(); + let mut structural_to_nomimal = FnvHashMap(); let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap(); if intr.inputs.len() != sig.inputs.len() { @@ -405,7 +405,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( ccx: &CrateCtxt<'a, 'tcx>, position: &str, span: Span, - structural_to_nominal: &mut HashMap<&'a intrinsics::Type, ty::Ty<'tcx>>, + structural_to_nominal: &mut FnvHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>, expected: &'a intrinsics::Type, t: ty::Ty<'tcx>) { use intrinsics::Type::*; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a64982cd1bf81..29366823fffdc 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -20,10 +20,10 @@ use rustc::ty::subst::{Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::infer::{InferOk, TypeOrigin}; +use rustc::util::nodemap::FnvHashSet; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir; -use std::collections::HashSet; use std::mem; use std::ops::Deref; use std::rc::Rc; @@ -40,7 +40,7 @@ struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { opt_simplified_steps: Option>, inherent_candidates: Vec>, extension_candidates: Vec>, - impl_dups: HashSet, + impl_dups: FnvHashSet, import_id: Option, /// Collects near misses when the candidate functions are missing a `self` keyword and is only @@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { item_name: item_name, inherent_candidates: Vec::new(), extension_candidates: Vec::new(), - impl_dups: HashSet::new(), + impl_dups: FnvHashSet(), import_id: None, steps: Rc::new(steps), opt_simplified_steps: opt_simplified_steps, @@ -574,7 +574,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { expr_id: ast::NodeId) -> Result<(), MethodError<'tcx>> { - let mut duplicates = HashSet::new(); + let mut duplicates = FnvHashSet(); let opt_applicable_traits = self.tcx.trait_map.get(&expr_id); if let Some(applicable_traits) = opt_applicable_traits { for trait_candidate in applicable_traits { @@ -591,7 +591,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> { - let mut duplicates = HashSet::new(); + let mut duplicates = FnvHashSet(); for trait_info in suggest::all_traits(self.ccx) { if duplicates.insert(trait_info.def_id) { self.assemble_extension_candidates_for_trait(trait_info.def_id)?; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e972a5ca7fb38..fb24971c4251d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -104,10 +104,9 @@ use CrateCtxt; use TypeAndSubsts; use lint; use util::common::{block_query, ErrorReported, indenter, loop_query}; -use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; +use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet, NodeMap}; use std::cell::{Cell, Ref, RefCell}; -use std::collections::{HashSet}; use std::mem::replace; use std::ops::Deref; use syntax::abi::Abi; @@ -2045,7 +2044,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .filter_map(|t| self.default(t).map(|d| (t, d))) .collect(); - let mut unbound_tyvars = HashSet::new(); + let mut unbound_tyvars = FnvHashSet(); debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); @@ -2192,7 +2191,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // table then apply defaults until we find a conflict. That default must be the one // that caused conflict earlier. fn find_conflicting_default(&self, - unbound_vars: &HashSet>, + unbound_vars: &FnvHashSet>, default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, conflict: Ty<'tcx>) -> Option> { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 38ec7ba686f6f..6b6a688bf1d18 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -16,8 +16,8 @@ use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::util::nodemap::FnvHashSet; -use std::collections::HashSet; use syntax::ast; use syntax_pos::Span; use errors::DiagnosticBuilder; @@ -456,7 +456,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { assert_eq!(ty_predicates.parent, None); let variances = self.tcx().item_variances(item_def_id); - let mut constrained_parameters: HashSet<_> = + let mut constrained_parameters: FnvHashSet<_> = variances[ast_generics.lifetimes.len()..] .iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) @@ -519,7 +519,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) { let parent = tcx.lookup_generics(generics.parent.unwrap()); - let impl_params: HashSet<_> = parent.types.iter().map(|tp| tp.name).collect(); + let impl_params: FnvHashSet<_> = parent.types.iter().map(|tp| tp.name).collect(); for method_param in &generics.types { if impl_params.contains(&method_param.name) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0074d3930e29f..30b9d15587069 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -73,13 +73,12 @@ use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; -use util::nodemap::{NodeMap, FnvHashMap}; +use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; use {CrateCtxt, write_ty_to_tcx}; use rustc_const_math::ConstInt; use std::cell::RefCell; -use std::collections::HashSet; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::rc::Rc; @@ -1927,9 +1926,9 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, { let inline_bounds = from_bounds(ccx, param_bounds); let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); - let all_bounds: HashSet<_> = inline_bounds.into_iter() - .chain(where_bounds) - .collect(); + let all_bounds: FnvHashSet<_> = inline_bounds.into_iter() + .chain(where_bounds) + .collect(); return if all_bounds.len() > 1 { ty::ObjectLifetimeDefault::Ambiguous } else if all_bounds.len() == 0 { @@ -2146,7 +2145,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // The trait reference is an input, so find all type parameters // reachable from there, to start (if this is an inherent impl, // then just examine the self type). - let mut input_parameters: HashSet<_> = + let mut input_parameters: FnvHashSet<_> = ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { input_parameters.extend(ctp::parameters_for(trait_ref, false)); @@ -2175,7 +2174,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - let mut input_parameters: HashSet<_> = + let mut input_parameters: FnvHashSet<_> = ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { input_parameters.extend(ctp::parameters_for(trait_ref, false)); @@ -2183,7 +2182,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctp::identify_constrained_type_params( &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); - let lifetimes_in_associated_types: HashSet<_> = impl_items.iter() + let lifetimes_in_associated_types: FnvHashSet<_> = impl_items.iter() .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id))) .filter_map(|item| match item { ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 637df52e3cb03..9e5c3a5d575bf 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -10,7 +10,7 @@ use rustc::ty::{self, Ty}; use rustc::ty::fold::{TypeFoldable, TypeVisitor}; -use std::collections::HashSet; +use rustc::util::nodemap::FnvHashSet; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Parameter { @@ -71,7 +71,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>], impl_trait_ref: Option>, - input_parameters: &mut HashSet) + input_parameters: &mut FnvHashSet) { let mut predicates = predicates.to_owned(); setup_constraining_predicates(&mut predicates, impl_trait_ref, input_parameters); @@ -120,7 +120,7 @@ pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>] /// think of any. pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>], impl_trait_ref: Option>, - input_parameters: &mut HashSet) + input_parameters: &mut FnvHashSet) { // The canonical way of doing the needed topological sort // would be a DFS, but getting the graph and its ownership From 5adf003b990c7fc76cca3a909c6f81cfe4a1102f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Aug 2016 10:55:03 +0200 Subject: [PATCH 309/768] Use deterministic `FnvHash{Map,Set}` in rustdoc --- src/librustdoc/clean/inline.rs | 6 ++-- src/librustdoc/clean/mod.rs | 18 +++++------ src/librustdoc/core.rs | 12 +++---- src/librustdoc/html/render.rs | 57 +++++++++++++++++----------------- src/librustdoc/test.rs | 6 ++-- src/librustdoc/visit_ast.rs | 6 ++-- 6 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 013433336a1d5..20d4c41765540 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -10,7 +10,6 @@ //! Support for inlining external documentation into the current AST. -use std::collections::HashSet; use std::iter::once; use syntax::ast; @@ -21,6 +20,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; use rustc::ty::{self, TyCtxt}; +use rustc::util::nodemap::FnvHashSet; use rustc_const_eval::lookup_const_by_id; @@ -425,7 +425,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, .into_iter() .map(|meth| meth.name.to_string()) .collect() - }).unwrap_or(HashSet::new()); + }).unwrap_or(FnvHashSet()); ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { @@ -461,7 +461,7 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we're reexporting a reexport it may actually reexport something in // two namespaces, so the target may be listed twice. Make sure we only // visit each node at most once. - let mut visited = HashSet::new(); + let mut visited = FnvHashSet(); for item in tcx.sess.cstore.item_children(did) { match item.def { cstore::DlDef(Def::ForeignMod(did)) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c8620254b6f42..cd425b7c9ebbd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -43,10 +43,10 @@ use rustc::hir::print as pprust; use rustc::ty::subst::Substs; use rustc::ty; use rustc::middle::stability; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc::hir; -use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; @@ -121,7 +121,7 @@ pub struct Crate { pub access_levels: Arc>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. - pub external_traits: HashMap, + pub external_traits: FnvHashMap, } struct CrateNum(ast::CrateNum); @@ -1010,7 +1010,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, // Note that associated types also have a sized bound by default, but we // don't actually know the set of associated types right here so that's // handled in cleaning associated types - let mut sized_params = HashSet::new(); + let mut sized_params = FnvHashSet(); where_predicates.retain(|pred| { match *pred { WP::BoundPredicate { ty: Generic(ref g), ref bounds } => { @@ -1656,9 +1656,9 @@ impl From for PrimitiveType { struct SubstAlias<'a, 'tcx: 'a> { tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>, // Table type parameter definition -> substituted type - ty_substs: HashMap, + ty_substs: FnvHashMap, // Table node id of lifetime parameter definition -> substituted lifetime - lt_substs: HashMap, + lt_substs: FnvHashMap, } impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> { @@ -1727,8 +1727,8 @@ impl Clean for hir::Ty { let item = tcx.map.expect_item(node_id); if let hir::ItemTy(ref ty, ref generics) = item.node { let provided_params = &path.segments.last().unwrap().parameters; - let mut ty_substs = HashMap::new(); - let mut lt_substs = HashMap::new(); + let mut ty_substs = FnvHashMap(); + let mut lt_substs = FnvHashMap(); for (i, ty_param) in generics.ty_params.iter().enumerate() { let ty_param_def = tcx.expect_def(ty_param.id); if let Some(ty) = provided_params.types().get(i).cloned() @@ -2384,7 +2384,7 @@ impl Clean for hir::ImplPolarity { pub struct Impl { pub unsafety: hir::Unsafety, pub generics: Generics, - pub provided_trait_methods: HashSet, + pub provided_trait_methods: FnvHashSet, pub trait_: Option, pub for_: Type, pub items: Vec, @@ -2410,7 +2410,7 @@ impl Clean> for doctree::Impl { .map(|meth| meth.name.to_string()) .collect() }) - }).unwrap_or(HashSet::new()); + }).unwrap_or(FnvHashSet()); ret.push(Item { name: None, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 8032b5c31046e..26f792a1fdf99 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -18,6 +18,7 @@ use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::hir::map as hir_map; use rustc::lint; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; @@ -28,7 +29,6 @@ use errors; use errors::emitter::ColorConfig; use std::cell::{RefCell, Cell}; -use std::collections::{HashMap, HashSet}; use std::rc::Rc; use visit_ast::RustdocVisitor; @@ -45,13 +45,13 @@ pub enum MaybeTyped<'a, 'tcx: 'a> { NotTyped(&'a session::Session) } -pub type ExternalPaths = HashMap, clean::TypeKind)>; +pub type ExternalPaths = FnvHashMap, clean::TypeKind)>; pub struct DocContext<'a, 'tcx: 'a> { pub map: &'a hir_map::Map<'tcx>, pub maybe_typed: MaybeTyped<'a, 'tcx>, pub input: Input, - pub populated_crate_impls: RefCell>, + pub populated_crate_impls: RefCell>, pub deref_trait_did: Cell>, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -61,7 +61,7 @@ pub struct DocContext<'a, 'tcx: 'a> { /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` - pub external_traits: RefCell>, + pub external_traits: RefCell>, } impl<'b, 'tcx> DocContext<'b, 'tcx> { @@ -178,10 +178,10 @@ pub fn run_core(search_paths: SearchPaths, map: &tcx.map, maybe_typed: Typed(tcx), input: input, - populated_crate_impls: RefCell::new(HashSet::new()), + populated_crate_impls: RefCell::new(FnvHashSet()), deref_trait_did: Cell::new(None), access_levels: RefCell::new(access_levels), - external_traits: RefCell::new(HashMap::new()), + external_traits: RefCell::new(FnvHashMap()), renderinfo: RefCell::new(Default::default()), }; debug!("crate: {:?}", ctxt.map.krate()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6993f85c3d9a4..5cb5cc051870b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -37,7 +37,7 @@ pub use self::ExternalLocation::*; use std::ascii::AsciiExt; use std::cell::RefCell; use std::cmp::Ordering; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::BTreeMap; use std::default::Default; use std::error; use std::fmt::{self, Display, Formatter}; @@ -61,6 +61,7 @@ use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::session::config::get_unstable_features_setting; use rustc::hir; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use clean::{self, Attributes, GetDefId}; use doctree; @@ -114,9 +115,9 @@ pub struct SharedContext { /// `true`. pub include_sources: bool, /// The local file sources we've emitted and their respective url-paths. - pub local_sources: HashMap, + pub local_sources: FnvHashMap, /// All the passes that were run on this crate. - pub passes: HashSet, + pub passes: FnvHashSet, /// The base-URL of the issue tracker for when an item has been tagged with /// an issue number. pub issue_tracker_base_url: Option, @@ -211,7 +212,7 @@ pub struct Cache { /// Mapping of typaram ids to the name of the type parameter. This is used /// when pretty-printing a type (so pretty printing doesn't have to /// painfully maintain a context like this) - pub typarams: HashMap, + pub typarams: FnvHashMap, /// Maps a type id to all known implementations for that type. This is only /// recognized for intra-crate `ResolvedPath` types, and is used to print @@ -219,35 +220,35 @@ pub struct Cache { /// /// The values of the map are a list of implementations and documentation /// found on that implementation. - pub impls: HashMap>, + pub impls: FnvHashMap>, /// Maintains a mapping of local crate node ids to the fully qualified name /// and "short type description" of that node. This is used when generating /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - pub paths: HashMap, ItemType)>, + pub paths: FnvHashMap, ItemType)>, /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. - pub external_paths: HashMap, ItemType)>, + pub external_paths: FnvHashMap, ItemType)>, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods /// should show up in documentation about trait implementations. - pub traits: HashMap, + pub traits: FnvHashMap, /// When rendering traits, it's often useful to be able to list all /// implementors of the trait, and this mapping is exactly, that: a mapping /// of trait ids to the list of known implementors of the trait - pub implementors: HashMap>, + pub implementors: FnvHashMap>, /// Cache of where external crate documentation can be found. - pub extern_locations: HashMap, + pub extern_locations: FnvHashMap, /// Cache of where documentation for primitives can be found. - pub primitive_locations: HashMap, + pub primitive_locations: FnvHashMap, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -260,7 +261,7 @@ pub struct Cache { parent_stack: Vec, parent_is_trait_impl: bool, search_index: Vec, - seen_modules: HashSet, + seen_modules: FnvHashSet, seen_mod: bool, stripped_mod: bool, deref_trait_did: Option, @@ -277,9 +278,9 @@ pub struct Cache { /// Later on moved into `CACHE_KEY`. #[derive(Default)] pub struct RenderInfo { - pub inlined: HashSet, + pub inlined: FnvHashSet, pub external_paths: ::core::ExternalPaths, - pub external_typarams: HashMap, + pub external_typarams: FnvHashMap, pub deref_trait_did: Option, } @@ -377,10 +378,10 @@ impl ToJson for IndexItemFunctionType { thread_local!(static CACHE_KEY: RefCell> = Default::default()); thread_local!(pub static CURRENT_LOCATION_KEY: RefCell> = RefCell::new(Vec::new())); -thread_local!(static USED_ID_MAP: RefCell> = +thread_local!(static USED_ID_MAP: RefCell> = RefCell::new(init_ids())); -fn init_ids() -> HashMap { +fn init_ids() -> FnvHashMap { [ "main", "search", @@ -407,7 +408,7 @@ pub fn reset_ids(embedded: bool) { *s.borrow_mut() = if embedded { init_ids() } else { - HashMap::new() + FnvHashMap() }; }); } @@ -432,7 +433,7 @@ pub fn derive_id(candidate: String) -> String { pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: PathBuf, - passes: HashSet, + passes: FnvHashSet, css_file_extension: Option, renderinfo: RenderInfo) -> Result<(), Error> { let src_root = match krate.src.parent() { @@ -443,7 +444,7 @@ pub fn run(mut krate: clean::Crate, src_root: src_root, passes: passes, include_sources: true, - local_sources: HashMap::new(), + local_sources: FnvHashMap(), issue_tracker_base_url: None, layout: layout::Layout { logo: "".to_string(), @@ -513,22 +514,22 @@ pub fn run(mut krate: clean::Crate, .collect(); let mut cache = Cache { - impls: HashMap::new(), + impls: FnvHashMap(), external_paths: external_paths, - paths: HashMap::new(), - implementors: HashMap::new(), + paths: FnvHashMap(), + implementors: FnvHashMap(), stack: Vec::new(), parent_stack: Vec::new(), search_index: Vec::new(), parent_is_trait_impl: false, - extern_locations: HashMap::new(), - primitive_locations: HashMap::new(), - seen_modules: HashSet::new(), + extern_locations: FnvHashMap(), + primitive_locations: FnvHashMap(), + seen_modules: FnvHashSet(), seen_mod: false, stripped_mod: false, access_levels: krate.access_levels.clone(), orphan_methods: Vec::new(), - traits: mem::replace(&mut krate.external_traits, HashMap::new()), + traits: mem::replace(&mut krate.external_traits, FnvHashMap()), deref_trait_did: deref_trait_did, typarams: external_typarams, }; @@ -574,7 +575,7 @@ pub fn run(mut krate: clean::Crate, /// Build the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { - let mut nodeid_to_pathid = HashMap::new(); + let mut nodeid_to_pathid = FnvHashMap(); let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = Vec::::new(); @@ -2515,7 +2516,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, #[derive(Copy, Clone)] enum AssocItemLink<'a> { Anchor(Option<&'a str>), - GotoSource(DefId, &'a HashSet), + GotoSource(DefId, &'a FnvHashSet), } impl<'a> AssocItemLink<'a> { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 7d1dbbe5dc07d..e7edf8d1cabe2 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::cell::{RefCell, Cell}; -use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::OsString; use std::io::prelude::*; @@ -29,6 +28,7 @@ use rustc::session::{self, config}; use rustc::session::config::{get_unstable_features_setting, OutputType, OutputTypes, Externs}; use rustc::session::search_paths::{SearchPaths, PathKind}; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc_back::dynamic_lib::DynamicLibrary; use rustc_back::tempdir::TempDir; use rustc_driver::{driver, Compilation}; @@ -107,8 +107,8 @@ pub fn run(input: &str, map: &map, maybe_typed: core::NotTyped(&sess), input: input, - external_traits: RefCell::new(HashMap::new()), - populated_crate_impls: RefCell::new(HashSet::new()), + external_traits: RefCell::new(FnvHashMap()), + populated_crate_impls: RefCell::new(FnvHashSet()), deref_trait_did: Cell::new(None), access_levels: Default::default(), renderinfo: Default::default(), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0334c5ef5c4f4..f6084180f0bd1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -11,7 +11,6 @@ //! Rust AST Visitor. Extracts useful information and massages it into a form //! usable for clean -use std::collections::HashSet; use std::mem; use syntax::abi; @@ -23,6 +22,7 @@ use syntax_pos::Span; use rustc::hir::map as hir_map; use rustc::hir::def::Def; use rustc::middle::privacy::AccessLevel; +use rustc::util::nodemap::FnvHashSet; use rustc::hir; @@ -42,14 +42,14 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { pub module: Module, pub attrs: hir::HirVec, pub cx: &'a core::DocContext<'a, 'tcx>, - view_item_stack: HashSet, + view_item_stack: FnvHashSet, inlining_from_glob: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new(cx: &'a core::DocContext<'a, 'tcx>) -> RustdocVisitor<'a, 'tcx> { // If the root is reexported, terminate all recursion. - let mut stack = HashSet::new(); + let mut stack = FnvHashSet(); stack.insert(ast::CRATE_NODE_ID); RustdocVisitor { module: Module::new(None), From 2eeca3ccd254b49aef83f12a1cb4179a686e8551 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2016 22:02:47 +0200 Subject: [PATCH 310/768] Make metadata encoding deterministic `ty::Predicate` was being used as a key for a hash map, but its hash implementation indirectly hashed addresses, which vary between each compiler run. This is fixed by sorting predicates by their ID before encoding them. In my tests, rustc is now able to produce deterministic results when compiling libcore and libstd. I've beefed up `run-make/reproducible-build` to compare the produced artifacts bit-by-bit. This doesn't catch everything, but should be a good start. cc #34902 --- src/librustc_metadata/encoder.rs | 7 +++++- src/test/run-make/reproducible-build/Makefile | 22 +++++++++++-------- .../reproducible-build-aux.rs | 8 ++++++- .../reproducible-build/reproducible-build.rs | 8 +++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 9a668b69b2eeb..f99bdf3b890cb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -862,8 +862,13 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, xrefs: FnvHashMap, u32>) { let mut xref_positions = vec![0; xrefs.len()]; + + // Encode XRefs sorted by their ID + let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); + sorted_xrefs.sort_by_key(|&(_, id)| id); + rbml_w.start_tag(tag_xref_data); - for (xref, id) in xrefs.into_iter() { + for (xref, id) in sorted_xrefs.into_iter() { xref_positions[id as usize] = rbml_w.mark_stable_position() as u32; match xref { XRef::Predicate(p) => { diff --git a/src/test/run-make/reproducible-build/Makefile b/src/test/run-make/reproducible-build/Makefile index 8e799ca1a4303..8b22dd021a9e7 100644 --- a/src/test/run-make/reproducible-build/Makefile +++ b/src/test/run-make/reproducible-build/Makefile @@ -1,20 +1,24 @@ -include ../tools.mk all: $(RUSTC) reproducible-build-aux.rs + mv libreproducible_build_aux.rlib first.rlib + $(RUSTC) reproducible-build-aux.rs + cp libreproducible_build_aux.rlib second.rlib + cmp "first.rlib" "second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build1" $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build2" - nm "$(TMPDIR)/reproducible-build1" | sort > "$(TMPDIR)/reproducible-build1.nm" - nm "$(TMPDIR)/reproducible-build2" | sort > "$(TMPDIR)/reproducible-build2.nm" - cmp "$(TMPDIR)/reproducible-build1.nm" "$(TMPDIR)/reproducible-build2.nm" || exit 1 + cmp "$(TMPDIR)/reproducible-build1" "$(TMPDIR)/reproducible-build2" || exit 1 + $(RUSTC) reproducible-build-aux.rs -g + mv libreproducible_build_aux.rlib first.rlib $(RUSTC) reproducible-build-aux.rs -g + cp libreproducible_build_aux.rlib second.rlib $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug" $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug" - nm "$(TMPDIR)/reproducible-build1-debug" | sort > "$(TMPDIR)/reproducible-build1-debug.nm" - nm "$(TMPDIR)/reproducible-build2-debug" | sort > "$(TMPDIR)/reproducible-build2-debug.nm" - cmp "$(TMPDIR)/reproducible-build1-debug.nm" "$(TMPDIR)/reproducible-build2-debug.nm" || exit 1 + cmp "$(TMPDIR)/reproducible-build1-debug" "$(TMPDIR)/reproducible-build2-debug" || exit 1 + $(RUSTC) reproducible-build-aux.rs -O + mv libreproducible_build_aux.rlib first.rlib $(RUSTC) reproducible-build-aux.rs -O + cp libreproducible_build_aux.rlib second.rlib $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt" $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt" - nm "$(TMPDIR)/reproducible-build1-opt" | sort > "$(TMPDIR)/reproducible-build1-opt.nm" - nm "$(TMPDIR)/reproducible-build2-opt" | sort > "$(TMPDIR)/reproducible-build2-opt.nm" - cmp "$(TMPDIR)/reproducible-build1-opt.nm" "$(TMPDIR)/reproducible-build2-opt.nm" || exit 1 + cmp "$(TMPDIR)/reproducible-build1-opt" "$(TMPDIR)/reproducible-build2-opt" || exit 1 diff --git a/src/test/run-make/reproducible-build/reproducible-build-aux.rs b/src/test/run-make/reproducible-build/reproducible-build-aux.rs index 9ef853e79960b..73a62eee265cd 100644 --- a/src/test/run-make/reproducible-build/reproducible-build-aux.rs +++ b/src/test/run-make/reproducible-build/reproducible-build-aux.rs @@ -33,6 +33,12 @@ pub enum Enum { pub struct TupleStruct(pub i8, pub i16, pub i32, pub i64); -pub trait Trait { +pub trait Marker {} +impl Marker for char {} +impl Marker for (T, U) {} + +pub trait Trait where T1: 'static { + type Assoc: Marker; + fn foo(&self); } diff --git a/src/test/run-make/reproducible-build/reproducible-build.rs b/src/test/run-make/reproducible-build/reproducible-build.rs index dc7c702e5cc67..a732cc11d6061 100644 --- a/src/test/run-make/reproducible-build/reproducible-build.rs +++ b/src/test/run-make/reproducible-build/reproducible-build.rs @@ -67,7 +67,9 @@ impl Trait for u64 { fn foo(&self) {} } -impl reproducible_build_aux::Trait for TupleStruct { +impl reproducible_build_aux::Trait for TupleStruct { + type Assoc = (u8, i16); + fn foo(&self) {} } @@ -117,12 +119,10 @@ fn main() { let _ = reproducible_build_aux::Enum::Variant3 { x: 0 }; let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4); - let object_shim: &reproducible_build_aux::Trait = &TupleStruct(0, 1, 2, 3); + let object_shim: &reproducible_build_aux::Trait = &TupleStruct(0, 1, 2, 3); object_shim.foo(); let pointer_shim: &Fn(i32) = ®ular_fn; TupleStruct(1, 2, 3, 4).bar(); } - - From dca01f9443c0337e96fd2d7d72c64ba35a578230 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 25 Aug 2016 17:53:41 +0200 Subject: [PATCH 311/768] fix tidy --- src/test/run-make/reproducible-build/reproducible-build.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/reproducible-build/reproducible-build.rs b/src/test/run-make/reproducible-build/reproducible-build.rs index a732cc11d6061..17c2e87b5c1a6 100644 --- a/src/test/run-make/reproducible-build/reproducible-build.rs +++ b/src/test/run-make/reproducible-build/reproducible-build.rs @@ -67,7 +67,8 @@ impl Trait for u64 { fn foo(&self) {} } -impl reproducible_build_aux::Trait for TupleStruct { +impl +reproducible_build_aux::Trait for TupleStruct { type Assoc = (u8, i16); fn foo(&self) {} @@ -119,7 +120,8 @@ fn main() { let _ = reproducible_build_aux::Enum::Variant3 { x: 0 }; let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4); - let object_shim: &reproducible_build_aux::Trait = &TupleStruct(0, 1, 2, 3); + let object_shim: &reproducible_build_aux::Trait = + &TupleStruct(0, 1, 2, 3); object_shim.foo(); let pointer_shim: &Fn(i32) = ®ular_fn; From e468ede6247590c3cdef196bcf62c17b55d3fddb Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 25 Aug 2016 21:37:36 +0200 Subject: [PATCH 312/768] Fix the reproducible-build test --- src/test/run-make/reproducible-build/Makefile | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/test/run-make/reproducible-build/Makefile b/src/test/run-make/reproducible-build/Makefile index 8b22dd021a9e7..8db9e0ec078f6 100644 --- a/src/test/run-make/reproducible-build/Makefile +++ b/src/test/run-make/reproducible-build/Makefile @@ -1,24 +1,26 @@ -include ../tools.mk all: $(RUSTC) reproducible-build-aux.rs - mv libreproducible_build_aux.rlib first.rlib + mv "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/first.rlib" $(RUSTC) reproducible-build-aux.rs - cp libreproducible_build_aux.rlib second.rlib - cmp "first.rlib" "second.rlib" || exit 1 + cp "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/second.rlib" + cmp "$(TMPDIR)/first.rlib" "$(TMPDIR)/second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build1" $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build2" cmp "$(TMPDIR)/reproducible-build1" "$(TMPDIR)/reproducible-build2" || exit 1 $(RUSTC) reproducible-build-aux.rs -g - mv libreproducible_build_aux.rlib first.rlib + mv "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/first.rlib" $(RUSTC) reproducible-build-aux.rs -g - cp libreproducible_build_aux.rlib second.rlib + cp "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/second.rlib" + cmp "$(TMPDIR)/first.rlib" "$(TMPDIR)/second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug" $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug" cmp "$(TMPDIR)/reproducible-build1-debug" "$(TMPDIR)/reproducible-build2-debug" || exit 1 $(RUSTC) reproducible-build-aux.rs -O - mv libreproducible_build_aux.rlib first.rlib + mv "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/first.rlib" $(RUSTC) reproducible-build-aux.rs -O - cp libreproducible_build_aux.rlib second.rlib + cp "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/second.rlib" + cmp "$(TMPDIR)/first.rlib" "$(TMPDIR)/second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt" $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt" cmp "$(TMPDIR)/reproducible-build1-opt" "$(TMPDIR)/reproducible-build2-opt" || exit 1 From a7c671bb90ba1584d0098460ad8e417f848913f9 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 27 Aug 2016 17:00:36 +0100 Subject: [PATCH 313/768] rustdoc: Add missing item types to page titles Most pages include the item type in the title such as "Struct std::vec::Vec". However it is missing from the pages for foreign functions, type definitions, macros, statics and constants. This adds them so for example, instead of a title of "std::u32::MAX" it is "Constant std::u32::MAX" to match the others. --- src/librustdoc/html/render.rs | 18 +++++++++-- src/test/rustdoc/titles.rs | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/titles.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6993f85c3d9a4..3717e876d736d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1552,12 +1552,21 @@ impl<'a> fmt::Display for Item<'a> { } else { write!(fmt, "Module ")?; }, - clean::FunctionItem(..) => write!(fmt, "Function ")?, + clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => + write!(fmt, "Function ")?, clean::TraitItem(..) => write!(fmt, "Trait ")?, clean::StructItem(..) => write!(fmt, "Struct ")?, clean::EnumItem(..) => write!(fmt, "Enum ")?, + clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, + clean::MacroItem(..) => write!(fmt, "Macro ")?, clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, - _ => {} + clean::StaticItem(..) | clean::ForeignStaticItem(..) => + write!(fmt, "Static ")?, + clean::ConstantItem(..) => write!(fmt, "Constant ")?, + _ => { + // We don't generate pages for any other type. + unreachable!(); + } } if !self.item.is_primitive() { let cur = &self.cx.current; @@ -1618,7 +1627,10 @@ impl<'a> fmt::Display for Item<'a> { clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(fmt, self.cx, self.item, i), clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c), - _ => Ok(()) + _ => { + // We don't generate pages for any other type. + unreachable!(); + } } } } diff --git a/src/test/rustdoc/titles.rs b/src/test/rustdoc/titles.rs new file mode 100644 index 0000000000000..a56fa420944f7 --- /dev/null +++ b/src/test/rustdoc/titles.rs @@ -0,0 +1,59 @@ +// 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. + +#![crate_name = "foo"] + +// @matches 'foo/index.html' '//h1' 'Crate foo' + +// @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod' +pub mod foo_mod { + pub struct __Thing {} +} + +extern { + // @matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn' + pub fn foo_ffn(); +} + +// @matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn' +pub fn foo_fn() {} + +// @matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait' +pub trait FooTrait {} + +// @matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct' +pub struct FooStruct; + +// @matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum' +pub enum FooEnum {} + +// @matches 'foo/type.FooType.html' '//h1' 'Type Definition foo::FooType' +pub type FooType = FooStruct; + +// @matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro' +#[macro_export] +macro_rules! foo_macro { + () => (); +} + +// @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool' +#[doc(primitive = "bool")] +mod bool {} + +// @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC' +pub static FOO_STATIC: FooStruct = FooStruct; + +extern { + // @matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC' + pub static FOO_FSTATIC: FooStruct; +} + +// @matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT' +pub const FOO_CONSTANT: FooStruct = FooStruct; From eea03f5caab3ca6aa6789cce3d8e699fb7ac1404 Mon Sep 17 00:00:00 2001 From: William Lee Date: Sat, 27 Aug 2016 12:23:19 -0400 Subject: [PATCH 314/768] Fixes #35280 to update E0194 to support new error message format. Part of #35233. --- src/librustc_typeck/check/wfcheck.rs | 6 ++++-- src/test/compile-fail/E0194.rs | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e2080906ca242..0073506a11225 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -658,7 +658,9 @@ fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::N } fn error_194(tcx: TyCtxt, span: Span, name: ast::Name) { - span_err!(tcx.sess, span, E0194, + struct_span_err!(tcx.sess, span, E0194, "type parameter `{}` shadows another type parameter of the same name", - name); + name) + .span_label(span, &format!("`{}` shadows another type parameter", name)) + .emit(); } diff --git a/src/test/compile-fail/E0194.rs b/src/test/compile-fail/E0194.rs index 96b3062cacb78..fa94c88328a86 100644 --- a/src/test/compile-fail/E0194.rs +++ b/src/test/compile-fail/E0194.rs @@ -10,7 +10,9 @@ trait Foo { fn do_something(&self) -> T; - fn do_something_else(&self, bar: T); //~ ERROR E0194 + fn do_something_else(&self, bar: T); + //~^ ERROR E0194 + //~| NOTE `T` shadows another type parameter } fn main() { From 9c07ed21282fa0710580d589c6ba468ae12455df Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Sat, 27 Aug 2016 19:39:22 +0300 Subject: [PATCH 315/768] update error E0450 to new format --- src/librustc_privacy/lib.rs | 33 ++++++++++++++++++++++++++------- src/test/compile-fail/E0450.rs | 8 ++++++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 028632ad7c006..6da901a5f86c0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -444,13 +444,32 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { }), ..}) => ty, _ => expr_ty }.ty_adt_def().unwrap(); - let any_priv = def.struct_variant().fields.iter().any(|f| { - !f.vis.is_accessible_from(self.curitem, &self.tcx.map) - }); - if any_priv { - span_err!(self.tcx.sess, expr.span, E0450, - "cannot invoke tuple struct constructor with private \ - fields"); + + let private_indexes : Vec<_> = def.struct_variant().fields.iter().enumerate() + .filter(|&(_,f)| { + !f.vis.is_accessible_from(self.curitem, &self.tcx.map) + }).map(|(n,&_)|n).collect(); + + if !private_indexes.is_empty() { + + let mut error = struct_span_err!(self.tcx.sess, expr.span, E0450, + "cannot invoke tuple struct constructor \ + with private fields"); + error.span_label(expr.span, + &format!("cannot construct with a private field")); + + if let Some(def_id) = self.tcx.map.as_local_node_id(def.did) { + if let Some(hir::map::NodeItem(node)) = self.tcx.map.find(def_id) { + if let hir::Item_::ItemStruct(ref tuple_data, _) = node.node { + + for i in private_indexes { + error.span_label(tuple_data.fields()[i].span, + &format!("private field declared here")); + } + } + } + } + error.emit(); } } } diff --git a/src/test/compile-fail/E0450.rs b/src/test/compile-fail/E0450.rs index 3d76cb9377316..200b58a329344 100644 --- a/src/test/compile-fail/E0450.rs +++ b/src/test/compile-fail/E0450.rs @@ -9,9 +9,13 @@ // except according to those terms. mod Bar { - pub struct Foo(isize); + pub struct Foo( bool, pub i32, f32, bool); + //~^ NOTE private field declared here + //~| NOTE private field declared here + //~| NOTE private field declared here } fn main() { - let f = Bar::Foo(0); //~ ERROR E0450 + let f = Bar::Foo(false,1,0.1, true); //~ ERROR E0450 + //~^ NOTE cannot construct with a private field } From a068fc70ab38adea73f84a8f8c6f826454ce563b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 6 Aug 2016 12:49:17 +0200 Subject: [PATCH 316/768] Doc: explain why Box/Rc/Arc methods do not take self This can be confusing for newcomers, especially due to the argument name "this". --- src/liballoc/arc.rs | 6 ++++++ src/liballoc/boxed.rs | 4 ++++ src/liballoc/rc.rs | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 9c9f1e7b9de07..b54b71cabd1e9 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -71,6 +71,12 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// does not use atomics, making it both thread-unsafe as well as significantly /// faster when updating the reference count. /// +/// Note: the inherent methods defined on `Arc` are all associated functions, +/// which means that you have to call them as e.g. `Arc::get_mut(&value)` +/// instead of `value.get_mut()`. This is so that there are no conflicts with +/// methods on the inner type `T`, which are what you want to call in the +/// majority of cases. +/// /// # Examples /// /// In this example, a large vector of data will be shared by several threads. First we diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c8a78f84f1857..70c429cc3600a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -271,6 +271,10 @@ impl Box { /// proper way to do so is to convert the raw pointer back into a /// `Box` with the `Box::from_raw` function. /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This + /// is so that there is no conflict with a method on the inner type. + /// /// # Examples /// /// ``` diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 8e43e9eec1608..c24c7ca47ad05 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -182,6 +182,12 @@ struct RcBox { /// A reference-counted pointer type over an immutable value. /// /// See the [module level documentation](./index.html) for more details. +/// +/// Note: the inherent methods defined on `Rc` are all associated functions, +/// which means that you have to call them as e.g. `Rc::get_mut(&value)` instead +/// of `value.get_mut()`. This is so that there are no conflicts with methods +/// on the inner type `T`, which are what you want to call in the majority of +/// cases. #[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { From 286ae72fb7954ee51a6f4a1aeacbed6be4e6f37e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 Aug 2016 21:01:27 +0200 Subject: [PATCH 317/768] Clean code a bit --- src/libstd/sys/unix/os.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index e61804efd50f6..82606d2c728ea 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -584,18 +584,15 @@ pub fn home_dir() -> Option { n if n < 0 => 512 as usize, n => n as usize, }; - let me = libc::getuid(); - loop { - let mut buf = Vec::with_capacity(amt); - let mut passwd: libc::passwd = mem::zeroed(); - - if getpwduid_r(me, &mut passwd, &mut buf).is_some() { - let ptr = passwd.pw_dir as *const _; - let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); - return Some(OsStringExt::from_vec(bytes)) - } else { - return None; - } + let mut buf = Vec::with_capacity(amt); + let mut passwd: libc::passwd = mem::zeroed(); + + if getpwduid_r(libc::getuid(), &mut passwd, &mut buf).is_some() { + let ptr = passwd.pw_dir as *const _; + let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); + Some(OsStringExt::from_vec(bytes)) + } else { + None } } } From 4853456be0efa376064148f480618985b076c196 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 26 Aug 2016 19:58:31 -0700 Subject: [PATCH 318/768] Fix lifetime rules for 'if' conditions --- src/librustc/middle/region.rs | 3 ++- src/test/run-pass/issue-12033.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-12033.rs diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index faf2f7dae08c5..ef905b51edfb2 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -803,7 +803,8 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &hir::Expr) { terminating(r.id); } - hir::ExprIf(_, ref then, Some(ref otherwise)) => { + hir::ExprIf(ref expr, ref then, Some(ref otherwise)) => { + terminating(expr.id); terminating(then.id); terminating(otherwise.id); } diff --git a/src/test/run-pass/issue-12033.rs b/src/test/run-pass/issue-12033.rs new file mode 100644 index 0000000000000..5e1d82ce52cc6 --- /dev/null +++ b/src/test/run-pass/issue-12033.rs @@ -0,0 +1,16 @@ +// 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. + +use std::cell::RefCell; + +fn main() { + let x = RefCell::new(0); + if *x.borrow() == 0 {} else {} +} From c70d633e94dd52d036ef5808ab7dc49a72506492 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 17:12:37 -0500 Subject: [PATCH 319/768] rustbuild: skip filecheck check if codegen tests are disabled to match the behavior of the old Makefile-based build system closes #35752 --- src/bootstrap/config.rs | 3 +++ src/bootstrap/sanity.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index aafbf68d1b7b6..682a6f74126a8 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -78,6 +78,7 @@ pub struct Config { pub channel: String, pub musl_root: Option, pub prefix: Option, + pub codegen_tests: bool, } /// Per-target configuration stored in the global configuration structure. @@ -169,6 +170,7 @@ impl Config { config.rust_codegen_units = 1; config.build = build.to_string(); config.channel = "dev".to_string(); + config.codegen_tests = true; let toml = file.map(|file| { let mut f = t!(File::open(&file)); @@ -322,6 +324,7 @@ impl Config { ("DEBUGINFO_TESTS", self.rust_debuginfo_tests), ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), + ("CODEGEN_TESTS", self.codegen_tests), } match key { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index d6ac3ef6c9c50..c0d303c0ea9ae 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -89,7 +89,7 @@ pub fn check(build: &mut Build) { // Externally configured LLVM requires FileCheck to exist let filecheck = build.llvm_filecheck(&build.config.build); - if !filecheck.starts_with(&build.out) && !filecheck.exists() { + if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { panic!("filecheck executable {:?} does not exist", filecheck); } From 7b9adfd5747b3e845086d251d008175ee8a3e4a1 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sat, 27 Aug 2016 18:37:27 -0400 Subject: [PATCH 320/768] Add tests for #20433, #26251, #28625, #33687 Closes #20433 Closes #26251 Closes #28625 Closes #33687 --- src/test/compile-fail/issue-20433.rs | 18 +++++++++++++++++ src/test/compile-fail/issue-28625.rs | 30 ++++++++++++++++++++++++++++ src/test/run-pass/issue-26251.rs | 22 ++++++++++++++++++++ src/test/run-pass/issue-33687.rs | 26 ++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 src/test/compile-fail/issue-20433.rs create mode 100644 src/test/compile-fail/issue-28625.rs create mode 100644 src/test/run-pass/issue-26251.rs create mode 100644 src/test/run-pass/issue-33687.rs diff --git a/src/test/compile-fail/issue-20433.rs b/src/test/compile-fail/issue-20433.rs new file mode 100644 index 0000000000000..d1a139e698e12 --- /dev/null +++ b/src/test/compile-fail/issue-20433.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() {} + +struct The; + +impl The { + fn iceman(c: Vec<[i32]>) {} + //~^ ERROR the trait bound `[i32]: std::marker::Sized` is not satisfied +} diff --git a/src/test/compile-fail/issue-28625.rs b/src/test/compile-fail/issue-28625.rs new file mode 100644 index 0000000000000..c332e4ea45973 --- /dev/null +++ b/src/test/compile-fail/issue-28625.rs @@ -0,0 +1,30 @@ +// 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. + +trait Bar { + type Bar; +} + +struct ArrayPeano { + data: T::Bar, +} + +fn foo(a: &ArrayPeano) -> &[T] where T: Bar { + unsafe { std::mem::transmute(a) } //~ ERROR transmute called with differently sized types +} + +impl Bar for () { + type Bar = (); +} + +fn main() { + let x: ArrayPeano<()> = ArrayPeano { data: () }; + foo(&x); +} diff --git a/src/test/run-pass/issue-26251.rs b/src/test/run-pass/issue-26251.rs new file mode 100644 index 0000000000000..1e77d54fbf934 --- /dev/null +++ b/src/test/run-pass/issue-26251.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. + +fn main() { + let x = 'a'; + + let y = match x { + 'a'...'b' if false => "one", + 'a' => "two", + 'a'...'b' => "three", + _ => panic!("what?"), + }; + + assert_eq!(y, "two"); +} diff --git a/src/test/run-pass/issue-33687.rs b/src/test/run-pass/issue-33687.rs new file mode 100644 index 0000000000000..59badca065a10 --- /dev/null +++ b/src/test/run-pass/issue-33687.rs @@ -0,0 +1,26 @@ +// 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. + +#![feature(unboxed_closures)] +#![feature(fn_traits)] + +struct Test; + +impl FnOnce<(u32, u32)> for Test { + type Output = u32; + + extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { + a + b + } +} + +fn main() { + assert_eq!(Test(1u32, 2u32), 3u32); +} From 121b2fe988f47996933af699d6223de8e9262df0 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Sun, 28 Aug 2016 01:30:30 +0200 Subject: [PATCH 321/768] Improve Demangling of Rust Symbols This turns `..` into `::`, handles some more escapes and gets rid of unwanted underscores at the beginning of path elements. ![Image of Diff](http://puu.sh/qQIN3.png) --- src/libstd/sys/common/backtrace.rs | 66 +++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index c1d1792363d70..a509b80eaca91 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -137,10 +137,21 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); inner = &rest[i..]; rest = &rest[..i]; + if rest.starts_with("_$") { + rest = &rest[1..]; + } while !rest.is_empty() { - if rest.starts_with("$") { + if rest.starts_with(".") { + if let Some('.') = rest[1..].chars().next() { + writer.write_all(b"::")?; + rest = &rest[2..]; + } else { + writer.write_all(b".")?; + rest = &rest[1..]; + } + } else if rest.starts_with("$") { macro_rules! demangle { - ($($pat:expr, => $demangled:expr),*) => ({ + ($($pat:expr => $demangled:expr),*) => ({ $(if rest.starts_with($pat) { try!(writer.write_all($demangled)); rest = &rest[$pat.len()..]; @@ -155,29 +166,32 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { // see src/librustc/back/link.rs for these mappings demangle! ( - "$SP$", => b"@", - "$BP$", => b"*", - "$RF$", => b"&", - "$LT$", => b"<", - "$GT$", => b">", - "$LP$", => b"(", - "$RP$", => b")", - "$C$", => b",", + "$SP$" => b"@", + "$BP$" => b"*", + "$RF$" => b"&", + "$LT$" => b"<", + "$GT$" => b">", + "$LP$" => b"(", + "$RP$" => b")", + "$C$" => b",", // in theory we can demangle any Unicode code point, but // for simplicity we just catch the common ones. - "$u7e$", => b"~", - "$u20$", => b" ", - "$u27$", => b"'", - "$u5b$", => b"[", - "$u5d$", => b"]", - "$u7b$", => b"{", - "$u7d$", => b"}" + "$u7e$" => b"~", + "$u20$" => b" ", + "$u27$" => b"'", + "$u5b$" => b"[", + "$u5d$" => b"]", + "$u7b$" => b"{", + "$u7d$" => b"}", + "$u3b$" => b";", + "$u2b$" => b"+", + "$u22$" => b"\"" ) } else { - let idx = match rest.find('$') { + let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { None => rest.len(), - Some(i) => i, + Some((i, _)) => i, }; writer.write_all(rest[..idx].as_bytes())?; rest = &rest[idx..]; @@ -212,6 +226,7 @@ mod tests { t!("_ZN8$RF$testE", "&test"); t!("_ZN8$BP$test4foobE", "*test::foob"); t!("_ZN9$u20$test4foobE", " test::foob"); + t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); } #[test] @@ -226,4 +241,17 @@ mod tests { t!("ZN13test$u20$test4foobE", "test test::foob"); t!("ZN12test$RF$test4foobE", "test&test::foob"); } + + #[test] + fn demangle_elements_beginning_with_underscore() { + t!("_ZN13_$LT$test$GT$E", ""); + t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); + t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); + } + + #[test] + fn demangle_trait_impls() { + t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", + ">::bar"); + } } From a375799f7a4793adc92b76df59dc0be0bb2a90b8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 21:33:38 -0500 Subject: [PATCH 322/768] rustbuild: smarter `git submodule`-ing With this commit, if one bootstraps rust against system llvm then the src/llvm submodule is not updated/checked-out. This saves considerable network bandwith when starting from a fresh clone of rust-lang/rust as the llvm submodule is never cloned. cc #30107 --- src/bootstrap/lib.rs | 83 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 9eacb5e3924fa..b1a609aac5c2b 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -32,7 +32,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::env; use std::fs::{self, File}; -use std::path::{PathBuf, Path}; +use std::path::{Component, PathBuf, Path}; use std::process::Command; use build_helper::{run_silent, output}; @@ -475,12 +475,32 @@ impl Build { /// This will detect if any submodules are out of date an run the necessary /// commands to sync them all with upstream. fn update_submodules(&self) { + struct Submodule<'a> { + path: &'a Path, + state: State, + } + + enum State { + // The submodule may have staged/unstaged changes + MaybeDirty, + // Or could be initialized but never updated + NotInitialized, + // The submodule, itself, has extra commits but those changes haven't been commited to + // the (outer) git repository + OutOfSync, + } + if !self.config.submodules { return } if fs::metadata(self.src.join(".git")).is_err() { return } + let git = || { + let mut cmd = Command::new("git"); + cmd.current_dir(&self.src); + return cmd + }; let git_submodule = || { let mut cmd = Command::new("git"); cmd.current_dir(&self.src).arg("submodule"); @@ -492,19 +512,60 @@ impl Build { // of detecting whether we need to run all the submodule commands // below. let out = output(git_submodule().arg("status")); - if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) { - return + let mut submodules = vec![]; + for line in out.lines() { + // NOTE `git submodule status` output looks like this: + // + // -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc + // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/rust-llvm-2016-07-18-1-gb37ef24) + // e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6) + // + // The first character can be '-', '+' or ' ' and denotes the `State` of the submodule + // Right next to this character is the SHA-1 of the submodule HEAD + // And after that comes the path to the submodule + let path = Path::new(line[1..].split(' ').skip(1).next().unwrap()); + let state = if line.starts_with('-') { + State::NotInitialized + } else if line.starts_with('*') { + State::OutOfSync + } else if line.starts_with(' ') { + State::MaybeDirty + } else { + panic!("unexpected git submodule state: {:?}", line.chars().next()); + }; + + submodules.push(Submodule { path: path, state: state }) } self.run(git_submodule().arg("sync")); - self.run(git_submodule().arg("init")); - self.run(git_submodule().arg("update")); - self.run(git_submodule().arg("update").arg("--recursive")); - self.run(git_submodule().arg("status").arg("--recursive")); - self.run(git_submodule().arg("foreach").arg("--recursive") - .arg("git").arg("clean").arg("-fdx")); - self.run(git_submodule().arg("foreach").arg("--recursive") - .arg("git").arg("checkout").arg(".")); + + for submodule in submodules { + // If using llvm-root then don't touch the llvm submodule. + if submodule.path.components().any(|c| c == Component::Normal("llvm".as_ref())) && + self.config.target_config.get(&self.config.build).and_then(|c| c.llvm_config.as_ref()).is_some() + { + continue + } + + match submodule.state { + State::MaybeDirty => { + // drop staged changes + self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"])); + // drops unstaged changes + self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"])); + }, + State::NotInitialized => { + self.run(git_submodule().arg("init").arg(submodule.path)); + self.run(git_submodule().arg("update").arg(submodule.path)); + }, + State::OutOfSync => { + // drops submodule commits that weren't reported to the (outer) git repository + self.run(git_submodule().arg("update").arg(submodule.path)); + self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"])); + self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"])); + }, + } + } } /// Clear out `dir` if `input` is newer. From b8ebc1347c0f69c833b4fa908bcc43eb47949efa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 22:14:29 -0500 Subject: [PATCH 323/768] don't run codegen tests when they have been disabled --- src/bootstrap/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 9eacb5e3924fa..9f0efa8289d48 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -390,8 +390,10 @@ impl Build { "mir-opt", "mir-opt"); } CheckCodegen { compiler } => { - check::compiletest(self, &compiler, target.target, - "codegen", "codegen"); + if self.config.codegen_tests { + check::compiletest(self, &compiler, target.target, + "codegen", "codegen"); + } } CheckCodegenUnits { compiler } => { check::compiletest(self, &compiler, target.target, From 5683bf9e2020506003d6528482e0673399f61c7d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 22:53:19 -0500 Subject: [PATCH 324/768] don't update the src/jemalloc submodule is jemalloc has been disabled i.e. via the --disable-jemalloc configure flag --- src/bootstrap/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b1a609aac5c2b..8d0a6a81572f8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -542,7 +542,14 @@ impl Build { for submodule in submodules { // If using llvm-root then don't touch the llvm submodule. if submodule.path.components().any(|c| c == Component::Normal("llvm".as_ref())) && - self.config.target_config.get(&self.config.build).and_then(|c| c.llvm_config.as_ref()).is_some() + self.config.target_config.get(&self.config.build) + .and_then(|c| c.llvm_config.as_ref()).is_some() + { + continue + } + + if submodule.path.components().any(|c| c == Component::Normal("jemalloc".as_ref())) && + !self.config.use_jemalloc { continue } From 1e9e798ccea7f70480c3bcc86e271ca2191b8675 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sun, 7 Aug 2016 14:33:35 -0700 Subject: [PATCH 325/768] Move E0379 check from typeck to ast validation --- src/librustc_passes/ast_validation.rs | 21 +++++++++++++++ src/librustc_passes/diagnostics.rs | 7 +++++ src/librustc_typeck/check/mod.rs | 26 ++----------------- src/librustc_typeck/diagnostics.rs | 7 ----- src/test/compile-fail/const-fn-mismatch.rs | 2 +- .../compile-fail/const-fn-not-in-trait.rs | 8 ++++-- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 46124d0f97359..f10f1fba4c25e 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -69,6 +69,17 @@ impl<'a> AstValidator<'a> { } } } + + fn check_trait_fn_not_const(&self, span: Span, constness: Constness) { + match constness { + Constness::Const => { + struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const") + .span_label(span, &format!("trait fns cannot be const")) + .emit(); + } + _ => {} + } + } } impl<'a> Visitor for AstValidator<'a> { @@ -146,6 +157,9 @@ impl<'a> Visitor for AstValidator<'a> { self.invalid_visibility(&item.vis, item.span, None); for impl_item in impl_items { self.invalid_visibility(&impl_item.vis, impl_item.span, None); + if let ImplItemKind::Method(ref sig, _) = impl_item.node { + self.check_trait_fn_not_const(impl_item.span, sig.constness); + } } } ItemKind::Impl(_, _, _, None, _, _) => { @@ -169,6 +183,13 @@ impl<'a> Visitor for AstValidator<'a> { } } } + ItemKind::Trait(_, _, _, ref trait_items) => { + for trait_item in trait_items { + if let TraitItemKind::Method(ref sig, _) = trait_item.node { + self.check_trait_fn_not_const(trait_item.span, sig.constness); + } + } + } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 7049040678e39..89b8aa81411b3 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -176,6 +176,13 @@ fn some_func() { ``` "##, +E0379: r##" +Trait methods cannot be declared `const` by design. For more information, see +[RFC 911]. + +[RFC 911]: https://github.com/rust-lang/rfcs/pull/911 +"##, + E0449: r##" A visibility qualifier was used when it was unnecessary. Erroneous code examples: diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e972a5ca7fb38..c8d2f9144dcc6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -836,13 +836,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_const(ccx, &expr, trait_item.id) } hir::MethodTraitItem(ref sig, Some(ref body)) => { - check_trait_fn_not_const(ccx, trait_item.span, sig.constness); - check_bare_fn(ccx, &sig.decl, body, trait_item.id); } - hir::MethodTraitItem(ref sig, None) => { - check_trait_fn_not_const(ccx, trait_item.span, sig.constness); - } + hir::MethodTraitItem(_, None) | hir::ConstTraitItem(_, None) | hir::TypeTraitItem(..) => { // Nothing to do. @@ -854,22 +850,6 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } } -fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, - constness: hir::Constness) -{ - match constness { - hir::Constness::NotConst => { - // good - } - hir::Constness::Const => { - struct_span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const") - .span_label(span, &format!("trait fns cannot be const")) - .emit() - } - } -} - fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: DefId, item: &hir::Item) { @@ -1027,9 +1007,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, err.emit() } } - hir::ImplItemKind::Method(ref sig, ref body) => { - check_trait_fn_not_const(ccx, impl_item.span, sig.constness); - + hir::ImplItemKind::Method(_, ref body) => { let impl_method = match ty_impl_item { ty::MethodTraitItem(ref mti) => mti, _ => span_bug!(impl_item.span, "non-method impl-item for method") diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8bb5efdcad2c3..3f1374db36936 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3422,13 +3422,6 @@ containing the unsized type is the last and only unsized type field in the struct. "##, -E0379: r##" -Trait methods cannot be declared `const` by design. For more information, see -[RFC 911]. - -[RFC 911]: https://github.com/rust-lang/rfcs/pull/911 -"##, - E0380: r##" Default impls are only allowed for traits with no methods or associated items. For more information see the [opt-in builtin traits RFC](https://github.com/rust diff --git a/src/test/compile-fail/const-fn-mismatch.rs b/src/test/compile-fail/const-fn-mismatch.rs index 92568b27f7c1d..7ea72e23779ec 100644 --- a/src/test/compile-fail/const-fn-mismatch.rs +++ b/src/test/compile-fail/const-fn-mismatch.rs @@ -21,7 +21,7 @@ trait Foo { impl Foo for u32 { const fn f() -> u32 { 22 } - //~^ ERROR E0379 + //~^ ERROR trait fns cannot be declared const //~| NOTE trait fns cannot be const } diff --git a/src/test/compile-fail/const-fn-not-in-trait.rs b/src/test/compile-fail/const-fn-not-in-trait.rs index 191f3e025270f..257d4d5ee9921 100644 --- a/src/test/compile-fail/const-fn-not-in-trait.rs +++ b/src/test/compile-fail/const-fn-not-in-trait.rs @@ -14,8 +14,12 @@ #![feature(const_fn)] trait Foo { - const fn f() -> u32; //~ ERROR trait fns cannot be declared const - const fn g() -> u32 { 0 } //~ ERROR trait fns cannot be declared const + const fn f() -> u32; + //~^ ERROR trait fns cannot be declared const + //~| NOTE trait fns cannot be const + const fn g() -> u32 { 0 } + //~^ ERROR trait fns cannot be declared const + //~| NOTE trait fns cannot be const } fn main() { } From aa5c4bb05d1d5d10a2fdbb80f098ba06e73214b9 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 10 Aug 2016 16:20:12 -0700 Subject: [PATCH 326/768] Change Constness to Spanned --- src/librustc/hir/lowering.rs | 4 +-- src/librustc/hir/map/blocks.rs | 6 ++--- src/librustc/infer/error_reporting.rs | 3 ++- src/librustc_passes/ast_validation.rs | 14 +++++----- src/librustc_passes/consts.rs | 3 ++- src/libsyntax/ast.rs | 4 +-- src/libsyntax/ext/build.rs | 4 +-- src/libsyntax/feature_gate.rs | 8 +++--- src/libsyntax/parse/mod.rs | 5 +++- src/libsyntax/parse/parser.rs | 33 ++++++++++++++++------- src/libsyntax/print/pprust.rs | 4 +-- src/libsyntax/test.rs | 4 +-- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 5 ++-- 14 files changed, 61 insertions(+), 38 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b45610c3fe820..be5eb7f83769e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -809,8 +809,8 @@ impl<'a> LoweringContext<'a> { } } - fn lower_constness(&mut self, c: Constness) -> hir::Constness { - match c { + fn lower_constness(&mut self, c: Spanned) -> hir::Constness { + match c.node { Constness::Const => hir::Constness::Const, Constness::NotConst => hir::Constness::NotConst, } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 50e8c6e7ab842..4487234885692 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -23,13 +23,13 @@ pub use self::Code::*; +use hir as ast; use hir::map::{self, Node}; -use syntax::abi; use hir::{Block, FnDecl}; +use hir::intravisit::FnKind; +use syntax::abi; use syntax::ast::{Attribute, Name, NodeId}; -use hir as ast; use syntax_pos::Span; -use hir::intravisit::FnKind; /// An FnLikeNode is a Node that is like a fn, in that it has a decl /// and a body (as well as a NodeId, a span, etc). diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9169d299e040b..eab7f37382e67 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1030,7 +1030,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { = node_inner.expect("expect item fn"); let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver); let (fn_decl, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, &generics, span); + self.give_expl_lifetime_param( + err, &fn_decl, unsafety, constness, name, &generics, span); } pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index f10f1fba4c25e..dde1a4a759563 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -20,6 +20,7 @@ use rustc::lint; use rustc::session::Session; use syntax::ast::*; use syntax::attr; +use syntax::codemap::Spanned; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; use syntax_pos::Span; @@ -70,11 +71,12 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, span: Span, constness: Constness) { - match constness { + fn check_trait_fn_not_const(&self, constness: Spanned) { + match constness.node { Constness::Const => { - struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const") - .span_label(span, &format!("trait fns cannot be const")) + struct_span_err!(self.session, constness.span, E0379, + "trait fns cannot be declared const") + .span_label(constness.span, &format!("trait fns cannot be const")) .emit(); } _ => {} @@ -158,7 +160,7 @@ impl<'a> Visitor for AstValidator<'a> { for impl_item in impl_items { self.invalid_visibility(&impl_item.vis, impl_item.span, None); if let ImplItemKind::Method(ref sig, _) = impl_item.node { - self.check_trait_fn_not_const(impl_item.span, sig.constness); + self.check_trait_fn_not_const(sig.constness); } } } @@ -186,7 +188,7 @@ impl<'a> Visitor for AstValidator<'a> { ItemKind::Trait(_, _, _, ref trait_items) => { for trait_item in trait_items { if let TraitItemKind::Method(ref sig, _) = trait_item.node { - self.check_trait_fn_not_const(trait_item.span, sig.constness); + self.check_trait_fn_not_const(sig.constness); } } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 4aae6d690c4df..2d1b6e1315f8b 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -147,7 +147,8 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } let mode = match fk { - FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => Mode::ConstFn, + FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) + => Mode::ConstFn, FnKind::Method(_, m, _, _) => { if m.constness == hir::Constness::Const { Mode::ConstFn diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..427a44d2e740c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1120,7 +1120,7 @@ pub struct MutTy { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MethodSig { pub unsafety: Unsafety, - pub constness: Constness, + pub constness: Spanned, pub abi: Abi, pub decl: P, pub generics: Generics, @@ -1846,7 +1846,7 @@ pub enum ItemKind { /// A function declaration (`fn` or `pub fn`). /// /// E.g. `fn foo(bar: usize) -> usize { .. }` - Fn(P, Unsafety, Constness, Abi, Generics, P), + Fn(P, Unsafety, Spanned, Abi, Generics, P), /// A module declaration (`mod` or `pub mod`). /// /// E.g. `mod foo;` or `mod foo { .. }` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..14c7e46246d0d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -12,7 +12,7 @@ use abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; use syntax_pos::{Span, DUMMY_SP, Pos}; -use codemap::{respan, Spanned}; +use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use parse::token::{self, keywords, InternedString}; use ptr::P; @@ -1016,7 +1016,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { Vec::new(), ast::ItemKind::Fn(self.fn_decl(inputs, output), ast::Unsafety::Normal, - ast::Constness::NotConst, + dummy_spanned(ast::Constness::NotConst), Abi::Rust, generics, body)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dc68e06463464..9114c31d29816 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -30,7 +30,7 @@ use ast::{NodeId, PatKind}; use ast; use attr; use attr::AttrMetaMethods; -use codemap::CodeMap; +use codemap::{CodeMap, Spanned}; use syntax_pos::Span; use errors::Handler; use visit::{self, FnKind, Visitor}; @@ -1046,7 +1046,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { _node_id: NodeId) { // check for const fn declarations match fn_kind { - FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => { + FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => { gate_feature_post!(&self, const_fn, span, "const fn is unstable"); } _ => { @@ -1078,7 +1078,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { if block.is_none() { self.check_abi(sig.abi, ti.span); } - if sig.constness == ast::Constness::Const { + if sig.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } @@ -1105,7 +1105,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { "associated constants are experimental") } ast::ImplItemKind::Method(ref sig, _) => { - if sig.constness == ast::Constness::Const { + if sig.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d130..a89dc80df4b08 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -937,7 +937,10 @@ mod tests { variadic: false }), ast::Unsafety::Normal, - ast::Constness::NotConst, + Spanned { + span: sp(0,2), + node: ast::Constness::NotConst, + }, Abi::Rust, ast::Generics{ // no idea on either of these: lifetimes: Vec::new(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1646246069ead..757c0779e352a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -39,7 +39,7 @@ use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; use ast; -use codemap::{self, CodeMap, Spanned, spanned}; +use codemap::{self, CodeMap, Spanned, spanned, respan}; use syntax_pos::{self, Span, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; use ext::tt::macro_parser; @@ -4768,7 +4768,7 @@ impl<'a> Parser<'a> { /// Parse an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, - constness: Constness, + constness: Spanned, abi: abi::Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; @@ -4794,18 +4794,21 @@ impl<'a> Parser<'a> { /// - `extern fn` /// - etc pub fn parse_fn_front_matter(&mut self) - -> PResult<'a, (ast::Constness, ast::Unsafety, abi::Abi)> { + -> PResult<'a, (Spanned, + ast::Unsafety, + abi::Abi)> { let is_const_fn = self.eat_keyword(keywords::Const); + let const_span = self.last_span; let unsafety = self.parse_unsafety()?; let (constness, unsafety, abi) = if is_const_fn { - (Constness::Const, unsafety, Abi::Rust) + (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi()?.unwrap_or(Abi::C) } else { Abi::Rust }; - (Constness::NotConst, unsafety, abi) + (respan(self.last_span, Constness::NotConst), unsafety, abi) }; self.expect_keyword(keywords::Fn)?; Ok((constness, unsafety, abi)) @@ -5704,9 +5707,12 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Fn) { // EXTERN FUNCTION ITEM + let fn_span = self.last_span; let abi = opt_abi.unwrap_or(Abi::C); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi)?; + self.parse_item_fn(Unsafety::Normal, + respan(fn_span, Constness::NotConst), + abi)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5740,6 +5746,7 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } if self.eat_keyword(keywords::Const) { + let const_span = self.last_span; if self.check_keyword(keywords::Fn) || (self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) { @@ -5751,7 +5758,9 @@ impl<'a> Parser<'a> { }; self.bump(); let (ident, item_, extra_attrs) = - self.parse_item_fn(unsafety, Constness::Const, Abi::Rust)?; + self.parse_item_fn(unsafety, + respan(const_span, Constness::Const), + Abi::Rust)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5815,8 +5824,11 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Fn) { // FUNCTION ITEM self.bump(); + let fn_span = self.last_span; let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, Constness::NotConst, Abi::Rust)?; + self.parse_item_fn(Unsafety::Normal, + respan(fn_span, Constness::NotConst), + Abi::Rust)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5836,8 +5848,11 @@ impl<'a> Parser<'a> { Abi::Rust }; self.expect_keyword(keywords::Fn)?; + let fn_span = self.last_span; let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi)?; + self.parse_item_fn(Unsafety::Unsafe, + respan(fn_span, Constness::NotConst), + abi)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..4c83440306306 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1184,7 +1184,7 @@ impl<'a> State<'a> { try!(self.print_fn( decl, unsafety, - constness, + constness.node, abi, Some(item.ident), typarams, @@ -1518,7 +1518,7 @@ impl<'a> State<'a> { -> io::Result<()> { self.print_fn(&m.decl, m.unsafety, - m.constness, + m.constness.node, m.abi, Some(ident), &m.generics, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index faf6a17a15045..cbf9aa8c6c17f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -24,7 +24,7 @@ use attr; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; -use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute}; +use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned}; use errors; use errors::snippet::{SnippetData}; use config; @@ -485,7 +485,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { let main_body = ecx.block(sp, vec![call_test_main]); let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty), ast::Unsafety::Normal, - ast::Constness::NotConst, + dummy_spanned(ast::Constness::NotConst), ::abi::Abi::Rust, ast::Generics::default(), main_body); let main = P(ast::Item { ident: token::str_to_ident("main"), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 582412119caa8..d75110b2654ce 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -31,7 +31,7 @@ use codemap::Spanned; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, &'a Visibility), + ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility), /// fn foo(&self) Method(Ident, &'a MethodSig, Option<&'a Visibility>), diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..809f444b9936e 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -197,7 +197,7 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; -use syntax::codemap::{self, respan}; +use syntax::codemap::{self, dummy_spanned, respan}; use syntax::util::move_map::MoveMap; use syntax::parse::token::{InternedString, keywords}; use syntax::ptr::P; @@ -901,7 +901,8 @@ impl<'a> MethodDef<'a> { generics: fn_generics, abi: abi, unsafety: unsafety, - constness: ast::Constness::NotConst, + constness: + dummy_spanned(ast::Constness::NotConst), decl: fn_decl, }, body_block), From e46b09a1f9051a65544dee08f4d8d749d474d586 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 12 Aug 2016 15:47:42 -0700 Subject: [PATCH 327/768] Add UI test for E0379 --- .../ui/mismatched_types/const-fn-in-trait.rs | 25 +++++++++++++++++++ .../mismatched_types/const-fn-in-trait.stderr | 14 +++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/ui/mismatched_types/const-fn-in-trait.rs create mode 100644 src/test/ui/mismatched_types/const-fn-in-trait.stderr diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.rs b/src/test/ui/mismatched_types/const-fn-in-trait.rs new file mode 100644 index 0000000000000..5e44030eab71a --- /dev/null +++ b/src/test/ui/mismatched_types/const-fn-in-trait.rs @@ -0,0 +1,25 @@ +// 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. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +#![feature(const_fn)] + +trait Foo { + fn f() -> u32; + const fn g(); +} + +impl Foo for u32 { + const fn f() -> u32 { 22 } + fn g() {} +} + +fn main() { } diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr new file mode 100644 index 0000000000000..f7b7635e41aec --- /dev/null +++ b/src/test/ui/mismatched_types/const-fn-in-trait.stderr @@ -0,0 +1,14 @@ +error[E0379]: trait fns cannot be declared const + --> $DIR/const-fn-in-trait.rs:17:5 + | +17 | const fn g(); + | ^^^^^ trait fns cannot be const + +error[E0379]: trait fns cannot be declared const + --> $DIR/const-fn-in-trait.rs:21:5 + | +21 | const fn f() -> u32 { 22 } + | ^^^^^ trait fns cannot be const + +error: aborting due to 2 previous errors + From 8766c18473c23502c37a6edfe999999ed86053c2 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 28 Aug 2016 15:37:37 +0200 Subject: [PATCH 328/768] Revert changes to the reproducible-builds test --- src/test/run-make/reproducible-build/Makefile | 24 +++++++------------ .../reproducible-build-aux.rs | 8 +------ .../reproducible-build/reproducible-build.rs | 10 ++++---- 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/test/run-make/reproducible-build/Makefile b/src/test/run-make/reproducible-build/Makefile index 8db9e0ec078f6..8e799ca1a4303 100644 --- a/src/test/run-make/reproducible-build/Makefile +++ b/src/test/run-make/reproducible-build/Makefile @@ -1,26 +1,20 @@ -include ../tools.mk all: $(RUSTC) reproducible-build-aux.rs - mv "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/first.rlib" - $(RUSTC) reproducible-build-aux.rs - cp "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/second.rlib" - cmp "$(TMPDIR)/first.rlib" "$(TMPDIR)/second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build1" $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build2" - cmp "$(TMPDIR)/reproducible-build1" "$(TMPDIR)/reproducible-build2" || exit 1 - $(RUSTC) reproducible-build-aux.rs -g - mv "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/first.rlib" + nm "$(TMPDIR)/reproducible-build1" | sort > "$(TMPDIR)/reproducible-build1.nm" + nm "$(TMPDIR)/reproducible-build2" | sort > "$(TMPDIR)/reproducible-build2.nm" + cmp "$(TMPDIR)/reproducible-build1.nm" "$(TMPDIR)/reproducible-build2.nm" || exit 1 $(RUSTC) reproducible-build-aux.rs -g - cp "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/second.rlib" - cmp "$(TMPDIR)/first.rlib" "$(TMPDIR)/second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug" $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug" - cmp "$(TMPDIR)/reproducible-build1-debug" "$(TMPDIR)/reproducible-build2-debug" || exit 1 - $(RUSTC) reproducible-build-aux.rs -O - mv "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/first.rlib" + nm "$(TMPDIR)/reproducible-build1-debug" | sort > "$(TMPDIR)/reproducible-build1-debug.nm" + nm "$(TMPDIR)/reproducible-build2-debug" | sort > "$(TMPDIR)/reproducible-build2-debug.nm" + cmp "$(TMPDIR)/reproducible-build1-debug.nm" "$(TMPDIR)/reproducible-build2-debug.nm" || exit 1 $(RUSTC) reproducible-build-aux.rs -O - cp "$(TMPDIR)/libreproducible_build_aux.rlib" "$(TMPDIR)/second.rlib" - cmp "$(TMPDIR)/first.rlib" "$(TMPDIR)/second.rlib" || exit 1 $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt" $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt" - cmp "$(TMPDIR)/reproducible-build1-opt" "$(TMPDIR)/reproducible-build2-opt" || exit 1 + nm "$(TMPDIR)/reproducible-build1-opt" | sort > "$(TMPDIR)/reproducible-build1-opt.nm" + nm "$(TMPDIR)/reproducible-build2-opt" | sort > "$(TMPDIR)/reproducible-build2-opt.nm" + cmp "$(TMPDIR)/reproducible-build1-opt.nm" "$(TMPDIR)/reproducible-build2-opt.nm" || exit 1 diff --git a/src/test/run-make/reproducible-build/reproducible-build-aux.rs b/src/test/run-make/reproducible-build/reproducible-build-aux.rs index 73a62eee265cd..9ef853e79960b 100644 --- a/src/test/run-make/reproducible-build/reproducible-build-aux.rs +++ b/src/test/run-make/reproducible-build/reproducible-build-aux.rs @@ -33,12 +33,6 @@ pub enum Enum { pub struct TupleStruct(pub i8, pub i16, pub i32, pub i64); -pub trait Marker {} -impl Marker for char {} -impl Marker for (T, U) {} - -pub trait Trait where T1: 'static { - type Assoc: Marker; - +pub trait Trait { fn foo(&self); } diff --git a/src/test/run-make/reproducible-build/reproducible-build.rs b/src/test/run-make/reproducible-build/reproducible-build.rs index 17c2e87b5c1a6..dc7c702e5cc67 100644 --- a/src/test/run-make/reproducible-build/reproducible-build.rs +++ b/src/test/run-make/reproducible-build/reproducible-build.rs @@ -67,10 +67,7 @@ impl Trait for u64 { fn foo(&self) {} } -impl -reproducible_build_aux::Trait for TupleStruct { - type Assoc = (u8, i16); - +impl reproducible_build_aux::Trait for TupleStruct { fn foo(&self) {} } @@ -120,11 +117,12 @@ fn main() { let _ = reproducible_build_aux::Enum::Variant3 { x: 0 }; let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4); - let object_shim: &reproducible_build_aux::Trait = - &TupleStruct(0, 1, 2, 3); + let object_shim: &reproducible_build_aux::Trait = &TupleStruct(0, 1, 2, 3); object_shim.foo(); let pointer_shim: &Fn(i32) = ®ular_fn; TupleStruct(1, 2, 3, 4).bar(); } + + From 15d8dfb6a0c7241845e4636cfc7d8cbf86108a08 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 28 Aug 2016 13:18:28 -0500 Subject: [PATCH 329/768] build llvm with systemz backend enabled, and link to related libraries when building rust against system llvm closes #36077 --- configure | 2 +- mk/main.mk | 2 +- src/rustllvm/PassWrapper.cpp | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/configure b/configure index a48ff6a76109c..44fb3d368d2c7 100755 --- a/configure +++ b/configure @@ -1747,7 +1747,7 @@ do CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" fi - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC'" + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ'" CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'" CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR" diff --git a/mk/main.mk b/mk/main.mk index 428d9d16182ab..5a849af9856f1 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -300,7 +300,7 @@ endif # LLVM macros ###################################################################### -LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl +LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \ interpreter instrumentation diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 0555a96ff24ce..a271987210b67 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -131,12 +131,19 @@ LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { #define SUBTARGET_PPC #endif +#ifdef LLVM_COMPONENT_SYSTEMZ +#define SUBTARGET_SYSTEMZ SUBTARGET(SystemZ) +#else +#define SUBTARGET_SYSTEMZ +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ SUBTARGET_AARCH64 \ SUBTARGET_MIPS \ - SUBTARGET_PPC + SUBTARGET_PPC \ + SUBTARGET_SYSTEMZ #define SUBTARGET(x) namespace llvm { \ extern const SubtargetFeatureKV x##FeatureKV[]; \ From 744312754dc3a3c36d2a609bb24889cb1b7994de Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 28 Aug 2016 20:35:48 +0200 Subject: [PATCH 330/768] fixed and extended tests once more --- src/test/compile-fail/rfc1623.rs | 70 ++++++++++++++++++++++++++++++-- src/test/run-pass/rfc1623.rs | 5 +-- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 963459b27bf1f..abdcc02de767f 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -17,18 +17,82 @@ static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = //~^ ERROR: missing lifetime specifier &(non_elidable as fn(&u8, &u8) -> &u8); +struct SomeStruct<'x, 'y, 'z: 'x> { + foo: &'x Foo<'z>, + bar: &'x Bar<'z>, + f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, +} + +fn id(t: T) -> T { t } + +static SOME_STRUCT : &SomeStruct = SomeStruct { + foo: &Foo { bools: &[false, true] }, + bar: &Bar { bools: &[true, true] }, + f: &id, +}; + +// very simple test for a 'static static with default lifetime +static STATIC_STR : &'static str = "&'static str"; +const CONST_STR : &'static str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; +const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; +const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; + type Baz<'a> = fn(&'a [u8]) -> Option; fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } -static STATIC_BAZ : &Baz<'static> = &(baz as Baz); -const CONST_BAZ : &Baz<'static> = &(baz as Baz); +static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); +const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); + +static BYTES : &'static [u8] = &[1, 2, 3]; fn main() { let x = &[1u8, 2, 3]; let y = x; - //surprisingly this appears to work, so lifetime < `'static` is valid + //this works, so lifetime < `'static` is valid assert_eq!(Some(1), STATIC_BAZ(y)); assert_eq!(Some(1), CONST_BAZ(y)); + + let y = &[1u8, 2, 3]; + //^~ ERROR: borrowed values does not live long enough + STATIC_BAZ(BYTES); // BYTES has static lifetime + CONST_BAZ(y); // This forces static lifetime, which y has not } diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index bd0420bb5067a..0915118ca27c0 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -68,9 +68,8 @@ fn main() { STATIC_SIMPLE_FN(x); CONST_SIMPLE_FN(x); - let y = &[1u8, 2, 3]; - STATIC_BAZ(BYTES); - //CONST_BAZ(y); // strangely enough, this fails + STATIC_BAZ(BYTES); // neees static lifetime + CONST_BAZ(BYTES); // make sure this works with different lifetimes let a = &1; From ef4952e73926bda4cfdbd0e48badc3ae30e4fb58 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 28 Aug 2016 18:52:21 -0400 Subject: [PATCH 331/768] Address FIXME in libcollectionstest/btree/set.rs --- src/libcollectionstest/btree/set.rs | 30 ++++++----------------------- src/libcollectionstest/lib.rs | 1 - 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index f7b647d7772db..a32e3f1a76aea 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollectionstest/btree/set.rs @@ -39,30 +39,8 @@ fn test_hash() { assert!(::hash(&x) == ::hash(&y)); } -struct Counter<'a, 'b> { - i: &'a mut usize, - expected: &'b [i32], -} - -impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> { - extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool { - assert_eq!(x, self.expected[*self.i]); - *self.i += 1; - true - } -} - -impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> { - type Output = bool; - - extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool { - self.call_mut(args) - } -} - fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where - // FIXME Replace Counter with `Box _>` - F: FnOnce(&BTreeSet, &BTreeSet, Counter) -> bool, + F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool, { let mut set_a = BTreeSet::new(); let mut set_b = BTreeSet::new(); @@ -71,7 +49,11 @@ fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where for y in b { assert!(set_b.insert(*y)) } let mut i = 0; - f(&set_a, &set_b, Counter { i: &mut i, expected: expected }); + f(&set_a, &set_b, &mut |&x| { + assert_eq!(x, expected[i]); + i += 1; + true + }); assert_eq!(i, expected.len()); } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index f448fcf2dbf99..32a07e3e7e621 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -16,7 +16,6 @@ #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] -#![feature(fn_traits)] #![feature(enumset)] #![feature(pattern)] #![feature(rand)] From da566aeebf27f5adf2446366a1f2f84ba703f1a8 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 28 Aug 2016 19:10:12 -0400 Subject: [PATCH 332/768] Add test for #34053 Closes #34053 --- src/test/run-pass/issue-34053.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/issue-34053.rs diff --git a/src/test/run-pass/issue-34053.rs b/src/test/run-pass/issue-34053.rs new file mode 100644 index 0000000000000..7f8a4941494a9 --- /dev/null +++ b/src/test/run-pass/issue-34053.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(drop_types_in_const)] + +struct A(i32); + +impl Drop for A { + fn drop(&mut self) {} +} + +static FOO: A = A(123); + +fn main() { + println!("{}", &FOO.0); +} From 9c256ec94bd2270508ded3dfa569b5d440140213 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 28 Aug 2016 19:16:13 -0400 Subject: [PATCH 333/768] Add test for #35423 Closes #35423 --- src/test/run-pass/issue-35423.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/run-pass/issue-35423.rs diff --git a/src/test/run-pass/issue-35423.rs b/src/test/run-pass/issue-35423.rs new file mode 100644 index 0000000000000..35d0c305ed834 --- /dev/null +++ b/src/test/run-pass/issue-35423.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + let x = 4; + match x { + ref r if *r < 0 => println!("got negative num {} < 0", r), + e @ 1 ... 100 => println!("got number within range [1,100] {}", e), + _ => println!("no"), + } +} From f74063136375fec1208ab937314b0f4ca7f92cbe Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 28 Aug 2016 19:21:04 -0400 Subject: [PATCH 334/768] Add test for #28324 Closes #28324 --- src/test/compile-fail/issue-28324.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/compile-fail/issue-28324.rs diff --git a/src/test/compile-fail/issue-28324.rs b/src/test/compile-fail/issue-28324.rs new file mode 100644 index 0000000000000..13ce41f4dcc54 --- /dev/null +++ b/src/test/compile-fail/issue-28324.rs @@ -0,0 +1,18 @@ +// 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. + +extern { + static error_message_count: u32; +} + +pub static BAZ: u32 = *&error_message_count; +//~^ ERROR cannot refer to other statics by value + +fn main() {} From 91bfa2c829e4a0ca01a75ec5f70e04717f0b4813 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 28 Aug 2016 19:28:31 -0400 Subject: [PATCH 335/768] Add test for #24204 Closes #24204 --- src/test/compile-fail/issue-24204.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/compile-fail/issue-24204.rs diff --git a/src/test/compile-fail/issue-24204.rs b/src/test/compile-fail/issue-24204.rs new file mode 100644 index 0000000000000..2a012da0083bc --- /dev/null +++ b/src/test/compile-fail/issue-24204.rs @@ -0,0 +1,27 @@ +// 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. + +#![allow(dead_code)] + +trait MultiDispatch { + type O; +} + +trait Trait: Sized { + type A: MultiDispatch; + type B; + + fn new(u: U) -> >::O where Self::A : MultiDispatch; +} + +fn test>(b: i32) -> T where T::A: MultiDispatch { T::new(b) } +//~^ ERROR type mismatch resolving + +fn main() {} From bc288a598c018273343f29f6ad609062ce4ac2c7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 28 Aug 2016 17:41:26 -0500 Subject: [PATCH 336/768] cabi: change some more 32s to 64s --- src/librustc_trans/cabi_mips64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs index d3d3f83eac431..e92ef1eaec8ec 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_trans/cabi_mips64.rs @@ -124,14 +124,14 @@ fn is_reg_ty(ty: Type) -> bool { fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) + Some(Type::i64(ccx)) } else { None } } fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); + let int_ty = Type::i64(ccx); let mut args = Vec::new(); let mut n = size / 64; From 2222d437a75dec627a21c0b68b32bee080fa1f5a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 28 Aug 2016 21:34:04 -0500 Subject: [PATCH 337/768] fix data-layouts --- src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs | 2 +- src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index 7e45b32065360..837856344280f 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), target_endian: "big".to_string(), target_pointer_width: "64".to_string(), - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + data_layout: "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index 338a5da1e1d1d..e1340e8e127b2 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + data_layout: "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), From 65249a5431bbc3bf6b0f0894aefcc28c76eb17bb Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Sun, 28 Aug 2016 22:55:39 +1000 Subject: [PATCH 338/768] E0459 Update error format #35933 - Fixes #35933 - Part of #35233 r? @jonathandturner --- src/librustc_metadata/creader.rs | 5 +++-- src/test/compile-fail/E0459.rs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 46469efea6bc8..b84c3e8a5bc25 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -977,8 +977,9 @@ impl<'a> LocalCrateReader<'a> { let n = match n { Some(n) => n, None => { - span_err!(self.sess, m.span, E0459, - "#[link(...)] specified without `name = \"foo\"`"); + struct_span_err!(self.sess, m.span, E0459, + "#[link(...)] specified without `name = \"foo\"`") + .span_label(m.span, &format!("missing `name` argument")).emit(); InternedString::new("foo") } }; diff --git a/src/test/compile-fail/E0459.rs b/src/test/compile-fail/E0459.rs index dc7ac714f2239..41376bd9ef5a2 100644 --- a/src/test/compile-fail/E0459.rs +++ b/src/test/compile-fail/E0459.rs @@ -9,6 +9,7 @@ // except according to those terms. #[link(kind = "dylib")] extern {} //~ ERROR E0459 + //~| NOTE missing `name` argument fn main() { } From 0412fa8b8e00bebc2bb0ad17a7e558f13b8954a7 Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Sun, 28 Aug 2016 23:55:43 +1000 Subject: [PATCH 339/768] E0458 Update error format #35932 - Fixes #35932 - Part of #35233 r? @jonathandturner --- src/librustc_metadata/creader.rs | 5 +++-- src/test/compile-fail/E0458.rs | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index b84c3e8a5bc25..8f4e9f941c600 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -965,8 +965,9 @@ impl<'a> LocalCrateReader<'a> { Some("dylib") => cstore::NativeUnknown, Some("framework") => cstore::NativeFramework, Some(k) => { - span_err!(self.sess, m.span, E0458, - "unknown kind: `{}`", k); + struct_span_err!(self.sess, m.span, E0458, + "unknown kind: `{}`", k) + .span_label(m.span, &format!("unknown kind")).emit(); cstore::NativeUnknown } None => cstore::NativeUnknown diff --git a/src/test/compile-fail/E0458.rs b/src/test/compile-fail/E0458.rs index 21bedc6b84c2b..e87158ae3b03f 100644 --- a/src/test/compile-fail/E0458.rs +++ b/src/test/compile-fail/E0458.rs @@ -9,7 +9,9 @@ // except according to those terms. #[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458 - //~^ ERROR E0459 + //~| NOTE unknown kind + //~| ERROR E0459 + //~| NOTE missing `name` argument fn main() { } From 4b5007a1a25c09746307c9e8cabdc6292f969582 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 28 Aug 2016 22:13:35 -0500 Subject: [PATCH 340/768] fix tidy error --- src/bootstrap/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8d0a6a81572f8..ef3fed6fd9433 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -517,7 +517,7 @@ impl Build { // NOTE `git submodule status` output looks like this: // // -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc - // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/rust-llvm-2016-07-18-1-gb37ef24) + // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..) // e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6) // // The first character can be '-', '+' or ' ' and denotes the `State` of the submodule From 4fe94e0be65865bef1d0283873158baa523afddc Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 29 Aug 2016 05:04:31 +0000 Subject: [PATCH 341/768] Future proof the AST for `union`. --- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/map/def_collector.rs | 4 ++-- src/librustc_resolve/build_reduced_graph.rs | 2 ++ src/librustc_resolve/lib.rs | 1 + src/libsyntax/ast.rs | 5 +++++ src/libsyntax/config.rs | 3 +++ src/libsyntax/fold.rs | 4 ++++ src/libsyntax/print/pprust.rs | 5 ++++- src/libsyntax/visit.rs | 3 ++- 9 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 24792e634a5d2..6739d3f662ac6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -638,6 +638,7 @@ impl<'a> LoweringContext<'a> { let struct_def = self.lower_variant_data(struct_def); hir::ItemStruct(struct_def, self.lower_generics(generics)) } + ItemKind::Union(..) => panic!("`union` is not yet implemented"), ItemKind::DefaultImpl(unsafety, ref trait_ref) => { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), self.lower_trait_ref(trait_ref)) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 752b0e9a253dd..77567fc7a4603 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -133,7 +133,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { let def_data = match i.node { ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => DefPathData::Impl, - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) | + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.name.as_str()), ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), @@ -164,7 +164,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { }); } } - ItemKind::Struct(ref struct_def, _) => { + ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { // If this is a tuple-like struct, register the constructor. if !struct_def.is_struct() { this.create_def(struct_def.id(), diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 12c55b3ac172c..71b00218e7cc1 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -275,6 +275,8 @@ impl<'b> Resolver<'b> { self.structs.insert(item_def_id, field_names); } + ItemKind::Union(..) => panic!("`union` is not yet implemented"), + ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {} ItemKind::Trait(_, _, _, ref items) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5641a50ccaccf..b5cf680cc129c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1619,6 +1619,7 @@ impl<'a> Resolver<'a> { ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) | ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) | ItemKind::Fn(_, _, _, _, ref generics, _) => { self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| visit::walk_item(this, item)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c0994ccb2acf9..fcb99444957c4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1883,6 +1883,10 @@ pub enum ItemKind { /// /// E.g. `struct Foo { x: A }` Struct(VariantData, Generics), + /// A union definition (`union` or `pub union`). + /// + /// E.g. `union Foo { x: A, y: B }` + Union(VariantData, Generics), // FIXME: not yet implemented /// A Trait declaration (`trait` or `pub trait`). /// /// E.g. `trait Foo { .. }` or `trait Foo { .. }` @@ -1919,6 +1923,7 @@ impl ItemKind { ItemKind::Ty(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", + ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::Mac(..) | ItemKind::Impl(..) | diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ff1ecd443717e..69a979176521b 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -180,6 +180,9 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { ast::ItemKind::Struct(def, generics) => { ast::ItemKind::Struct(fold_struct(self, def), generics) } + ast::ItemKind::Union(def, generics) => { + ast::ItemKind::Union(fold_struct(self, def), generics) + } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { self.configure(v).map(|v| { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fad0b6f65a70d..7500bfe9caa80 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -885,6 +885,10 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { let struct_def = folder.fold_variant_data(struct_def); ItemKind::Struct(struct_def, folder.fold_generics(generics)) } + ItemKind::Union(struct_def, generics) => { + let struct_def = folder.fold_variant_data(struct_def); + ItemKind::Union(struct_def, folder.fold_generics(generics)) + } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 99c00789219bf..8563d27908db6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1251,7 +1251,10 @@ impl<'a> State<'a> { try!(self.head(&visibility_qualified(&item.vis, "struct"))); try!(self.print_struct(&struct_def, generics, item.ident, item.span, true)); } - + ast::ItemKind::Union(ref struct_def, ref generics) => { + try!(self.head(&visibility_qualified(&item.vis, "union"))); + try!(self.print_struct(&struct_def, generics, item.ident, item.span, true)); + } ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => { try!(self.head("")); try!(self.print_visibility(&item.vis)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index b2d4799665956..efd9b027504f0 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -278,7 +278,8 @@ pub fn walk_item(visitor: &mut V, item: &Item) { visitor.visit_ty(typ); walk_list!(visitor, visit_impl_item, impl_items); } - ItemKind::Struct(ref struct_definition, ref generics) => { + ItemKind::Struct(ref struct_definition, ref generics) | + ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_variant_data(struct_definition, item.ident, generics, item.id, item.span); From 663caa9ddf856c5e3a9612b1ac002c8d0646a3c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 28 Aug 2016 10:52:03 +0000 Subject: [PATCH 342/768] Remove inherent methods `Annotatable::attrs` and `Annotatable::fold_attrs`. --- src/libsyntax/ext/base.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6ba3b92483fdd..43e190f5deb81 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -60,13 +60,6 @@ impl HasAttrs for Annotatable { } impl Annotatable { - pub fn attrs(&self) -> &[ast::Attribute] { - HasAttrs::attrs(self) - } - pub fn fold_attrs(self, attrs: Vec) -> Annotatable { - self.map_attrs(|_| attrs) - } - pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, From cdde06ea97ad7ef9718cc0896ab3989f11188da2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 28 Aug 2016 11:18:58 +0000 Subject: [PATCH 343/768] Fix merge conflicts. --- src/librustc_typeck/check/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index ed3e645eeebeb..d26de9b2a6c53 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -52,7 +52,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let i_n_tps = i_ty.generics.types.len(); if i_n_tps != n_tps { let span = match it.node { - hir::ForeignItemFn(_, ref generics) => generics.span().unwrap_or(it.span), + hir::ForeignItemFn(_, ref generics) => generics.span, hir::ForeignItemStatic(_, _) => it.span }; From 46fc80c44e8dfa974210c441eaf53c89dfad031e Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Sat, 27 Aug 2016 23:28:38 +0300 Subject: [PATCH 344/768] update error E0451 to new format --- src/librustc_privacy/lib.rs | 19 +++++++++++++------ src/test/compile-fail/E0451.rs | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 028632ad7c006..51202b5e3987d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -384,8 +384,10 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { if def.adt_kind() == ty::AdtKind::Struct && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { - span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private", - field.name, self.tcx.item_path_str(def.did)); + struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private", + field.name, self.tcx.item_path_str(def.did)) + .span_label(span, &format!("field `{}` is private", field.name)) + .emit(); } } @@ -425,14 +427,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { let method = self.tcx.tables.borrow().method_map[&method_call]; self.check_method(expr.span, method.def_id); } - hir::ExprStruct(..) => { + hir::ExprStruct(_, ref fields, _) => { let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(expr.id)); // RFC 736: ensure all unmentioned fields are visible. // Rather than computing the set of unmentioned fields // (i.e. `all_fields - fields`), just check them all. - for field in &variant.fields { - self.check_field(expr.span, adt, field); + for field in variant.fields.iter() { + let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) { + f.span + } else { + expr.span + }; + self.check_field(span, adt, field); } } hir::ExprPath(..) => { @@ -472,7 +479,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id)); for field in fields { - self.check_field(pattern.span, adt, variant.field_named(field.node.name)); + self.check_field(field.span, adt, variant.field_named(field.node.name)); } } PatKind::TupleStruct(_, ref fields, ddpos) => { diff --git a/src/test/compile-fail/E0451.rs b/src/test/compile-fail/E0451.rs index 9e4a8713a33e0..f7b106d160dae 100644 --- a/src/test/compile-fail/E0451.rs +++ b/src/test/compile-fail/E0451.rs @@ -13,8 +13,24 @@ mod Bar { pub a: isize, b: isize, } + + pub struct FooTuple ( + pub isize, + isize, + ); +} + +fn pat_match(foo: Bar::Foo) { + let Bar::Foo{a:a, b:b} = foo; //~ ERROR E0451 + //~^ NOTE field `b` is private +} + +fn pat_match_tuple(foo: Bar::FooTuple) { + let Bar::FooTuple(a,b) = foo; //~ ERROR E0451 + //~^ NOTE field `1` is private } fn main() { let f = Bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451 + //~^ NOTE field `b` is private } From 59e5e0b2db2ab66f138044bde80c44c7f9391a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 29 Aug 2016 10:53:12 +0200 Subject: [PATCH 345/768] Avoid using pthread_condattr_setclock on Android. The pthread_condattr_setclock is available only since Android 5.0 and API level 21. --- src/libstd/sys/unix/condvar.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 725a071a4f9fe..27b9f131d120b 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -30,10 +30,10 @@ impl Condvar { Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } } - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] pub unsafe fn init(&mut self) {} - #[cfg(not(any(target_os = "macos", target_os = "ios")))] + #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] pub unsafe fn init(&mut self) { use mem; let mut attr: libc::pthread_condattr_t = mem::uninitialized(); @@ -69,7 +69,7 @@ impl Condvar { // where we configure condition variable to use monotonic clock (instead of // default system clock). This approach avoids all problems that result // from changes made to the system time. - #[cfg(not(any(target_os = "macos", target_os = "ios")))] + #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use mem; @@ -99,7 +99,7 @@ impl Condvar { // This implementation is modeled after libcxx's condition_variable // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use ptr; use time::Instant; From 9ce47e318aa1b8ec9442d19e40b8d00c99b65239 Mon Sep 17 00:00:00 2001 From: king6cong Date: Mon, 29 Aug 2016 16:53:38 +0800 Subject: [PATCH 346/768] fix git submodule status check --- src/bootstrap/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a487c95fec200..dbf29cda49212 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -528,7 +528,7 @@ impl Build { let path = Path::new(line[1..].split(' ').skip(1).next().unwrap()); let state = if line.starts_with('-') { State::NotInitialized - } else if line.starts_with('*') { + } else if line.starts_with('+') { State::OutOfSync } else if line.starts_with(' ') { State::MaybeDirty From d6fc2baa11f0fc5223d4e4b9f84e60ca60e64871 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Mon, 29 Aug 2016 16:20:08 +0530 Subject: [PATCH 347/768] Update E0260 to new error format Updates #35515. Part of #35233. r? @jonathandturner --- src/librustc_resolve/lib.rs | 6 +++++- src/test/compile-fail/E0260.rs | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6a4a48377c783..9d0c93f3e9dd2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3354,7 +3354,11 @@ impl<'a> Resolver<'a> { e.span_label(span, &"already imported"); e }, - (true, _) | (_, true) => struct_span_err!(self.session, span, E0260, "{}", msg), + (true, _) | (_, true) => { + let mut e = struct_span_err!(self.session, span, E0260, "{}", msg); + e.span_label(span, &format!("`{}` already imported", name)); + e + }, _ => match (old_binding.is_import(), binding.is_import()) { (false, false) => { let mut e = struct_span_err!(self.session, span, E0428, "{}", msg); diff --git a/src/test/compile-fail/E0260.rs b/src/test/compile-fail/E0260.rs index d20829bf4d415..63647cb41035a 100644 --- a/src/test/compile-fail/E0260.rs +++ b/src/test/compile-fail/E0260.rs @@ -9,8 +9,11 @@ // except according to those terms. extern crate collections; +//~^ NOTE previous import of `collections` here -mod collections { //~ ERROR E0260 +mod collections { +//~^ ERROR `collections` has already been imported in this module [E0260] +//~| NOTE `collections` already imported pub trait MyTrait { fn do_something(); } From e95f119d68008891193cdc10cf2ebc33e73c693c Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 29 Aug 2016 14:03:57 +0200 Subject: [PATCH 348/768] rustfmt tests --- src/test/compile-fail/rfc1623.rs | 72 ++++++++++++++++---------------- src/test/run-pass/rfc1623.rs | 54 ++++++++++++------------ 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index abdcc02de767f..3e9afdd5b13ae 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -10,12 +10,12 @@ #![allow(dead_code)] -fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { + a +} // the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ ERROR: missing lifetime specifier - &(non_elidable as fn(&u8, &u8) -> &u8); +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8); struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -23,76 +23,78 @@ struct SomeStruct<'x, 'y, 'z: 'x> { f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, } -fn id(t: T) -> T { t } +fn id(t: T) -> T { + t +} -static SOME_STRUCT : &SomeStruct = SomeStruct { +static SOME_STRUCT: &SomeStruct = SomeStruct { foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, }; // very simple test for a 'static static with default lifetime -static STATIC_STR : &'static str = "&'static str"; -const CONST_STR : &'static str = "&'static str"; +static STATIC_STR: &'static str = "&'static str"; +const CONST_STR: &'static str = "&'static str"; // this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; +static EXPLICIT_STATIC_STR: &'static str = "&'static str"; +const EXPLICIT_CONST_STR: &'static str = "&'static str"; // a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } +fn id_u8_slice(arg: &[u8]) -> &[u8] { + arg +} // one with a function, argument elided -static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); +static STATIC_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +static STATIC_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } +fn multi_args(a: &u8, b: &u8, c: &u8) {} -static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); +static STATIC_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); struct Foo<'a> { - bools: &'a [bool] + bools: &'a [bool], } -static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; -const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; +static STATIC_FOO: Foo<'static> = Foo { bools: &[true, false] }; +const CONST_FOO: Foo<'static> = Foo { bools: &[true, false] }; type Bar<'a> = Foo<'a>; -static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; -const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; +static STATIC_BAR: Bar<'static> = Bar { bools: &[true, false] }; +const CONST_BAR: Bar<'static> = Bar { bools: &[true, false] }; type Baz<'a> = fn(&'a [u8]) -> Option; -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } +fn baz(e: &[u8]) -> Option { + e.first().map(|x| *x) +} -static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); -const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); +static STATIC_BAZ: &'static Baz<'static> = &(baz as Baz); +const CONST_BAZ: &'static Baz<'static> = &(baz as Baz); -static BYTES : &'static [u8] = &[1, 2, 3]; +static BYTES: &'static [u8] = &[1, 2, 3]; fn main() { let x = &[1u8, 2, 3]; let y = x; - //this works, so lifetime < `'static` is valid + // this works, so lifetime < `'static` is valid assert_eq!(Some(1), STATIC_BAZ(y)); assert_eq!(Some(1), CONST_BAZ(y)); let y = &[1u8, 2, 3]; - //^~ ERROR: borrowed values does not live long enough + // ^~ ERROR: borrowed values does not live long enough STATIC_BAZ(BYTES); // BYTES has static lifetime CONST_BAZ(y); // This forces static lifetime, which y has not } diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 0915118ca27c0..17453933c8abc 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -11,56 +11,56 @@ #![allow(dead_code)] // very simple test for a 'static static with default lifetime -static STATIC_STR : &str = "&'static str"; -const CONST_STR : &str = "&'static str"; +static STATIC_STR: &str = "&'static str"; +const CONST_STR: &str = "&'static str"; // this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; +static EXPLICIT_STATIC_STR: &'static str = "&'static str"; +const EXPLICIT_CONST_STR: &'static str = "&'static str"; // a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } +fn id_u8_slice(arg: &[u8]) -> &[u8] { + arg +} // one with a function, argument elided -static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); +static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } +fn multi_args(a: &u8, b: &u8, c: &u8) {} -static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); +static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); struct Foo<'a> { - bools: &'a [bool] + bools: &'a [bool], } -static STATIC_FOO : Foo = Foo { bools: &[true, false] }; -const CONST_FOO : Foo = Foo { bools: &[true, false] }; +static STATIC_FOO: Foo = Foo { bools: &[true, false] }; +const CONST_FOO: Foo = Foo { bools: &[true, false] }; type Bar<'a> = Foo<'a>; -static STATIC_BAR : Bar = Bar { bools: &[true, false] }; -const CONST_BAR : Bar = Bar { bools: &[true, false] }; +static STATIC_BAR: Bar = Bar { bools: &[true, false] }; +const CONST_BAR: Bar = Bar { bools: &[true, false] }; type Baz<'a> = fn(&'a [u8]) -> Option; -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } +fn baz(e: &[u8]) -> Option { + e.first().map(|x| *x) +} -static STATIC_BAZ : &Baz = &(baz as Baz); -const CONST_BAZ : &Baz = &(baz as Baz); +static STATIC_BAZ: &Baz = &(baz as Baz); +const CONST_BAZ: &Baz = &(baz as Baz); -static BYTES : &[u8] = &[1, 2, 3]; +static BYTES: &[u8] = &[1, 2, 3]; fn main() { // make sure that the lifetime is actually elided (and not defaulted) From a87b4d88fb5c40736a5d884ac9fd3f01690d29d6 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 29 Aug 2016 16:45:22 +0200 Subject: [PATCH 349/768] removed unneeded test, also compiletest vs. rustfmt --- src/test/compile-fail/regions-in-consts.rs | 15 ---- src/test/compile-fail/rfc1623.rs | 5 +- src/test/compile-fail/rfc1623.rs.bk | 98 ++++++++++++++++++++++ src/test/run-pass/rfc1623.rs.bk | 81 ++++++++++++++++++ 4 files changed, 182 insertions(+), 17 deletions(-) delete mode 100644 src/test/compile-fail/regions-in-consts.rs create mode 100644 src/test/compile-fail/rfc1623.rs.bk create mode 100644 src/test/run-pass/rfc1623.rs.bk diff --git a/src/test/compile-fail/regions-in-consts.rs b/src/test/compile-fail/regions-in-consts.rs deleted file mode 100644 index 8d0829a4cffc3..0000000000000 --- a/src/test/compile-fail/regions-in-consts.rs +++ /dev/null @@ -1,15 +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. - -static c_y: &isize = &22; //~ ERROR missing lifetime specifier -static c_z: &'static isize = &22; - -fn main() { -} diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 3e9afdd5b13ae..1d8fc7fe111c0 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -16,6 +16,7 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { // the boundaries of elision static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8); +//~^ ERROR missing lifetime specifier [E0106] struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -94,7 +95,7 @@ fn main() { assert_eq!(Some(1), CONST_BAZ(y)); let y = &[1u8, 2, 3]; - // ^~ ERROR: borrowed values does not live long enough + STATIC_BAZ(BYTES); // BYTES has static lifetime - CONST_BAZ(y); // This forces static lifetime, which y has not + CONST_BAZ(y); // interestingly this does not get reported } diff --git a/src/test/compile-fail/rfc1623.rs.bk b/src/test/compile-fail/rfc1623.rs.bk new file mode 100644 index 0000000000000..abdcc02de767f --- /dev/null +++ b/src/test/compile-fail/rfc1623.rs.bk @@ -0,0 +1,98 @@ +// 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. + +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } + +// the boundaries of elision +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = +//~^ ERROR: missing lifetime specifier + &(non_elidable as fn(&u8, &u8) -> &u8); + +struct SomeStruct<'x, 'y, 'z: 'x> { + foo: &'x Foo<'z>, + bar: &'x Bar<'z>, + f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, +} + +fn id(t: T) -> T { t } + +static SOME_STRUCT : &SomeStruct = SomeStruct { + foo: &Foo { bools: &[false, true] }, + bar: &Bar { bools: &[true, true] }, + f: &id, +}; + +// very simple test for a 'static static with default lifetime +static STATIC_STR : &'static str = "&'static str"; +const CONST_STR : &'static str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; +const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; +const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); +const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); + +static BYTES : &'static [u8] = &[1, 2, 3]; + +fn main() { + let x = &[1u8, 2, 3]; + let y = x; + + //this works, so lifetime < `'static` is valid + assert_eq!(Some(1), STATIC_BAZ(y)); + assert_eq!(Some(1), CONST_BAZ(y)); + + let y = &[1u8, 2, 3]; + //^~ ERROR: borrowed values does not live long enough + STATIC_BAZ(BYTES); // BYTES has static lifetime + CONST_BAZ(y); // This forces static lifetime, which y has not +} diff --git a/src/test/run-pass/rfc1623.rs.bk b/src/test/run-pass/rfc1623.rs.bk new file mode 100644 index 0000000000000..0915118ca27c0 --- /dev/null +++ b/src/test/run-pass/rfc1623.rs.bk @@ -0,0 +1,81 @@ +// 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. + +#![allow(dead_code)] + +// very simple test for a 'static static with default lifetime +static STATIC_STR : &str = "&'static str"; +const CONST_STR : &str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo = Foo { bools: &[true, false] }; +const CONST_FOO : Foo = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar = Bar { bools: &[true, false] }; +const CONST_BAR : Bar = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &Baz = &(baz as Baz); +const CONST_BAZ : &Baz = &(baz as Baz); + +static BYTES : &[u8] = &[1, 2, 3]; + +fn main() { + // make sure that the lifetime is actually elided (and not defaulted) + let x = &[1u8, 2, 3]; + STATIC_SIMPLE_FN(x); + CONST_SIMPLE_FN(x); + + STATIC_BAZ(BYTES); // neees static lifetime + CONST_BAZ(BYTES); + + // make sure this works with different lifetimes + let a = &1; + { + let b = &2; + let c = &3; + CONST_MULTI_FN(a, b, c); + } +} From 89f7e9269826abf44ee39fdde06197aff15f30ff Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 15:10:57 -0400 Subject: [PATCH 350/768] demonstrate `RHS != Self` use cases for `Add` and `Sub` remove extra `../`s --- src/libcore/ops.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 5d431230e9744..78c8fc0ac4549 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -212,6 +212,12 @@ macro_rules! forward_ref_binop { /// Point { x: 3, y: 3 }); /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Add`, which permits +/// operations of the form `SystemTime = SystemTime + Duration`. +/// +/// [std::time::SystemTime]: ../time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Add { @@ -279,6 +285,12 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Point { x: 1, y: 0 }); /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Sub`, which permits +/// operations of the form `SystemTime = SystemTime - Duration`. +/// +/// [std::time::SystemTime]: ../time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Sub { From 41d0a89e3ad99a9fdf700ea7d15750fe1cbfab14 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 17 Aug 2016 17:41:33 +0200 Subject: [PATCH 351/768] Implement From for u32, and From for char These fit with other From implementations between integer types. This helps the coding style of avoiding the 'as' operator that sometimes silently truncates, and signals that these specific conversions are lossless and infaillible. --- src/libcore/char.rs | 34 ++++++++++++++++++++++++++++++++++ src/libcoretest/char.rs | 8 ++++++++ 2 files changed, 42 insertions(+) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 4677f0b523f42..47a8678d608ae 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -175,6 +175,40 @@ pub unsafe fn from_u32_unchecked(i: u32) -> char { transmute(i) } +#[stable(feature = "char_convert", since = "1.13.0")] +impl From for u32 { + #[inline] + fn from(c: char) -> Self { + c as u32 + } +} + +/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. +/// +/// Unicode is designed such that this effectively decodes bytes +/// with the character encoding that IANA calls ISO-8859-1. +/// This encoding is compatible with ASCII. +/// +/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hypen), +/// which leaves some "blanks", byte values that are not assigned to any character. +/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. +/// +/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, +/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks +/// to punctuation and various Latin characters. +/// +/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) +/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases +/// for a superset of Windows-1252 that fills the remaining blanks with corresponding +/// C0 and C1 control codes. +#[stable(feature = "char_convert", since = "1.13.0")] +impl From for char { + #[inline] + fn from(i: u8) -> Self { + i as char + } +} + /// Converts a digit in the given radix to a `char`. /// /// A 'radix' here is sometimes also called a 'base'. A radix of two diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 333503d738943..92a2b23d242b9 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -10,6 +10,14 @@ use std::char; +#[test] +fn test_convert() { + assert_eq!(u32::from('a'), 0x61); + assert_eq!(char::from(b'\0'), '\0'); + assert_eq!(char::from(b'a'), 'a'); + assert_eq!(char::from(b'\xFF'), '\u{FF}'); +} + #[test] fn test_is_lowercase() { assert!('a'.is_lowercase()); From f040208d533e1d6d9ee0e0408ee74e26e14d1284 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 17 Aug 2016 18:01:41 +0200 Subject: [PATCH 352/768] Implement TryFrom for char For symmetry with From for u32. --- src/libcore/char.rs | 35 +++++++++++++++++++++++++++++------ src/libcoretest/char.rs | 10 ++++++++++ src/librustc_unicode/char.rs | 2 ++ src/librustc_unicode/lib.rs | 1 + src/libstd/error.rs | 7 +++++++ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 47a8678d608ae..ad492c81bd38a 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -16,6 +16,8 @@ #![stable(feature = "core_char", since = "1.2.0")] use char_private::is_printable; +use convert::TryFrom; +use fmt; use iter::FusedIterator; use mem::transmute; @@ -122,12 +124,7 @@ pub const MAX: char = '\u{10ffff}'; #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_u32(i: u32) -> Option { - // catch out-of-bounds and surrogates - if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { - None - } else { - Some(unsafe { from_u32_unchecked(i) }) - } + char::try_from(i).ok() } /// Converts a `u32` to a `char`, ignoring validity. @@ -209,6 +206,32 @@ impl From for char { } } +#[unstable(feature = "try_from", issue = "33417")] +impl TryFrom for char { + type Err = CharTryFromError; + + #[inline] + fn try_from(i: u32) -> Result { + if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { + Err(CharTryFromError(())) + } else { + Ok(unsafe { from_u32_unchecked(i) }) + } + } +} + +/// The error type returned when a conversion from u32 to char fails. +#[unstable(feature = "try_from", issue = "33417")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CharTryFromError(()); + +#[unstable(feature = "try_from", issue = "33417")] +impl fmt::Display for CharTryFromError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "converted integer out of range for `char`".fmt(f) + } +} + /// Converts a digit in the given radix to a `char`. /// /// A 'radix' here is sometimes also called a 'base'. A radix of two diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 92a2b23d242b9..199437a431eee 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -9,6 +9,7 @@ // except according to those terms. use std::char; +use std::convert::TryFrom; #[test] fn test_convert() { @@ -16,6 +17,15 @@ fn test_convert() { assert_eq!(char::from(b'\0'), '\0'); assert_eq!(char::from(b'a'), 'a'); assert_eq!(char::from(b'\xFF'), '\u{FF}'); + assert_eq!(char::try_from(0_u32), Ok('\0')); + assert_eq!(char::try_from(0x61_u32), Ok('a')); + assert_eq!(char::try_from(0xD7FF_u32), Ok('\u{D7FF}')); + assert!(char::try_from(0xD800_u32).is_err()); + assert!(char::try_from(0xDFFF_u32).is_err()); + assert_eq!(char::try_from(0xE000_u32), Ok('\u{E000}')); + assert_eq!(char::try_from(0x10FFFF_u32), Ok('\u{10FFFF}')); + assert!(char::try_from(0x110000_u32).is_err()); + assert!(char::try_from(0xFFFF_FFFF_u32).is_err()); } #[test] diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index c2b7d7045ddd8..5a0c27d9c609f 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -40,6 +40,8 @@ pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode}; // unstable reexports +#[unstable(feature = "try_from", issue = "33417")] +pub use core::char::CharTryFromError; #[unstable(feature = "decode_utf8", issue = "33906")] pub use core::char::{DecodeUtf8, decode_utf8}; #[unstable(feature = "unicode", issue = "27783")] diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index b812c262ac197..65bd717e01a82 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -38,6 +38,7 @@ #![feature(fused)] #![feature(lang_items)] #![feature(staged_api)] +#![feature(try_from)] #![feature(unicode)] mod tables; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index ab537f39bf96a..1629062001003 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -302,6 +302,13 @@ impl<'a, T: ?Sized + Reflect> Error for cell::BorrowMutError<'a, T> { } } +#[unstable(feature = "try_from", issue = "33417")] +impl Error for char::CharTryFromError { + fn description(&self) -> &str { + "converted integer out of range for `char`" + } +} + // copied from any.rs impl Error + 'static { /// Returns true if the boxed type is the same as `T` From 58ced1635b6c7766b18d47af45bcd484af578ab5 Mon Sep 17 00:00:00 2001 From: Paul Fanelli Date: Sun, 28 Aug 2016 00:38:04 +0000 Subject: [PATCH 353/768] Update E0463 error message to new format --- src/librustc_metadata/loader.rs | 8 +++++--- src/test/compile-fail/E0463.rs | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index b2c87db8ef566..44d7861066da3 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -342,9 +342,11 @@ impl<'a> Context<'a> { "found crate `{}` compiled by an incompatible version of rustc{}", self.ident, add) } else { - struct_span_err!(self.sess, self.span, E0463, - "can't find crate for `{}`{}", - self.ident, add) + let mut err = struct_span_err!(self.sess, self.span, E0463, + "can't find crate for `{}`{}", + self.ident, add); + err.span_label(self.span, &format!("can't find crate")); + err }; if !self.rejected_via_triple.is_empty() { diff --git a/src/test/compile-fail/E0463.rs b/src/test/compile-fail/E0463.rs index 3eff107365af1..3ce5b83e89fd4 100644 --- a/src/test/compile-fail/E0463.rs +++ b/src/test/compile-fail/E0463.rs @@ -9,7 +9,9 @@ // except according to those terms. #![feature(plugin)] -#![plugin(cookie_monster)] //~ ERROR E0463 +#![plugin(cookie_monster)] +//~^ ERROR E0463 +//~| NOTE can't find crate extern crate cake_is_a_lie; fn main() { From bbf2c3c31f3dd7703f4a13724bada979a921a65f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 12:25:06 -0500 Subject: [PATCH 354/768] update libc submodule --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 71b5d57ada32c..49d64cae0699e 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 71b5d57ada32cc5076791becc3b9019da29dffd4 +Subproject commit 49d64cae0699ed9d9ed84810d737a26b0b519da8 From 899c2891e6be24100db723f2b5464969bcebe0f0 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sun, 28 Aug 2016 15:48:56 -0700 Subject: [PATCH 355/768] Fix illegal instruction caused by overflow in channel cloning --- src/libstd/sync/mpsc/shared.rs | 15 ++++++++++++--- src/libstd/sync/mpsc/sync.rs | 13 ++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index baa4db7e5c0fa..2a9618251ff52 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -21,6 +21,7 @@ pub use self::Failure::*; use core::cmp; +use core::intrinsics::abort; use core::isize; use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; @@ -34,6 +35,7 @@ use time::Instant; const DISCONNECTED: isize = isize::MIN; const FUDGE: isize = 1024; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; #[cfg(test)] const MAX_STEALS: isize = 5; #[cfg(not(test))] @@ -46,7 +48,7 @@ pub struct Packet { to_wake: AtomicUsize, // SignalToken for wake up // The number of channels which are currently using this packet. - channels: AtomicIsize, + channels: AtomicUsize, // See the discussion in Port::drop and the channel send methods for what // these are used for @@ -72,7 +74,7 @@ impl Packet { cnt: AtomicIsize::new(0), steals: 0, to_wake: AtomicUsize::new(0), - channels: AtomicIsize::new(2), + channels: AtomicUsize::new(2), port_dropped: AtomicBool::new(false), sender_drain: AtomicIsize::new(0), select_lock: Mutex::new(()), @@ -340,7 +342,14 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. pub fn clone_chan(&mut self) { - self.channels.fetch_add(1, Ordering::SeqCst); + let old_count = self.channels.fetch_add(1, Ordering::SeqCst); + + // See comments on Arc::clone() on why we do this (for `mem::forget`). + if old_count > MAX_REFCOUNT { + unsafe { + abort(); + } + } } // Decrement the reference count on a channel. This is called whenever a diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 9985daaba8f69..1d16e002a2bef 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -36,6 +36,8 @@ pub use self::Failure::*; use self::Blocker::*; +use core::intrinsics::abort; +use core::isize; use core::mem; use core::ptr; @@ -45,6 +47,8 @@ use sync::mpsc::select::StartResult::{self, Installed, Abort}; use sync::{Mutex, MutexGuard}; use time::Instant; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + pub struct Packet { /// Only field outside of the mutex. Just done for kicks, but mainly because /// the other shared channel already had the code implemented @@ -350,7 +354,14 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. pub fn clone_chan(&self) { - self.channels.fetch_add(1, Ordering::SeqCst); + let old_count = self.channels.fetch_add(1, Ordering::SeqCst); + + // See comments on Arc::clone() on why we do this (for `mem::forget`). + if old_count > MAX_REFCOUNT { + unsafe { + abort(); + } + } } pub fn drop_chan(&self) { From b56d61cfd7e1a0956406272268cb9659f384a304 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 28 Aug 2016 17:33:17 +0100 Subject: [PATCH 356/768] rustdoc: Fix associated consts in search results Associated consts can appear in none trait impls so need to be treated like methods when generating the search index. --- src/librustdoc/html/render.rs | 21 ++++++++++----------- src/test/rustdoc/auxiliary/issue-36031.rs | 21 +++++++++++++++++++++ src/test/rustdoc/issue-36031.rs | 19 +++++++++++++++++++ 3 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/test/rustdoc/auxiliary/issue-36031.rs create mode 100644 src/test/rustdoc/issue-36031.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5cb5cc051870b..688ee38249642 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -271,7 +271,7 @@ pub struct Cache { // then the fully qualified name of the structure isn't presented in `paths` // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. - orphan_methods: Vec<(DefId, clean::Item)>, + orphan_impl_items: Vec<(DefId, clean::Item)>, } /// Temporary storage for data obtained during `RustdocVisitor::clean()`. @@ -528,7 +528,7 @@ pub fn run(mut krate: clean::Crate, seen_mod: false, stripped_mod: false, access_levels: krate.access_levels.clone(), - orphan_methods: Vec::new(), + orphan_impl_items: Vec::new(), traits: mem::replace(&mut krate.external_traits, FnvHashMap()), deref_trait_did: deref_trait_did, typarams: external_typarams, @@ -580,12 +580,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let mut crate_paths = Vec::::new(); let Cache { ref mut search_index, - ref orphan_methods, + ref orphan_impl_items, ref mut paths, .. } = *cache; - // Attach all orphan methods to the type's definition if the type + // Attach all orphan items to the type's definition if the type // has since been learned. - for &(did, ref item) in orphan_methods { + for &(did, ref item) in orphan_impl_items { if let Some(&(ref fqp, _)) = paths.get(&did) { search_index.push(IndexItem { ty: item_type(item), @@ -1023,7 +1023,7 @@ impl DocFolder for Cache { // Index this method for searching later on if let Some(ref s) = item.name { - let (parent, is_method) = match item.inner { + let (parent, is_inherent_impl_item) = match item.inner { clean::StrippedItem(..) => ((None, None), false), clean::AssociatedConstItem(..) | clean::TypedefItem(_, true) if self.parent_is_trait_impl => { @@ -1031,7 +1031,6 @@ impl DocFolder for Cache { ((None, None), false) } clean::AssociatedTypeItem(..) | - clean::AssociatedConstItem(..) | clean::TyMethodItem(..) | clean::StructFieldItem(..) | clean::VariantItem(..) => { @@ -1039,7 +1038,7 @@ impl DocFolder for Cache { Some(&self.stack[..self.stack.len() - 1])), false) } - clean::MethodItem(..) => { + clean::MethodItem(..) | clean::AssociatedConstItem(..) => { if self.parent_stack.is_empty() { ((None, None), false) } else { @@ -1064,7 +1063,7 @@ impl DocFolder for Cache { }; match parent { - (parent, Some(path)) if is_method || (!self.stripped_mod) => { + (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, @@ -1082,10 +1081,10 @@ impl DocFolder for Cache { }); } } - (Some(parent), None) if is_method => { + (Some(parent), None) if is_inherent_impl_item => { // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. - self.orphan_methods.push((parent, item.clone())); + self.orphan_impl_items.push((parent, item.clone())); } _ => {} } diff --git a/src/test/rustdoc/auxiliary/issue-36031.rs b/src/test/rustdoc/auxiliary/issue-36031.rs new file mode 100644 index 0000000000000..6b8a4b9f13703 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-36031.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(associated_consts)] + +pub trait Foo { + const FOO: usize; +} + +pub struct Bar; + +impl Bar { + pub const BAR: usize = 3; +} diff --git a/src/test/rustdoc/issue-36031.rs b/src/test/rustdoc/issue-36031.rs new file mode 100644 index 0000000000000..b025230f91820 --- /dev/null +++ b/src/test/rustdoc/issue-36031.rs @@ -0,0 +1,19 @@ +// 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. + +// aux-build:issue-36031.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate issue_36031; + +pub use issue_36031::Foo; From 01083baec26591a0b48752b3003fd73f4e07631e Mon Sep 17 00:00:00 2001 From: zjhmale Date: Mon, 29 Aug 2016 22:31:08 +0800 Subject: [PATCH 357/768] Update E0089 to new error format --- src/librustc_typeck/check/mod.rs | 20 ++++++++++++-------- src/test/compile-fail/E0089.rs | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fb24971c4251d..a846383309975 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4427,14 +4427,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // use inference variables instead of the provided types. *segment = None; } else if !(can_omit && types.len() == 0) && types.len() < required_len { - let qualifier = - if type_defs.len() != required_len { "at least " } else { "" }; - span_err!(self.tcx.sess, span, E0089, - "too few type parameters provided: \ - expected {}{}, found {}", - qualifier, - count(required_len), - count(types.len())); + let adjust = |len| if len > 1 { "parameters" } else { "parameter" }; + let required_param_str = adjust(required_len); + let actual_param_str = adjust(types.len()); + struct_span_err!(self.tcx.sess, span, E0089, + "too few type parameters provided: \ + expected {} {}, found {} {}", + count(required_len), + required_param_str, + count(types.len()), + actual_param_str) + .span_label(span, &format!("expected {} type {}", required_len, required_param_str)) + .emit(); } if !bindings.is_empty() { diff --git a/src/test/compile-fail/E0089.rs b/src/test/compile-fail/E0089.rs index 3b52f76bf09cc..9ce36523709e5 100644 --- a/src/test/compile-fail/E0089.rs +++ b/src/test/compile-fail/E0089.rs @@ -11,5 +11,7 @@ fn foo() {} fn main() { - foo::(); //~ ERROR E0089 + foo::(); +//~^ ERROR E0089 +//~| NOTE expected 2 type parameters } From 5928be1d9bcd96ce4dd7b328fe527683a4e1621f Mon Sep 17 00:00:00 2001 From: philipp Date: Mon, 29 Aug 2016 19:43:18 +0200 Subject: [PATCH 358/768] Changed issue number to 36105 --- src/libcore/iter/iterator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 48ea306ce5fd0..f530009585ece 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1678,7 +1678,7 @@ pub trait Iterator { /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); /// ``` #[inline] - #[unstable(feature = "iter_max_by", issue="1722")] + #[unstable(feature = "iter_max_by", issue="36105")] fn max_by(self, mut compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { @@ -1728,7 +1728,7 @@ pub trait Iterator { /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); /// ``` #[inline] - #[unstable(feature = "iter_min_by", issue="1722")] + #[unstable(feature = "iter_min_by", issue="36105")] fn min_by(self, mut compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { From 6ef8198406af9ba18787e0fd50ae2e25f78b7e4f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Aug 2016 18:22:02 -0400 Subject: [PATCH 359/768] Move `flock.rs` from librustdoc to librustc_data_structures. --- mk/crates.mk | 7 +++---- src/{librustdoc => librustc_data_structures}/flock.rs | 0 src/librustc_data_structures/lib.rs | 4 ++++ src/librustdoc/html/render.rs | 3 ++- src/librustdoc/lib.rs | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) rename src/{librustdoc => librustc_data_structures}/flock.rs (100%) diff --git a/mk/crates.mk b/mk/crates.mk index 5ff6d7a89dbe0..a915d07384f3c 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -112,7 +112,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \ rustc_const_math syntax_pos rustc_errors DEPS_rustc_back := std syntax flate log libc DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_mir -DEPS_rustc_data_structures := std log serialize +DEPS_rustc_data_structures := std log serialize libc DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \ rustc_trans rustc_privacy rustc_lint rustc_plugin \ @@ -137,9 +137,8 @@ DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \ rustc_const_eval rustc_errors -DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ - test rustc_lint rustc_const_eval syntax_pos - +DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts test \ + rustc_lint rustc_const_eval syntax_pos rustc_data_structures TOOL_DEPS_compiletest := test getopts log serialize TOOL_DEPS_rustdoc := rustdoc diff --git a/src/librustdoc/flock.rs b/src/librustc_data_structures/flock.rs similarity index 100% rename from src/librustdoc/flock.rs rename to src/librustc_data_structures/flock.rs diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 34c3961d5b4c1..4391123559f9b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -30,6 +30,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(fn_traits)] +#![feature(libc)] #![cfg_attr(test, feature(test))] @@ -37,6 +38,8 @@ extern crate core; #[macro_use] extern crate log; extern crate serialize as rustc_serialize; // used by deriving +#[cfg(unix)] +extern crate libc; pub mod bitvec; pub mod graph; @@ -51,6 +54,7 @@ pub mod fnv; pub mod tuple_slice; pub mod veccell; pub mod control_flow_graph; +pub mod flock; // See comments in src/librustc/lib.rs #[doc(hidden)] diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5cb5cc051870b..d3b9ca737b990 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -62,6 +62,7 @@ use rustc::middle::stability; use rustc::session::config::get_unstable_features_setting; use rustc::hir; use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use rustc_data_structures::flock; use clean::{self, Attributes, GetDefId}; use doctree; @@ -651,7 +652,7 @@ fn write_shared(cx: &Context, // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. try_err!(mkdir(&cx.dst), &cx.dst); - let _lock = ::flock::Lock::new(&cx.dst.join(".lock")); + let _lock = flock::Lock::new(&cx.dst.join(".lock")); // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 255e6b1e786df..0e685f063bd7b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -35,6 +35,7 @@ extern crate libc; extern crate rustc; extern crate rustc_const_eval; extern crate rustc_const_math; +extern crate rustc_data_structures; extern crate rustc_trans; extern crate rustc_driver; extern crate rustc_resolve; @@ -86,7 +87,6 @@ pub mod plugins; pub mod visit_ast; pub mod visit_lib; pub mod test; -mod flock; use clean::Attributes; From 206e7b6fc704c53b2a7174e8bec7b5f575d9bc93 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 15 Aug 2016 13:52:38 -0400 Subject: [PATCH 360/768] Add some features to flock. --- src/librustc_data_structures/flock.rs | 126 +++++++++++++++++++++----- src/librustdoc/html/render.rs | 2 +- 2 files changed, 106 insertions(+), 22 deletions(-) diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 41bcfdb7cb0f0..adfeaae847537 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -15,6 +15,7 @@ //! librustdoc, it is not production quality at all. #![allow(non_camel_case_types)] +use std::path::Path; pub use self::imp::Lock; @@ -41,6 +42,7 @@ mod imp { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 0; pub const F_WRLCK: libc::c_short = 1; pub const F_UNLCK: libc::c_short = 2; pub const F_SETLK: libc::c_int = 6; @@ -60,6 +62,7 @@ mod imp { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 1; pub const F_UNLCK: libc::c_short = 2; pub const F_WRLCK: libc::c_short = 3; pub const F_SETLK: libc::c_int = 12; @@ -84,6 +87,7 @@ mod imp { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 1; pub const F_UNLCK: libc::c_short = 2; pub const F_WRLCK: libc::c_short = 3; pub const F_SETLK: libc::c_int = 8; @@ -105,6 +109,7 @@ mod imp { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 1; pub const F_UNLCK: libc::c_short = 2; pub const F_WRLCK: libc::c_short = 3; pub const F_SETLK: libc::c_int = 8; @@ -124,6 +129,7 @@ mod imp { pub l_pid: libc::pid_t, } + pub const F_RDLCK: libc::c_short = 1; pub const F_WRLCK: libc::c_short = 2; pub const F_UNLCK: libc::c_short = 3; pub const F_SETLK: libc::c_int = 6; @@ -135,32 +141,53 @@ mod imp { } impl Lock { - pub fn new(p: &Path) -> Lock { + pub fn new(p: &Path, + wait: bool, + create: bool, + exclusive: bool) + -> io::Result { let os: &OsStr = p.as_ref(); let buf = CString::new(os.as_bytes()).unwrap(); + let open_flags = if create { + libc::O_RDWR | libc::O_CREAT + } else { + libc::O_RDWR + }; + let fd = unsafe { - libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT, + libc::open(buf.as_ptr(), open_flags, libc::S_IRWXU as libc::c_int) }; - assert!(fd > 0, "failed to open lockfile: {}", - io::Error::last_os_error()); + + if fd < 0 { + return Err(io::Error::last_os_error()); + } + + let lock_type = if exclusive { + os::F_WRLCK + } else { + os::F_RDLCK + }; + let flock = os::flock { l_start: 0, l_len: 0, l_pid: 0, l_whence: libc::SEEK_SET as libc::c_short, - l_type: os::F_WRLCK, + l_type: lock_type, l_sysid: 0, }; + let cmd = if wait { os::F_SETLKW } else { os::F_SETLK }; let ret = unsafe { - libc::fcntl(fd, os::F_SETLKW, &flock) + libc::fcntl(fd, cmd, &flock) }; if ret == -1 { let err = io::Error::last_os_error(); unsafe { libc::close(fd); } - panic!("could not lock `{}`: {}", p.display(), err); + Err(err) + } else { + Ok(Lock { fd: fd }) } - Lock { fd: fd } } } @@ -191,18 +218,28 @@ mod imp { use std::os::windows::raw::HANDLE; use std::path::Path; use std::fs::{File, OpenOptions}; + use std::os::raw::{c_ulong, c_ulonglong, c_int}; + use std::os::windows::fs::OpenOptionsExt; + + pub type DWORD = c_ulong; + pub type BOOL = c_int; + pub type ULONG_PTR = c_ulonglong; - type DWORD = u32; type LPOVERLAPPED = *mut OVERLAPPED; - type BOOL = i32; const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002; + const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001; + + pub const FILE_SHARE_DELETE: DWORD = 0x4; + pub const FILE_SHARE_READ: DWORD = 0x1; + pub const FILE_SHARE_WRITE: DWORD = 0x2; #[repr(C)] struct OVERLAPPED { - Internal: usize, - InternalHigh: usize, - Pointer: *mut u8, - hEvent: *mut u8, + Internal: ULONG_PTR, + InternalHigh: ULONG_PTR, + Offset: DWORD, + OffsetHigh: DWORD, + hEvent: HANDLE, } extern "system" { @@ -219,19 +256,66 @@ mod imp { } impl Lock { - pub fn new(p: &Path) -> Lock { - let f = OpenOptions::new().read(true).write(true).create(true) - .open(p).unwrap(); + pub fn new(p: &Path, + wait: bool, + create: bool, + exclusive: bool) + -> io::Result { + + let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; + + let f = { + let mut open_options = OpenOptions::new().read(true) + .share_mode(share_mode); + if create { + open_options.create(true); + } + + match open_options.open(p) { + Ok(file) => file, + Err(err) => return Err(err), + } + }; + let ret = unsafe { let mut overlapped: OVERLAPPED = mem::zeroed(); - LockFileEx(f.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0, + + let mut dwFlags = 0; + if !wait { + dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; + } + + if exclusive { + dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + } + + LockFileEx(f.as_raw_handle(), + dwFlags, + 0, + 0xFFFF_FFFF, + 0xFFFF_FFFF, &mut overlapped) }; if ret == 0 { - let err = io::Error::last_os_error(); - panic!("could not lock `{}`: {}", p.display(), err); + Err(io::Error::last_os_error()) + } else { + Ok(Lock { _file: f }) } - Lock { _file: f } } } + + // Note that we don't need a Drop impl on the Windows: The file is unlocked + // automatically when it's closed. +} + +impl imp::Lock { + pub fn panicking_new(p: &Path, + wait: bool, + create: bool, + exclusive: bool) + -> Lock { + Lock::new(p, wait, create, exclusive).unwrap_or_else(|err| { + panic!("could not lock `{}`: {}", p.display(), err); + }) + } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d3b9ca737b990..6d523ff381556 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -652,7 +652,7 @@ fn write_shared(cx: &Context, // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. try_err!(mkdir(&cx.dst), &cx.dst); - let _lock = flock::Lock::new(&cx.dst.join(".lock")); + let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true); // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. From 3e9bed92da499d7905232d47d54300134fca13b5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 11 Aug 2016 19:02:39 -0400 Subject: [PATCH 361/768] Implement copy-on-write scheme for managing the incremental compilation cache. --- src/librustc/hir/svh.rs | 15 + src/librustc/session/mod.rs | 93 +- src/librustc/util/fs.rs | 41 +- src/librustc_data_structures/flock.rs | 2 + src/librustc_driver/driver.rs | 20 +- src/librustc_incremental/lib.rs | 2 + src/librustc_incremental/persist/fs.rs | 895 ++++++++++++++++++ src/librustc_incremental/persist/hash.rs | 54 +- src/librustc_incremental/persist/load.rs | 29 +- src/librustc_incremental/persist/mod.rs | 5 +- src/librustc_incremental/persist/save.rs | 35 +- src/librustc_incremental/persist/util.rs | 95 -- .../persist/work_product.rs | 4 +- src/librustc_trans/back/write.rs | 22 +- 14 files changed, 1162 insertions(+), 150 deletions(-) create mode 100644 src/librustc_incremental/persist/fs.rs delete mode 100644 src/librustc_incremental/persist/util.rs diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs index d4e797c9f2d25..ae1f9d3028c2c 100644 --- a/src/librustc/hir/svh.rs +++ b/src/librustc/hir/svh.rs @@ -17,6 +17,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Svh { @@ -51,3 +52,17 @@ impl fmt::Display for Svh { f.pad(&self.to_string()) } } + +impl Encodable for Svh { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u64(self.as_u64().to_le()) + } +} + +impl Decodable for Svh { + fn decode(d: &mut D) -> Result { + d.read_u64() + .map(u64::from_le) + .map(Svh::new) + } +} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index c71253aee568f..02ee4571ab5d9 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -33,10 +33,11 @@ use syntax::feature_gate::AttributeType; use syntax_pos::{Span, MultiSpan}; use rustc_back::target::Target; +use rustc_data_structures::flock; use llvm; use std::path::{Path, PathBuf}; -use std::cell::{Cell, RefCell}; +use std::cell::{self, Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::CString; @@ -101,6 +102,8 @@ pub struct Session { /// macro name and defintion span in the source crate. pub imported_macro_spans: RefCell>, + incr_comp_session: RefCell, + next_node_id: Cell, } @@ -331,6 +334,70 @@ impl Session { &self.opts.search_paths, kind) } + + pub fn init_incr_comp_session(&self, + session_dir: PathBuf, + lock_file: flock::Lock) { + let mut incr_comp_session = self.incr_comp_session.borrow_mut(); + + if let IncrCompSession::NotInitialized = *incr_comp_session { } else { + bug!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session) + } + + *incr_comp_session = IncrCompSession::Active { + session_directory: session_dir, + lock_file: lock_file, + }; + } + + pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) { + let mut incr_comp_session = self.incr_comp_session.borrow_mut(); + + if let IncrCompSession::Active { .. } = *incr_comp_session { } else { + bug!("Trying to finalize IncrCompSession `{:?}`", *incr_comp_session) + } + + // Note: This will also drop the lock file, thus unlocking the directory + *incr_comp_session = IncrCompSession::Finalized { + session_directory: new_directory_path, + }; + } + + pub fn mark_incr_comp_session_as_invalid(&self) { + let mut incr_comp_session = self.incr_comp_session.borrow_mut(); + + if let IncrCompSession::Active { .. } = *incr_comp_session { } else { + bug!("Trying to invalidate IncrCompSession `{:?}`", *incr_comp_session) + } + + // Note: This will also drop the lock file, thus unlocking the directory + *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors; + } + + pub fn incr_comp_session_dir(&self) -> cell::Ref { + let incr_comp_session = self.incr_comp_session.borrow(); + cell::Ref::map(incr_comp_session, |incr_comp_session| { + match *incr_comp_session { + IncrCompSession::NotInitialized | + IncrCompSession::InvalidBecauseOfErrors => { + bug!("Trying to get session directory from IncrCompSession `{:?}`", + *incr_comp_session) + } + IncrCompSession::Active { ref session_directory, .. } | + IncrCompSession::Finalized { ref session_directory } => { + session_directory + } + } + }) + } + + pub fn incr_comp_session_dir_opt(&self) -> Option> { + if self.opts.incremental.is_some() { + Some(self.incr_comp_session_dir()) + } else { + None + } + } } pub fn build_session(sopts: config::Options, @@ -446,6 +513,7 @@ pub fn build_session_(sopts: config::Options, injected_panic_runtime: Cell::new(None), available_macros: RefCell::new(HashSet::new()), imported_macro_spans: RefCell::new(HashMap::new()), + incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), }; init_llvm(&sess); @@ -453,6 +521,29 @@ pub fn build_session_(sopts: config::Options, sess } +/// Holds data on the current incremental compilation session, if there is one. +#[derive(Debug)] +pub enum IncrCompSession { + // This is the state the session will be in until the incr. comp. dir is + // needed. + NotInitialized, + // This is the state during which the session directory is private and can + // be modified. + Active { + session_directory: PathBuf, + lock_file: flock::Lock, + }, + // This is the state after the session directory has been finalized. In this + // state, the contents of the directory must not be modified any more. + Finalized { + session_directory: PathBuf, + }, + // This is an error state that is reached when some compilation error has + // occurred. It indicates that the contents of the session directory must + // not be used, since they might be invalid. + InvalidBecauseOfErrors, +} + fn init_llvm(sess: &Session) { unsafe { // Before we touch LLVM, make sure that multithreading is enabled. diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index f4e1c06090e59..d7800ccaa5dd3 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -56,14 +56,49 @@ pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { } } +pub enum LinkOrCopy { + Link, + Copy +} + /// Copy `p` into `q`, preferring to use hard-linking if possible. If /// `q` already exists, it is removed first. -pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result<()> { +/// The result indicates which of the two operations has been performed. +pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result { let p = p.as_ref(); let q = q.as_ref(); if q.exists() { try!(fs::remove_file(&q)); } - fs::hard_link(p, q) - .or_else(|_| fs::copy(p, q).map(|_| ())) + + match fs::hard_link(p, q) { + Ok(()) => Ok(LinkOrCopy::Link), + Err(_) => { + match fs::copy(p, q) { + Ok(_) => Ok(LinkOrCopy::Copy), + Err(e) => Err(e) + } + } + } +} + +// Like std::fs::create_dir_all, except handles concurrent calls among multiple +// threads or processes. +pub fn create_dir_racy(path: &Path) -> io::Result<()> { + match fs::create_dir(path) { + Ok(()) => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(e) => return Err(e), + } + match path.parent() { + Some(p) => try!(create_dir_racy(p)), + None => return Err(io::Error::new(io::ErrorKind::Other, + "failed to create whole tree")), + } + match fs::create_dir(path) { + Ok(()) => Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), + Err(e) => Err(e), + } } diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index adfeaae847537..22f8d76399519 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -136,6 +136,7 @@ mod imp { pub const F_SETLKW: libc::c_int = 7; } + #[derive(Debug)] pub struct Lock { fd: libc::c_int, } @@ -251,6 +252,7 @@ mod imp { lpOverlapped: LPOVERLAPPED) -> BOOL; } + #[derive(Debug)] pub struct Lock { _file: File, } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 3f2f6c84da190..33d68523a0f94 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -88,7 +88,7 @@ pub fn compile_input(sess: &Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans, crate_name) = { + let (outputs, trans) = { let krate = match phase_1_parse_input(sess, cfg, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -213,11 +213,11 @@ pub fn compile_input(sess: &Session, // Discard interned strings as they are no longer required. token::clear_ident_interner(); - Ok((outputs, trans, crate_name.clone())) + Ok((outputs, trans)) })?? }; - let phase5_result = phase_5_run_llvm_passes(sess, &crate_name, &trans, &outputs); + let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); controller_entry_point!(after_llvm, sess, @@ -229,6 +229,10 @@ pub fn compile_input(sess: &Session, phase_6_link_output(sess, &trans, &outputs); + // Now that we won't touch anything in the incremental compilation directory + // any more, we can finalize it (which involves renaming it) + rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash); + controller_entry_point!(compilation_done, sess, CompileState::state_when_compilation_done(input, sess, outdir, output), @@ -1026,19 +1030,19 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(time_passes, "assert dep graph", - move || rustc_incremental::assert_dep_graph(tcx)); + || rustc_incremental::assert_dep_graph(tcx)); time(time_passes, "serialize dep graph", - move || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map)); - + || rustc_incremental::save_dep_graph(tcx, + &incremental_hashes_map, + translation.link.crate_hash)); translation } /// Run LLVM itself, producing a bitcode file, assembly file or object file /// as a side effect. pub fn phase_5_run_llvm_passes(sess: &Session, - crate_name: &str, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { if sess.opts.cg.no_integrated_as { @@ -1061,7 +1065,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, time(sess.time_passes(), "serialize work products", - move || rustc_incremental::save_work_products(sess, crate_name)); + move || rustc_incremental::save_work_products(sess)); if sess.err_count() > 0 { Err(sess.err_count()) diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index d31d97b22cf4f..511ba8ec19cc7 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,6 +22,7 @@ #![feature(question_mark)] #![feature(rustc_private)] #![feature(staged_api)] +#![feature(rand)] extern crate graphviz; extern crate rbml; @@ -45,3 +46,4 @@ pub use persist::save_dep_graph; pub use persist::save_trans_partition; pub use persist::save_work_products; pub use persist::in_incr_comp_dir; +pub use persist::finalize_session_directory; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs new file mode 100644 index 0000000000000..c2990c66020b5 --- /dev/null +++ b/src/librustc_incremental/persist/fs.rs @@ -0,0 +1,895 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +//! This module manages how the incremental compilation cache is represented in +//! the file system. +//! +//! Incremental compilation caches are managed according to a copy-on-write +//! strategy: Once a complete, consistent cache version is finalized, it is +//! never modified. Instead, when a subsequent compilation session is started, +//! the compiler will allocate a new version of the cache that starts out as +//! a copy of the previous version. Then only this new copy is modified and it +//! will not be visible to other processes until it is finalized. This ensures +//! that multiple compiler processes can be executed concurrently for the same +//! crate without interfering with each other or blocking each other. +//! +//! More concretely this is implemented via the following protocol: +//! +//! 1. For a newly started compilation session, the compiler allocates a +//! new `session` directory within the incremental compilation directory. +//! This session directory will have a unique name that ends with the suffix +//! "-working" and that contains a creation timestamp. +//! 2. Next, the compiler looks for the newest finalized session directory, +//! that is, a session directory from a previous compilation session that +//! has been marked as valid and consistent. A session directory is +//! considered finalized if the "-working" suffix in the directory name has +//! been replaced by the SVH of the crate. +//! 3. Once the compiler has found a valid, finalized session directory, it will +//! hard-link/copy its contents into the new "-working" directory. If all +//! goes well, it will have its own, private copy of the source directory and +//! subsequently not have to worry about synchronizing with other compiler +//! processes. +//! 4. Now the compiler can do its normal compilation process, which involves +//! reading and updating its private session directory. +//! 5. When compilation finishes without errors, the private session directory +//! will be in a state where it can be used as input for other compilation +//! sessions. That is, it will contain a dependency graph and cache artifacts +//! that are consistent with the state of the source code it was compiled +//! from, with no need to change them ever again. At this point, the compiler +//! finalizes and "publishes" its private session directory by renaming it +//! from "sess-{timestamp}-{random}-working" to "sess-{timestamp}-{SVH}". +//! 6. At this point the "old" session directory that we copied our data from +//! at the beginning of the session has become obsolete because we have just +//! published a more current version. Thus the compiler will delete it. +//! +//! ## Garbage Collection +//! +//! Naively following the above protocol might lead to old session directories +//! piling up if a compiler instance crashes for some reason before its able to +//! remove its private session directory. In order to avoid wasting disk space, +//! the compiler also does some garbage collection each time it is started in +//! incremental compilation mode. Specifically, it will scan the incremental +//! compilation directory for private session directories that are not in use +//! any more and will delete those. It will also delete any finalized session +//! directories for a given crate except for the most recent one. +//! +//! ## Synchronization +//! +//! There is some synchronization needed in order for the compiler to be able to +//! determine whether a given private session directory is not in used any more. +//! This is done by creating a lock file within each session directory and +//! locking it while the directory is still being used. Since file locks have +//! operating system support, we can rely on the lock being released if the +//! compiler process dies for some unexpected reason. Thus, when garbage +//! collecting private session directories, the collecting process can determine +//! whether the directory is still in use by trying to acquire a lock on the +//! file. If locking the file fails, the original process must still be alive. +//! If locking the file succeeds, we know that the owning process is not alive +//! any more and we can safely delete the directory. +//! There is still a small time window between the original process creating the +//! lock file and actually locking it. In order to minimize the chance that +//! another process tries to acquire the lock in just that instance, only +//! session directories that are older than a few seconds are considered for +//! garbage collection. +//! +//! Another case that has to be considered is what happens if one process +//! deletes a finalized session directory that another process is currently +//! trying to copy from. This case is also handled via the lock file. Before +//! a process starts copying a finalized session directory, it will acquire a +//! shared lock on the directory's lock file. Any garbage collecting process, +//! on the other hand, will acquire an exclusive lock on the lock file. +//! Thus, if a directory is being collected, any reader process will fail +//! acquiring the shared lock and will leave the directory alone. Conversely, +//! if a collecting process can't acquire the exclusive lock because the +//! directory is currently being read from, it will leave collecting that +//! directory to another process at a later point in time. +//! The exact same scheme is also used when reading the metadata hashes file +//! from an extern crate. When a crate is compiled, the hash values of its +//! metadata are stored in a file in its session directory. When the +//! compilation session of another crate imports the first crate's metadata, +//! it also has to read in the accompanying metadata hashes. It thus will access +//! the finalized session directory of all crates it links to and while doing +//! so, it will also place a read lock on that the respective session directory +//! so that it won't be deleted while the metadata hashes are loaded. +//! +//! ## Preconditions +//! +//! This system relies on two features being available in the file system in +//! order to work really well: file locking and hard linking. +//! If hard linking is not available (like on FAT) the data in the cache +//! actually has to be copied at the beginning of each session. +//! If file locking does not work reliably (like on NFS), some of the +//! synchronization will go haywire. +//! In both cases we recommend to locate the incremental compilation directory +//! on a file system that supports these things. +//! It might be a good idea though to try and detect whether we are on an +//! unsupported file system and emit a warning in that case. This is not yet +//! implemented. + +use rustc::hir::svh::Svh; +use rustc::middle::cstore::LOCAL_CRATE; +use rustc::session::Session; +use rustc::ty::TyCtxt; +use rustc::util::fs as fs_util; +use rustc_data_structures::flock; +use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap}; + +use std::ffi::OsString; +use std::fs as std_fs; +use std::io; +use std::mem; +use std::path::{Path, PathBuf}; +use std::time::{UNIX_EPOCH, SystemTime, Duration}; +use std::__rand::{thread_rng, Rng}; +use syntax::ast; + +const LOCK_FILE_NAME: &'static str = ".lock_file"; +const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin"; +const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin"; +const METADATA_HASHES_FILENAME: &'static str = "metadata.bin"; + +pub fn dep_graph_path(sess: &Session) -> PathBuf { + in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME) +} + +pub fn work_products_path(sess: &Session) -> PathBuf { + in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME) +} + +pub fn metadata_hash_export_path(sess: &Session) -> PathBuf { + in_incr_comp_dir_sess(sess, METADATA_HASHES_FILENAME) +} + +pub fn metadata_hash_import_path(import_session_dir: &Path) -> PathBuf { + import_session_dir.join(METADATA_HASHES_FILENAME) +} + +pub fn lock_file_path(session_dir: &Path) -> PathBuf { + session_dir.join(LOCK_FILE_NAME) +} + +pub fn in_incr_comp_dir_sess(sess: &Session, file_name: &str) -> PathBuf { + in_incr_comp_dir(&sess.incr_comp_session_dir(), file_name) +} + +pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBuf { + incr_comp_session_dir.join(file_name) +} + +/// Allocates the private session directory. The boolean in the Ok() result +/// indicates whether we should try loading a dep graph from the successfully +/// initialized directory, or not. +/// The post-condition of this fn is that we have a valid incremental +/// compilation session directory, if the result is `Ok`. A valid session +/// directory is one that contains a locked lock file. It may or may not contain +/// a dep-graph and work products from a previous session. +/// If the call fails, the fn may leave behind an invalid session directory. +/// The garbage collection will take care of it. +pub fn prepare_session_directory(tcx: TyCtxt) -> Result { + debug!("prepare_session_directory"); + + // {incr-comp-dir}/{crate-name-and-disambiguator} + let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE); + debug!("crate-dir: {}", crate_dir.display()); + + let mut source_directories_already_tried = FnvHashSet(); + + loop { + // Allocate a session directory of the form: + // + // {incr-comp-dir}/{crate-name-and-disambiguator}/sess-{timestamp}-{random}-working + // + // If this fails, return an error, don't retry + let session_dir = try!(alloc_session_dir(tcx.sess, &crate_dir)); + debug!("session-dir: {}", session_dir.display()); + + // Lock the newly created session directory. If this fails, return an + // error without retrying + let directory_lock = try!(lock_directory(tcx.sess, &session_dir)); + + let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info; + + // Find a suitable source directory to copy from. Ignore those that we + // have already tried before. + let source_directory = find_source_directory(&crate_dir, + &source_directories_already_tried); + + let source_directory = if let Some(dir) = source_directory { + dir + } else { + // There's nowhere to copy from, we're done + debug!("no source directory found. Continuing with empty session \ + directory."); + + tcx.sess.init_incr_comp_session(session_dir, directory_lock); + return Ok(false) + }; + + debug!("attempting to copy data from source: {}", + source_directory.display()); + + // Try copying over all files from the source directory + if copy_files(&session_dir, &source_directory, print_file_copy_stats).is_ok() { + debug!("successfully copied data from: {}", + source_directory.display()); + + tcx.sess.init_incr_comp_session(session_dir, directory_lock); + return Ok(true) + } else { + debug!("copying failed - trying next directory"); + + // Something went wrong while trying to copy/link files from the + // source directory. Try again with a different one. + source_directories_already_tried.insert(source_directory); + + // Try to remove the session directory we just allocated. We don't + // know if there's any garbage in it from the failed copy action. + if let Err(err) = std_fs::remove_dir_all(&session_dir) { + debug!("Failed to delete partly initialized session dir `{}`: {}", + session_dir.display(), + err); + } + mem::drop(directory_lock); + } + } +} + +/// This function finalizes and thus 'publishes' the session directory by +/// renaming it to `sess-{timestamp}-{svh}` and releasing the file lock. +/// If there have been compilation errors, however, this function will just +/// delete the presumably invalid session directory. +pub fn finalize_session_directory(sess: &Session, svh: Svh) { + if sess.opts.incremental.is_none() { + return; + } + + let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone(); + + if sess.has_errors() { + // If there have been any errors during compilation, we don't want to + // publish this session directory. Rather, we'll just delete it. + + debug!("finalize_session_directory() - invalidating session directory: {}", + incr_comp_session_dir.display()); + + if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) { + sess.warn(&format!("Error deleting incremental compilation \ + session directory `{}`: {}", + incr_comp_session_dir.display(), + err)); + } + sess.mark_incr_comp_session_as_invalid(); + } + + debug!("finalize_session_directory() - session directory: {}", + incr_comp_session_dir.display()); + + let old_sub_dir_name = incr_comp_session_dir.file_name() + .unwrap() + .to_string_lossy(); + assert_no_characters_lost(&old_sub_dir_name); + + // Keep the 'sess-{timestamp}' prefix, but replace the + // '-{random-number}-working' part with the SVH of the crate + let dash_indices: Vec<_> = old_sub_dir_name.match_indices("-") + .map(|(idx, _)| idx) + .collect(); + if dash_indices.len() != 3 { + bug!("Encountered incremental compilation session directory with \ + malformed name: {}", + incr_comp_session_dir.display()) + } + + // State: "sess-{timestamp}-" + let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[1] + 1]); + + // Append the svh + new_sub_dir_name.push_str(&svh.to_string()); + + // Create the full path + let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name); + debug!("finalize_session_directory() - new path: {}", new_path.display()); + + match std_fs::rename(&*incr_comp_session_dir, &new_path) { + Ok(_) => { + debug!("finalize_session_directory() - directory renamed successfully"); + + // This unlocks the directory + sess.finalize_incr_comp_session(new_path); + } + Err(e) => { + // Warn about the error. However, no need to abort compilation now. + sess.warn(&format!("Error finalizing incremental compilation \ + session directory `{}`: {}", + incr_comp_session_dir.display(), + e)); + + debug!("finalize_session_directory() - error, marking as invalid"); + // Drop the file lock, so we can garage collect + sess.mark_incr_comp_session_as_invalid(); + } + } + + let _ = garbage_collect_session_directories(sess); +} + +fn copy_files(target_dir: &Path, + source_dir: &Path, + print_stats_on_success: bool) + -> Result<(), ()> { + // We acquire a shared lock on the lock file of the directory, so that + // nobody deletes it out from under us while we are reading from it. + let lock_file_path = source_dir.join(LOCK_FILE_NAME); + let _lock = if let Ok(lock) = flock::Lock::new(&lock_file_path, + false, // don't wait, + false, // don't create + false) { // not exclusive + lock + } else { + // Could not acquire the lock, don't try to copy from here + return Err(()) + }; + + let source_dir_iterator = match source_dir.read_dir() { + Ok(it) => it, + Err(_) => return Err(()) + }; + + let mut files_linked = 0; + let mut files_copied = 0; + + for entry in source_dir_iterator { + match entry { + Ok(entry) => { + let file_name = entry.file_name(); + + if file_name.to_string_lossy() == LOCK_FILE_NAME { + continue; + } + + let target_file_path = target_dir.join(file_name); + let source_path = entry.path(); + + debug!("copying into session dir: {}", source_path.display()); + match fs_util::link_or_copy(source_path, target_file_path) { + Ok(fs_util::LinkOrCopy::Link) => { + files_linked += 1 + } + Ok(fs_util::LinkOrCopy::Copy) => { + files_copied += 1 + } + Err(_) => return Err(()) + } + } + Err(_) => { + return Err(()) + } + } + } + + if print_stats_on_success { + println!("incr. comp. session directory: {} files hard-linked", files_linked); + println!("incr. comp. session directory: {} files copied", files_copied); + } + + Ok(()) +} + +/// Create a directory with a path of the form: +/// {crate_dir}/sess-{timestamp}-{random-number}-working +fn alloc_session_dir(sess: &Session, + crate_dir: &Path) + -> Result { + let timestamp = timestamp_to_string(SystemTime::now()); + debug!("alloc_session_dir: timestamp = {}", timestamp); + let random_number = thread_rng().next_u32(); + debug!("alloc_session_dir: random_number = {}", random_number); + + let directory_name = format!("sess-{}-{:x}-working", timestamp, random_number); + debug!("alloc_session_dir: directory_name = {}", directory_name); + let directory_path = crate_dir.join(directory_name); + debug!("alloc_session_dir: directory_path = {}", directory_path.display()); + + match fs_util::create_dir_racy(&directory_path) { + Ok(()) => { + debug!("alloc_session_dir: directory created successfully"); + Ok(directory_path) + } + Err(err) => { + sess.err(&format!("incremental compilation: could not create \ + session directory `{}`: {}", + directory_path.display(), + err)); + Err(()) + } + } +} + +/// Allocate a the lock-file and lock it. +fn lock_directory(sess: &Session, + session_dir: &Path) + -> Result { + let lock_file_path = session_dir.join(LOCK_FILE_NAME); + debug!("lock_directory() - lock_file: {}", lock_file_path.display()); + + match flock::Lock::new(&lock_file_path, + false, // don't wait + true, // create the lock file + true) { // the lock should be exclusive + Ok(lock) => Ok(lock), + Err(err) => { + sess.err(&format!("incremental compilation: could not create \ + session directory lock file: {}", err)); + Err(()) + } + } +} + +/// Find the most recent published session directory that is not in the +/// ignore-list. +fn find_source_directory(crate_dir: &Path, + source_directories_already_tried: &FnvHashSet) + -> Option { + let iter = crate_dir.read_dir() + .unwrap() // FIXME + .filter_map(|e| e.ok().map(|e| e.path())); + + find_source_directory_in_iter(iter, source_directories_already_tried) +} + +fn find_source_directory_in_iter(iter: I, + source_directories_already_tried: &FnvHashSet) + -> Option + where I: Iterator +{ + let mut best_candidate = (UNIX_EPOCH, None); + + for session_dir in iter { + if source_directories_already_tried.contains(&session_dir) || + !is_finalized(&session_dir.to_string_lossy()) { + continue + } + + let timestamp = { + let directory_name = session_dir.file_name().unwrap().to_string_lossy(); + assert_no_characters_lost(&directory_name); + + extract_timestamp_from_session_dir(&directory_name) + .unwrap_or_else(|_| { + bug!("unexpected incr-comp session dir: {}", session_dir.display()) + }) + }; + + if timestamp > best_candidate.0 { + best_candidate = (timestamp, Some(session_dir)); + } + } + + best_candidate.1 +} + +fn is_finalized(directory_name: &str) -> bool { + !directory_name.ends_with("-working") +} + +fn is_session_directory(directory_name: &str) -> bool { + directory_name.starts_with("sess-") +} + +fn extract_timestamp_from_session_dir(directory_name: &str) + -> Result { + if !is_session_directory(directory_name) { + return Err(()) + } + + let dash_indices: Vec<_> = directory_name.match_indices("-") + .map(|(idx, _)| idx) + .collect(); + if dash_indices.len() < 2 { + return Err(()) + } + + string_to_timestamp(&directory_name[dash_indices[0]+1 .. dash_indices[1]]) +} + +fn timestamp_to_string(timestamp: SystemTime) -> String { + let duration = timestamp.duration_since(UNIX_EPOCH).unwrap(); + let nanos = duration.as_secs() * 1_000_000_000 + + (duration.subsec_nanos() as u64); + format!("{:x}", nanos) +} + +fn string_to_timestamp(s: &str) -> Result { + let nanos_since_unix_epoch = u64::from_str_radix(s, 16); + + if nanos_since_unix_epoch.is_err() { + return Err(()) + } + + let nanos_since_unix_epoch = nanos_since_unix_epoch.unwrap(); + + let duration = Duration::new(nanos_since_unix_epoch / 1_000_000_000, + (nanos_since_unix_epoch % 1_000_000_000) as u32); + Ok(UNIX_EPOCH + duration) +} + +fn crate_path_tcx(tcx: TyCtxt, cnum: ast::CrateNum) -> PathBuf { + crate_path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum)) +} + +/// Finds the session directory containing the correct metadata hashes file for +/// the given crate. In order to do that it has to compute the crate directory +/// of the given crate, and in there, look for the session directory with the +/// correct SVH in it. +/// Note that we have to match on the exact SVH here, not just the +/// crate's (name, disambiguator) pair. The metadata hashes are only valid for +/// the exact version of the binary we are reading from now (i.e. the hashes +/// are part of the dependency graph of a specific compilation session). +pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: ast::CrateNum) -> Option { + let crate_directory = crate_path_tcx(tcx, cnum); + + if !crate_directory.exists() { + return None + } + + let dir_entries = match crate_directory.read_dir() { + Ok(dir_entries) => dir_entries, + Err(e) => { + tcx.sess + .err(&format!("incremental compilation: Could not read crate directory `{}`: {}", + crate_directory.display(), e)); + return None + } + }; + + let target_svh = tcx.sess.cstore.crate_hash(cnum).to_string(); + + let sub_dir = find_metadata_hashes_iter(&target_svh, dir_entries.filter_map(|e| { + e.ok().map(|e| e.file_name().to_string_lossy().into_owned()) + })); + + sub_dir.map(|sub_dir_name| crate_directory.join(&sub_dir_name)) +} + +fn find_metadata_hashes_iter<'a, I>(target_svh: &str, iter: I) -> Option + where I: Iterator +{ + for sub_dir_name in iter { + if !is_session_directory(&sub_dir_name) || !is_finalized(&sub_dir_name) { + // This is not a usable session directory + continue + } + + let is_match = if let Some(last_dash_pos) = sub_dir_name.rfind("-") { + let candidate_svh = &sub_dir_name[last_dash_pos + 1 .. ]; + target_svh == candidate_svh + } else { + // some kind of invalid directory name + continue + }; + + if is_match { + return Some(OsString::from(sub_dir_name)) + } + } + + None +} + +fn crate_path(sess: &Session, + crate_name: &str, + crate_disambiguator: &str) + -> PathBuf { + use std::hash::{SipHasher, Hasher, Hash}; + + let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); + + // The full crate disambiguator is really long. A hash of it should be + // sufficient. + let mut hasher = SipHasher::new(); + crate_disambiguator.hash(&mut hasher); + + let crate_name = format!("{}-{:x}", crate_name, hasher.finish()); + incr_dir.join(crate_name) +} + +fn assert_no_characters_lost(s: &str) { + if s.contains('\u{FFFD}') { + bug!("Could not losslessly convert '{}'.", s) + } +} + +pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { + debug!("garbage_collect_session_directories() - begin"); + + let session_directory = sess.incr_comp_session_dir(); + debug!("garbage_collect_session_directories() - session directory: {}", + session_directory.display()); + + let crate_directory = session_directory.parent().unwrap(); + debug!("garbage_collect_session_directories() - crate directory: {}", + crate_directory.display()); + + let mut deletion_candidates = vec![]; + let mut definitely_delete = vec![]; + + for dir_entry in try!(crate_directory.read_dir()) { + let dir_entry = match dir_entry { + Ok(dir_entry) => dir_entry, + _ => { + // Ignore any errors + continue + } + }; + + let directory_name = dir_entry.file_name(); + let directory_name = directory_name.to_string_lossy(); + + if !is_session_directory(&directory_name) { + // This is something we don't know, leave it alone... + continue + } + assert_no_characters_lost(&directory_name); + + if let Ok(file_type) = dir_entry.file_type() { + if !file_type.is_dir() { + // This is not a directory, skip it + continue + } + } else { + // Some error occurred while trying to determine the file type, + // skip it + continue + } + + debug!("garbage_collect_session_directories() - inspecting: {}", + directory_name); + + match extract_timestamp_from_session_dir(&directory_name) { + Ok(timestamp) => { + let lock_file_path = crate_directory.join(&*directory_name) + .join(LOCK_FILE_NAME); + + if !is_finalized(&directory_name) { + let ten_seconds = Duration::from_secs(10); + + // When cleaning out "-working" session directories, i.e. + // session directories that might still be in use by another + // compiler instance, we only look a directories that are + // at least ten seconds old. This is supposed to reduce the + // chance of deleting a directory in the time window where + // the process has allocated the directory but has not yet + // acquired the file-lock on it. + if timestamp < SystemTime::now() - ten_seconds { + debug!("garbage_collect_session_directories() - \ + attempting to collect"); + + // Try to acquire the directory lock. If we can't, it + // means that the owning process is still alive and we + // leave this directory alone. + match flock::Lock::new(&lock_file_path, + false, // don't wait + false, // don't create the lock-file + true) { // get an exclusive lock + Ok(lock) => { + debug!("garbage_collect_session_directories() - \ + successfully acquired lock"); + + // Note that we are holding on to the lock + definitely_delete.push((dir_entry.path(), + Some(lock))); + } + Err(_) => { + debug!("garbage_collect_session_directories() - \ + not collecting, still in use"); + } + } + } else { + debug!("garbage_collect_session_directories() - \ + private session directory too new"); + } + } else { + match flock::Lock::new(&lock_file_path, + false, // don't wait + false, // don't create the lock-file + true) { // get an exclusive lock + Ok(lock) => { + debug!("garbage_collect_session_directories() - \ + successfully acquired lock"); + debug!("garbage_collect_session_directories() - adding \ + deletion candidate: {}", directory_name); + + // Note that we are holding on to the lock + deletion_candidates.push((timestamp, + dir_entry.path(), + Some(lock))); + } + Err(_) => { + debug!("garbage_collect_session_directories() - \ + not collecting, still in use"); + } + } + } + } + Err(_) => { + // Malformed timestamp in directory, delete it + definitely_delete.push((dir_entry.path(), None)); + + debug!("garbage_collect_session_directories() - encountered \ + malformed session directory: {}", directory_name); + } + } + } + + // Delete all but the most recent of the candidates + for (path, lock) in all_except_most_recent(deletion_candidates) { + debug!("garbage_collect_session_directories() - deleting `{}`", + path.display()); + + if let Err(err) = std_fs::remove_dir_all(&path) { + sess.warn(&format!("Failed to garbage collect finalized incremental \ + compilation session directory `{}`: {}", + path.display(), + err)); + } + + // Let's make it explicit that the file lock is released at this point, + // or rather, that we held on to it until here + mem::drop(lock); + } + + for (path, lock) in definitely_delete { + debug!("garbage_collect_session_directories() - deleting `{}`", + path.display()); + + if let Err(err) = std_fs::remove_dir_all(&path) { + sess.warn(&format!("Failed to garbage collect incremental \ + compilation session directory `{}`: {}", + path.display(), + err)); + } + + // Let's make it explicit that the file lock is released at this point, + // or rather, that we held on to it until here + mem::drop(lock); + } + + Ok(()) +} + +fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option)>) + -> FnvHashMap> { + let most_recent = deletion_candidates.iter() + .map(|&(timestamp, _, _)| timestamp) + .max(); + + if let Some(most_recent) = most_recent { + deletion_candidates.into_iter() + .filter(|&(timestamp, _, _)| timestamp != most_recent) + .map(|(_, path, lock)| (path, lock)) + .collect() + } else { + FnvHashMap() + } +} + +#[test] +fn test_all_except_most_recent() { + assert_eq!(all_except_most_recent( + vec![ + (UNIX_EPOCH + Duration::new(4, 0), PathBuf::from("4"), None), + (UNIX_EPOCH + Duration::new(1, 0), PathBuf::from("1"), None), + (UNIX_EPOCH + Duration::new(5, 0), PathBuf::from("5"), None), + (UNIX_EPOCH + Duration::new(3, 0), PathBuf::from("3"), None), + (UNIX_EPOCH + Duration::new(2, 0), PathBuf::from("2"), None), + ]).keys().cloned().collect::>(), + vec![ + PathBuf::from("1"), + PathBuf::from("2"), + PathBuf::from("3"), + PathBuf::from("4"), + ].into_iter().collect::>() + ); + + assert_eq!(all_except_most_recent( + vec![ + ]).keys().cloned().collect::>(), + FnvHashSet() + ); +} + +#[test] +fn test_timestamp_serialization() { + for i in 0 .. 1_000u64 { + let time = UNIX_EPOCH + Duration::new(i * 3_434_578, (i as u32) * 239_676); + let s = timestamp_to_string(time); + assert_eq!(time, string_to_timestamp(&s).unwrap()); + } +} + +#[test] +fn test_find_source_directory_in_iter() { + let already_visited = FnvHashSet(); + + // Find newest + assert_eq!(find_source_directory_in_iter( + vec![PathBuf::from("./sess-3234-0000"), + PathBuf::from("./sess-2234-0000"), + PathBuf::from("./sess-1234-0000")].into_iter(), &already_visited), + Some(PathBuf::from("./sess-3234-0000"))); + + // Filter out "-working" + assert_eq!(find_source_directory_in_iter( + vec![PathBuf::from("./sess-3234-0000-working"), + PathBuf::from("./sess-2234-0000"), + PathBuf::from("./sess-1234-0000")].into_iter(), &already_visited), + Some(PathBuf::from("./sess-2234-0000"))); + + // Handle empty + assert_eq!(find_source_directory_in_iter(vec![].into_iter(), &already_visited), + None); + + // Handle only working + assert_eq!(find_source_directory_in_iter( + vec![PathBuf::from("./sess-3234-0000-working"), + PathBuf::from("./sess-2234-0000-working"), + PathBuf::from("./sess-1234-0000-working")].into_iter(), &already_visited), + None); +} + +#[test] +fn test_find_metadata_hashes_iter() +{ + assert_eq!(find_metadata_hashes_iter("testsvh2", + vec![ + String::from("sess-timestamp1-testsvh1"), + String::from("sess-timestamp2-testsvh2"), + String::from("sess-timestamp3-testsvh3"), + ].into_iter()), + Some(OsString::from("sess-timestamp2-testsvh2")) + ); + + assert_eq!(find_metadata_hashes_iter("testsvh2", + vec![ + String::from("sess-timestamp1-testsvh1"), + String::from("sess-timestamp2-testsvh2"), + String::from("invalid-name"), + ].into_iter()), + Some(OsString::from("sess-timestamp2-testsvh2")) + ); + + assert_eq!(find_metadata_hashes_iter("testsvh2", + vec![ + String::from("sess-timestamp1-testsvh1"), + String::from("sess-timestamp2-testsvh2-working"), + String::from("sess-timestamp3-testsvh3"), + ].into_iter()), + None + ); + + assert_eq!(find_metadata_hashes_iter("testsvh1", + vec![ + String::from("sess-timestamp1-random1-working"), + String::from("sess-timestamp2-random2-working"), + String::from("sess-timestamp3-random3-working"), + ].into_iter()), + None + ); + + assert_eq!(find_metadata_hashes_iter("testsvh2", + vec![ + String::from("timestamp1-testsvh2"), + String::from("timestamp2-testsvh2"), + String::from("timestamp3-testsvh2"), + ].into_iter()), + None + ); +} diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 5d01f88060282..95bee669d3256 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -15,6 +15,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::flock; use rustc_serialize::Decodable; use std::io::{ErrorKind, Read}; use std::fs::File; @@ -22,7 +23,7 @@ use syntax::ast; use IncrementalHashesMap; use super::data::*; -use super::util::*; +use super::fs::*; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -128,19 +129,43 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { debug!("load_data: svh={}", svh); assert!(old.is_none(), "loaded data for crate {:?} twice", cnum); - if let Some(path) = metadata_hash_path(self.tcx, cnum) { - debug!("load_data: path={:?}", path); + if let Some(session_dir) = find_metadata_hashes_for(self.tcx, cnum) { + debug!("load_data: session_dir={:?}", session_dir); + + // Lock the directory we'll be reading the hashes from. + let lock_file_path = lock_file_path(&session_dir); + let _lock = match flock::Lock::new(&lock_file_path, + false, // don't wait + false, // don't create the lock-file + false) { // shared lock + Ok(lock) => lock, + Err(err) => { + debug!("Could not acquire lock on `{}` while trying to \ + load metadata hashes: {}", + lock_file_path.display(), + err); + + // Could not acquire the lock. The directory is probably in + // in the process of being deleted. It's OK to just exit + // here. It's the same scenario as if the file had not + // existed in the first place. + return + } + }; + + let hashes_file_path = metadata_hash_import_path(&session_dir); + let mut data = vec![]; match - File::open(&path) - .and_then(|mut file| file.read_to_end(&mut data)) + File::open(&hashes_file_path) + .and_then(|mut file| file.read_to_end(&mut data)) { Ok(_) => { - match self.load_from_data(cnum, &data) { + match self.load_from_data(cnum, &data, svh) { Ok(()) => { } Err(err) => { bug!("decoding error in dep-graph from `{}`: {}", - path.display(), err); + &hashes_file_path.display(), err); } } } @@ -152,7 +177,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { _ => { self.tcx.sess.err( &format!("could not load dep information from `{}`: {}", - path.display(), err)); + hashes_file_path.display(), err)); return; } } @@ -161,11 +186,22 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> { + fn load_from_data(&mut self, + cnum: ast::CrateNum, + data: &[u8], + expected_svh: Svh) -> Result<(), Error> { debug!("load_from_data(cnum={})", cnum); // Load up the hashes for the def-ids from this crate. let mut decoder = Decoder::new(data, 0); + let svh_in_hashes_file = try!(Svh::decode(&mut decoder)); + + if svh_in_hashes_file != expected_svh { + // We should not be able to get here. If we do, then + // `fs::find_metadata_hashes_for()` has messed up. + bug!("mismatch between SVH in crate and SVH in incr. comp. hashes") + } + let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder)); for serialized_hash in serialized_hashes.hashes { // the hashes are stored with just a def-index, which is diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 75448d199f73e..cc4966eadae91 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -27,7 +27,7 @@ use super::data::*; use super::directory::*; use super::dirty_clean; use super::hash::*; -use super::util::*; +use super::fs::*; pub type DirtyNodes = FnvHashSet>; @@ -45,19 +45,38 @@ pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } + match prepare_session_directory(tcx) { + Ok(true) => { + // We successfully allocated a session directory and there is + // something in it to load, so continue + } + Ok(false) => { + // We successfully allocated a session directory, but there is no + // dep-graph data in it to load (because this is the first + // compilation session with this incr. comp. dir.) + return + } + Err(()) => { + // Something went wrong while trying to allocate the session + // directory. Don't try to use it any further. + let _ = garbage_collect_session_directories(tcx.sess); + return + } + } + let _ignore = tcx.dep_graph.in_ignore(); load_dep_graph_if_exists(tcx, incremental_hashes_map); } fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap) { - let dep_graph_path = dep_graph_path(tcx).unwrap(); + let dep_graph_path = dep_graph_path(tcx.sess); let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) { Some(p) => p, None => return // no file }; - let work_products_path = tcx_work_products_path(tcx).unwrap(); + let work_products_path = work_products_path(tcx.sess); let work_products_data = match load_data(tcx.sess, &work_products_path) { Some(p) => p, None => return // no file @@ -258,7 +277,7 @@ fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .saved_files .iter() .all(|&(_, ref file_name)| { - let path = in_incr_comp_dir(tcx.sess, &file_name).unwrap(); + let path = in_incr_comp_dir_sess(tcx.sess, &file_name); path.exists() }); if all_files_exist { @@ -276,7 +295,7 @@ fn delete_dirty_work_product(tcx: TyCtxt, swp: SerializedWorkProduct) { debug!("delete_dirty_work_product({:?})", swp); for &(_, ref file_name) in &swp.work_product.saved_files { - let path = in_incr_comp_dir(tcx.sess, file_name).unwrap(); + let path = in_incr_comp_dir_sess(tcx.sess, file_name); match fs::remove_file(&path) { Ok(()) => { } Err(err) => { diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 4a042497e0441..ba0f71971bb45 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -15,15 +15,16 @@ mod data; mod directory; mod dirty_clean; +mod fs; mod hash; mod load; mod preds; mod save; -mod util; mod work_product; +pub use self::fs::finalize_session_directory; +pub use self::fs::in_incr_comp_dir; pub use self::load::load_dep_graph; pub use self::save::save_dep_graph; pub use self::save::save_work_products; pub use self::work_product::save_trans_partition; -pub use self::util::in_incr_comp_dir; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 74ee876d0bbc5..d31252be5e857 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -11,7 +11,7 @@ use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; -use rustc::middle::cstore::LOCAL_CRATE; +use rustc::hir::svh::Svh; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; @@ -26,10 +26,11 @@ use super::data::*; use super::directory::*; use super::hash::*; use super::preds::*; -use super::util::*; +use super::fs::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - incremental_hashes_map: &IncrementalHashesMap) { + incremental_hashes_map: &IncrementalHashesMap, + svh: Svh) { debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); let sess = tcx.sess; @@ -41,31 +42,31 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let query = tcx.dep_graph.query(); let preds = Predecessors::new(&query, &mut hcx); save_in(sess, - dep_graph_path(tcx), + dep_graph_path(sess), |e| encode_dep_graph(&preds, &mut builder, e)); save_in(sess, - metadata_hash_path(tcx, LOCAL_CRATE), - |e| encode_metadata_hashes(tcx, &preds, &mut builder, e)); + metadata_hash_export_path(sess), + |e| encode_metadata_hashes(tcx, svh, &preds, &mut builder, e)); } -pub fn save_work_products(sess: &Session, local_crate_name: &str) { +pub fn save_work_products(sess: &Session) { + if sess.opts.incremental.is_none() { + return; + } + debug!("save_work_products()"); let _ignore = sess.dep_graph.in_ignore(); - let path = sess_work_products_path(sess, local_crate_name); + let path = work_products_path(sess); save_in(sess, path, |e| encode_work_products(sess, e)); } -fn save_in(sess: &Session, opt_path_buf: Option, encode: F) +fn save_in(sess: &Session, path_buf: PathBuf, encode: F) where F: FnOnce(&mut Encoder) -> io::Result<()> { - let path_buf = match opt_path_buf { - Some(p) => p, - None => return, - }; - - // FIXME(#32754) lock file? - // delete the old dep-graph, if any + // Note: It's important that we actually delete the old file and not just + // truncate and overwrite it, since it might be a shared hard-link, the + // underlying data of which we don't want to modify if path_buf.exists() { match fs::remove_file(&path_buf) { Ok(()) => {} @@ -155,6 +156,7 @@ pub fn encode_dep_graph(preds: &Predecessors, } pub fn encode_metadata_hashes(tcx: TyCtxt, + svh: Svh, preds: &Predecessors, builder: &mut DefIdDirectoryBuilder, encoder: &mut Encoder) @@ -220,6 +222,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, } // Encode everything. + try!(svh.encode(encoder)); try!(serialized_hashes.encode(encoder)); Ok(()) diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs deleted file mode 100644 index f1e81fdb266b9..0000000000000 --- a/src/librustc_incremental/persist/util.rs +++ /dev/null @@ -1,95 +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. - -use rustc::middle::cstore::LOCAL_CRATE; -use rustc::session::Session; -use rustc::ty::TyCtxt; - -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use syntax::ast; - -pub fn dep_graph_path(tcx: TyCtxt) -> Option { - tcx_path(tcx, LOCAL_CRATE, "local") -} - -pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option { - tcx_path(tcx, cnum, "metadata") -} - -pub fn tcx_work_products_path(tcx: TyCtxt) -> Option { - let crate_name = tcx.crate_name(LOCAL_CRATE); - sess_work_products_path(tcx.sess, &crate_name) -} - -pub fn sess_work_products_path(sess: &Session, - local_crate_name: &str) - -> Option { - let crate_disambiguator = sess.local_crate_disambiguator(); - path(sess, local_crate_name, &crate_disambiguator, "work-products") -} - -pub fn in_incr_comp_dir(sess: &Session, file_name: &str) -> Option { - sess.opts.incremental.as_ref().map(|incr_dir| incr_dir.join(file_name)) -} - -fn tcx_path(tcx: TyCtxt, - cnum: ast::CrateNum, - middle: &str) - -> Option { - path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum), middle) -} - -fn path(sess: &Session, - crate_name: &str, - crate_disambiguator: &str, - middle: &str) - -> Option { - // For now, just save/load dep-graph from - // directory/dep_graph.rbml - sess.opts.incremental.as_ref().and_then(|incr_dir| { - match create_dir_racy(&incr_dir) { - Ok(()) => {} - Err(err) => { - sess.err( - &format!("could not create the directory `{}`: {}", - incr_dir.display(), err)); - return None; - } - } - - let file_name = format!("{}-{}.{}.bin", crate_name, crate_disambiguator, middle); - - Some(incr_dir.join(file_name)) - }) -} - -// Like std::fs::create_dir_all, except handles concurrent calls among multiple -// threads or processes. -fn create_dir_racy(path: &Path) -> io::Result<()> { - match fs::create_dir(path) { - Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(e) => return Err(e), - } - match path.parent() { - Some(p) => try!(create_dir_racy(p)), - None => return Err(io::Error::new(io::ErrorKind::Other, - "failed to create whole tree")), - } - match fs::create_dir(path) { - Ok(()) => Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), - Err(e) => Err(e), - } -} - diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index c106ea8f26269..a9ebd27ce9928 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -10,7 +10,7 @@ //! This module contains files for saving intermediate work-products. -use persist::util::*; +use persist::fs::*; use rustc::dep_graph::{WorkProduct, WorkProductId}; use rustc::session::Session; use rustc::session::config::OutputType; @@ -35,7 +35,7 @@ pub fn save_trans_partition(sess: &Session, files.iter() .map(|&(kind, ref path)| { let file_name = format!("cgu-{}.{}", cgu_name, kind.extension()); - let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap(); + let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); match link_or_copy(path, &path_in_incr_dir) { Ok(_) => Some((kind, file_name)), Err(err) => { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 4b9c29d3d7db3..081b4431bd7b8 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,7 +10,7 @@ use back::lto; use back::link::{get_linker, remove}; -use rustc_incremental::save_trans_partition; +use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; use session::Session; use session::config::{self, OutputType}; @@ -328,8 +328,9 @@ struct CodegenContext<'a> { remark: Passes, // Worker thread number worker: usize, - // Directory where incremental data is stored (if any) - incremental: Option, + // The incremental compilation session directory, or None if we are not + // compiling incrementally + incr_comp_session_dir: Option } impl<'a> CodegenContext<'a> { @@ -340,7 +341,7 @@ impl<'a> CodegenContext<'a> { plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), worker: 0, - incremental: sess.opts.incremental.clone(), + incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()) } } } @@ -962,17 +963,20 @@ fn execute_work_item(cgcx: &CodegenContext, work_item.output_names); } ModuleSource::Preexisting(wp) => { - let incremental = cgcx.incremental.as_ref().unwrap(); + let incr_comp_session_dir = cgcx.incr_comp_session_dir + .as_ref() + .unwrap(); let name = &work_item.mtrans.name; for (kind, saved_file) in wp.saved_files { let obj_out = work_item.output_names.temp_path(kind, Some(name)); - let source_file = incremental.join(&saved_file); + let source_file = in_incr_comp_dir(&incr_comp_session_dir, + &saved_file); debug!("copying pre-existing module `{}` from {:?} to {}", work_item.mtrans.name, source_file, obj_out.display()); match link_or_copy(&source_file, &obj_out) { - Ok(()) => { } + Ok(_) => { } Err(err) => { cgcx.handler.err(&format!("unable to copy {} to {}: {}", source_file.display(), @@ -1018,7 +1022,7 @@ fn run_work_multithreaded(sess: &Session, let mut tx = Some(tx); futures.push(rx); - let incremental = sess.opts.incremental.clone(); + let incr_comp_session_dir = sess.incr_comp_session_dir_opt().map(|r| r.clone()); thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || { let diag_handler = Handler::with_emitter(true, false, box diag_emitter); @@ -1031,7 +1035,7 @@ fn run_work_multithreaded(sess: &Session, plugin_passes: plugin_passes, remark: remark, worker: i, - incremental: incremental, + incr_comp_session_dir: incr_comp_session_dir }; loop { From 794fd315adb9bdfaacb28fa5571b3a63b954b010 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 22 Aug 2016 13:01:46 -0400 Subject: [PATCH 362/768] incr.comp.: Move lock files out of directory being locked --- src/librustc/session/mod.rs | 24 +- src/librustc_data_structures/flock.rs | 53 +-- src/librustc_data_structures/lib.rs | 2 +- src/librustc_incremental/persist/fs.rs | 409 ++++++++++++++--------- src/librustc_incremental/persist/load.rs | 1 - 5 files changed, 302 insertions(+), 187 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 02ee4571ab5d9..338c656379959 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -366,25 +366,31 @@ impl Session { pub fn mark_incr_comp_session_as_invalid(&self) { let mut incr_comp_session = self.incr_comp_session.borrow_mut(); - if let IncrCompSession::Active { .. } = *incr_comp_session { } else { - bug!("Trying to invalidate IncrCompSession `{:?}`", *incr_comp_session) - } + let session_directory = match *incr_comp_session { + IncrCompSession::Active { ref session_directory, .. } => { + session_directory.clone() + } + _ => bug!("Trying to invalidate IncrCompSession `{:?}`", + *incr_comp_session), + }; // Note: This will also drop the lock file, thus unlocking the directory - *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors; + *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { + session_directory: session_directory + }; } pub fn incr_comp_session_dir(&self) -> cell::Ref { let incr_comp_session = self.incr_comp_session.borrow(); cell::Ref::map(incr_comp_session, |incr_comp_session| { match *incr_comp_session { - IncrCompSession::NotInitialized | - IncrCompSession::InvalidBecauseOfErrors => { + IncrCompSession::NotInitialized => { bug!("Trying to get session directory from IncrCompSession `{:?}`", *incr_comp_session) } IncrCompSession::Active { ref session_directory, .. } | - IncrCompSession::Finalized { ref session_directory } => { + IncrCompSession::Finalized { ref session_directory } | + IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => { session_directory } } @@ -541,7 +547,9 @@ pub enum IncrCompSession { // This is an error state that is reached when some compilation error has // occurred. It indicates that the contents of the session directory must // not be used, since they might be invalid. - InvalidBecauseOfErrors, + InvalidBecauseOfErrors { + session_directory: PathBuf, + } } fn init_llvm(sess: &Session) { diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 22f8d76399519..4a184d3174dff 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -220,19 +220,18 @@ mod imp { use std::path::Path; use std::fs::{File, OpenOptions}; use std::os::raw::{c_ulong, c_ulonglong, c_int}; - use std::os::windows::fs::OpenOptionsExt; - pub type DWORD = c_ulong; - pub type BOOL = c_int; - pub type ULONG_PTR = c_ulonglong; + type DWORD = c_ulong; + type BOOL = c_int; + type ULONG_PTR = c_ulonglong; type LPOVERLAPPED = *mut OVERLAPPED; const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002; const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001; - pub const FILE_SHARE_DELETE: DWORD = 0x4; - pub const FILE_SHARE_READ: DWORD = 0x1; - pub const FILE_SHARE_WRITE: DWORD = 0x2; + const FILE_SHARE_DELETE: DWORD = 0x4; + const FILE_SHARE_READ: DWORD = 0x1; + const FILE_SHARE_WRITE: DWORD = 0x2; #[repr(C)] struct OVERLAPPED { @@ -263,19 +262,30 @@ mod imp { create: bool, exclusive: bool) -> io::Result { + assert!(p.parent().unwrap().exists(), + "Parent directory of lock-file must exist: {}", + p.display()); let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; - let f = { - let mut open_options = OpenOptions::new().read(true) - .share_mode(share_mode); - if create { - open_options.create(true); - } + let mut open_options = OpenOptions::new(); + open_options.read(true) + .share_mode(share_mode); + + if create { + open_options.create(true) + .write(true); + } - match open_options.open(p) { - Ok(file) => file, - Err(err) => return Err(err), + debug!("Attempting to open lock file `{}`", p.display()); + let file = match open_options.open(p) { + Ok(file) => { + debug!("Lock file opened successfully"); + file + } + Err(err) => { + debug!("Error opening lock file: {}", err); + return Err(err) } }; @@ -291,7 +301,9 @@ mod imp { dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; } - LockFileEx(f.as_raw_handle(), + debug!("Attempting to acquire lock on lock file `{}`", + p.display()); + LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, @@ -299,9 +311,12 @@ mod imp { &mut overlapped) }; if ret == 0 { - Err(io::Error::last_os_error()) + let err = io::Error::last_os_error(); + debug!("Failed acquiring file lock: {}", err); + Err(err) } else { - Ok(Lock { _file: f }) + debug!("Successfully acquired lock."); + Ok(Lock { _file: file }) } } } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 4391123559f9b..e7da18cef10f9 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -30,8 +30,8 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(fn_traits)] -#![feature(libc)] +#![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] extern crate core; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index c2990c66020b5..6eb3124e08eec 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -65,7 +65,7 @@ //! //! There is some synchronization needed in order for the compiler to be able to //! determine whether a given private session directory is not in used any more. -//! This is done by creating a lock file within each session directory and +//! This is done by creating a lock file for each session directory and //! locking it while the directory is still being used. Since file locks have //! operating system support, we can rely on the lock being released if the //! compiler process dies for some unexpected reason. Thus, when garbage @@ -131,7 +131,7 @@ use std::time::{UNIX_EPOCH, SystemTime, Duration}; use std::__rand::{thread_rng, Rng}; use syntax::ast; -const LOCK_FILE_NAME: &'static str = ".lock_file"; +const LOCK_FILE_EXT: &'static str = ".lock"; const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin"; const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin"; const METADATA_HASHES_FILENAME: &'static str = "metadata.bin"; @@ -153,7 +153,22 @@ pub fn metadata_hash_import_path(import_session_dir: &Path) -> PathBuf { } pub fn lock_file_path(session_dir: &Path) -> PathBuf { - session_dir.join(LOCK_FILE_NAME) + let crate_dir = session_dir.parent().unwrap(); + + let directory_name = session_dir.file_name().unwrap().to_string_lossy(); + assert_no_characters_lost(&directory_name); + + let dash_indices: Vec<_> = directory_name.match_indices("-") + .map(|(idx, _)| idx) + .collect(); + if dash_indices.len() != 3 { + bug!("Encountered incremental compilation session directory with \ + malformed name: {}", + session_dir.display()) + } + + crate_dir.join(&directory_name[0 .. dash_indices[2]]) + .with_extension(&LOCK_FILE_EXT[1..]) } pub fn in_incr_comp_dir_sess(sess: &Session, file_name: &str) -> PathBuf { @@ -179,23 +194,24 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { // {incr-comp-dir}/{crate-name-and-disambiguator} let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE); debug!("crate-dir: {}", crate_dir.display()); + try!(create_dir(tcx.sess, &crate_dir, "crate")); let mut source_directories_already_tried = FnvHashSet(); loop { - // Allocate a session directory of the form: + // Generate a session directory of the form: // // {incr-comp-dir}/{crate-name-and-disambiguator}/sess-{timestamp}-{random}-working - // - // If this fails, return an error, don't retry - let session_dir = try!(alloc_session_dir(tcx.sess, &crate_dir)); + let session_dir = generate_session_dir_path(&crate_dir); debug!("session-dir: {}", session_dir.display()); - // Lock the newly created session directory. If this fails, return an + // Lock the new session directory. If this fails, return an // error without retrying - let directory_lock = try!(lock_directory(tcx.sess, &session_dir)); + let (directory_lock, lock_file_path) = try!(lock_directory(tcx.sess, &session_dir)); - let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info; + // Now that we have the lock, we can actually create the session + // directory + try!(create_dir(tcx.sess, &session_dir, "session")); // Find a suitable source directory to copy from. Ignore those that we // have already tried before. @@ -216,6 +232,8 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { debug!("attempting to copy data from source: {}", source_directory.display()); + let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info; + // Try copying over all files from the source directory if copy_files(&session_dir, &source_directory, print_file_copy_stats).is_ok() { debug!("successfully copied data from: {}", @@ -233,15 +251,19 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { // Try to remove the session directory we just allocated. We don't // know if there's any garbage in it from the failed copy action. if let Err(err) = std_fs::remove_dir_all(&session_dir) { - debug!("Failed to delete partly initialized session dir `{}`: {}", - session_dir.display(), - err); + tcx.sess.warn(&format!("Failed to delete partly initialized \ + session dir `{}`: {}", + session_dir.display(), + err)); } + + delete_session_dir_lock_file(tcx.sess, &lock_file_path); mem::drop(directory_lock); } } } + /// This function finalizes and thus 'publishes' the session directory by /// renaming it to `sess-{timestamp}-{svh}` and releasing the file lock. /// If there have been compilation errors, however, this function will just @@ -262,10 +284,13 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) { sess.warn(&format!("Error deleting incremental compilation \ - session directory `{}`: {}", + session directory `{}`: {}", incr_comp_session_dir.display(), err)); } + + let lock_file_path = lock_file_path(&*incr_comp_session_dir); + delete_session_dir_lock_file(sess, &lock_file_path); sess.mark_incr_comp_session_as_invalid(); } @@ -277,8 +302,8 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { .to_string_lossy(); assert_no_characters_lost(&old_sub_dir_name); - // Keep the 'sess-{timestamp}' prefix, but replace the - // '-{random-number}-working' part with the SVH of the crate + // Keep the 'sess-{timestamp}-{random-number}' prefix, but replace the + // '-working' part with the SVH of the crate let dash_indices: Vec<_> = old_sub_dir_name.match_indices("-") .map(|(idx, _)| idx) .collect(); @@ -288,8 +313,8 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { incr_comp_session_dir.display()) } - // State: "sess-{timestamp}-" - let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[1] + 1]); + // State: "sess-{timestamp}-{random-number}-" + let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[2] + 1]); // Append the svh new_sub_dir_name.push_str(&svh.to_string()); @@ -327,7 +352,7 @@ fn copy_files(target_dir: &Path, -> Result<(), ()> { // We acquire a shared lock on the lock file of the directory, so that // nobody deletes it out from under us while we are reading from it. - let lock_file_path = source_dir.join(LOCK_FILE_NAME); + let lock_file_path = lock_file_path(source_dir); let _lock = if let Ok(lock) = flock::Lock::new(&lock_file_path, false, // don't wait, false, // don't create @@ -351,10 +376,6 @@ fn copy_files(target_dir: &Path, Ok(entry) => { let file_name = entry.file_name(); - if file_name.to_string_lossy() == LOCK_FILE_NAME { - continue; - } - let target_file_path = target_dir.join(file_name); let source_path = entry.path(); @@ -383,30 +404,32 @@ fn copy_files(target_dir: &Path, Ok(()) } -/// Create a directory with a path of the form: +/// Generate unique directory path of the form: /// {crate_dir}/sess-{timestamp}-{random-number}-working -fn alloc_session_dir(sess: &Session, - crate_dir: &Path) - -> Result { +fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { let timestamp = timestamp_to_string(SystemTime::now()); - debug!("alloc_session_dir: timestamp = {}", timestamp); + debug!("generate_session_dir_path: timestamp = {}", timestamp); let random_number = thread_rng().next_u32(); - debug!("alloc_session_dir: random_number = {}", random_number); + debug!("generate_session_dir_path: random_number = {}", random_number); let directory_name = format!("sess-{}-{:x}-working", timestamp, random_number); - debug!("alloc_session_dir: directory_name = {}", directory_name); + debug!("generate_session_dir_path: directory_name = {}", directory_name); let directory_path = crate_dir.join(directory_name); - debug!("alloc_session_dir: directory_path = {}", directory_path.display()); + debug!("generate_session_dir_path: directory_path = {}", directory_path.display()); + directory_path +} - match fs_util::create_dir_racy(&directory_path) { +fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(),()> { + match fs_util::create_dir_racy(path) { Ok(()) => { - debug!("alloc_session_dir: directory created successfully"); - Ok(directory_path) + debug!("{} directory created successfully", dir_tag); + Ok(()) } Err(err) => { - sess.err(&format!("incremental compilation: could not create \ - session directory `{}`: {}", - directory_path.display(), + sess.err(&format!("Could not create incremental compilation {} \ + directory `{}`: {}", + dir_tag, + path.display(), err)); Err(()) } @@ -416,15 +439,15 @@ fn alloc_session_dir(sess: &Session, /// Allocate a the lock-file and lock it. fn lock_directory(sess: &Session, session_dir: &Path) - -> Result { - let lock_file_path = session_dir.join(LOCK_FILE_NAME); + -> Result<(flock::Lock, PathBuf), ()> { + let lock_file_path = lock_file_path(session_dir); debug!("lock_directory() - lock_file: {}", lock_file_path.display()); match flock::Lock::new(&lock_file_path, false, // don't wait true, // create the lock file true) { // the lock should be exclusive - Ok(lock) => Ok(lock), + Ok(lock) => Ok((lock, lock_file_path)), Err(err) => { sess.err(&format!("incremental compilation: could not create \ session directory lock file: {}", err)); @@ -433,6 +456,16 @@ fn lock_directory(sess: &Session, } } +fn delete_session_dir_lock_file(sess: &Session, + lock_file_path: &Path) { + if let Err(err) = std_fs::remove_file(&lock_file_path) { + sess.warn(&format!("Error deleting lock file for incremental \ + compilation session directory `{}`: {}", + lock_file_path.display(), + err)); + } +} + /// Find the most recent published session directory that is not in the /// ignore-list. fn find_source_directory(crate_dir: &Path, @@ -453,23 +486,26 @@ fn find_source_directory_in_iter(iter: I, let mut best_candidate = (UNIX_EPOCH, None); for session_dir in iter { + debug!("find_source_directory_in_iter - inspecting `{}`", + session_dir.display()); + + let directory_name = session_dir.file_name().unwrap().to_string_lossy(); + assert_no_characters_lost(&directory_name); + if source_directories_already_tried.contains(&session_dir) || - !is_finalized(&session_dir.to_string_lossy()) { + !is_session_directory(&directory_name) || + !is_finalized(&directory_name) { + debug!("find_source_directory_in_iter - ignoring."); continue } - let timestamp = { - let directory_name = session_dir.file_name().unwrap().to_string_lossy(); - assert_no_characters_lost(&directory_name); - - extract_timestamp_from_session_dir(&directory_name) - .unwrap_or_else(|_| { - bug!("unexpected incr-comp session dir: {}", session_dir.display()) - }) - }; + let timestamp = extract_timestamp_from_session_dir(&directory_name) + .unwrap_or_else(|_| { + bug!("unexpected incr-comp session dir: {}", session_dir.display()) + }); if timestamp > best_candidate.0 { - best_candidate = (timestamp, Some(session_dir)); + best_candidate = (timestamp, Some(session_dir.clone())); } } @@ -481,7 +517,12 @@ fn is_finalized(directory_name: &str) -> bool { } fn is_session_directory(directory_name: &str) -> bool { - directory_name.starts_with("sess-") + directory_name.starts_with("sess-") && + !directory_name.ends_with(LOCK_FILE_EXT) +} + +fn is_session_directory_lock_file(file_name: &str) -> bool { + file_name.starts_with("sess-") && file_name.ends_with(LOCK_FILE_EXT) } fn extract_timestamp_from_session_dir(directory_name: &str) @@ -493,7 +534,7 @@ fn extract_timestamp_from_session_dir(directory_name: &str) let dash_indices: Vec<_> = directory_name.match_indices("-") .map(|(idx, _)| idx) .collect(); - if dash_indices.len() < 2 { + if dash_indices.len() != 3 { return Err(()) } @@ -502,22 +543,22 @@ fn extract_timestamp_from_session_dir(directory_name: &str) fn timestamp_to_string(timestamp: SystemTime) -> String { let duration = timestamp.duration_since(UNIX_EPOCH).unwrap(); - let nanos = duration.as_secs() * 1_000_000_000 + - (duration.subsec_nanos() as u64); - format!("{:x}", nanos) + let micros = duration.as_secs() * 1_000_000 + + (duration.subsec_nanos() as u64) / 1000; + format!("{:x}", micros) } fn string_to_timestamp(s: &str) -> Result { - let nanos_since_unix_epoch = u64::from_str_radix(s, 16); + let micros_since_unix_epoch = u64::from_str_radix(s, 16); - if nanos_since_unix_epoch.is_err() { + if micros_since_unix_epoch.is_err() { return Err(()) } - let nanos_since_unix_epoch = nanos_since_unix_epoch.unwrap(); + let micros_since_unix_epoch = micros_since_unix_epoch.unwrap(); - let duration = Duration::new(nanos_since_unix_epoch / 1_000_000_000, - (nanos_since_unix_epoch % 1_000_000_000) as u32); + let duration = Duration::new(micros_since_unix_epoch / 1_000_000, + 1000 * (micros_since_unix_epoch % 1_000_000) as u32); Ok(UNIX_EPOCH + duration) } @@ -607,6 +648,10 @@ fn assert_no_characters_lost(s: &str) { } } +fn is_old_enough_to_be_collected(timestamp: SystemTime) -> bool { + timestamp < SystemTime::now() - Duration::from_secs(10) +} + pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { debug!("garbage_collect_session_directories() - begin"); @@ -618,8 +663,10 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { debug!("garbage_collect_session_directories() - crate directory: {}", crate_directory.display()); - let mut deletion_candidates = vec![]; - let mut definitely_delete = vec![]; + // First do a pass over the crate directory, collecting lock files and + // session directories + let mut session_directories = FnvHashSet(); + let mut lock_files = FnvHashSet(); for dir_entry in try!(crate_directory.read_dir()) { let dir_entry = match dir_entry { @@ -630,102 +677,143 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { } }; - let directory_name = dir_entry.file_name(); - let directory_name = directory_name.to_string_lossy(); + let entry_name = dir_entry.file_name(); + let entry_name = entry_name.to_string_lossy(); - if !is_session_directory(&directory_name) { - // This is something we don't know, leave it alone... - continue + if is_session_directory_lock_file(&entry_name) { + assert_no_characters_lost(&entry_name); + lock_files.insert(entry_name.into_owned()); + } else if is_session_directory(&entry_name) { + assert_no_characters_lost(&entry_name); + session_directories.insert(entry_name.into_owned()); + } else { + // This is something we don't know, leave it alone } - assert_no_characters_lost(&directory_name); + } - if let Ok(file_type) = dir_entry.file_type() { - if !file_type.is_dir() { - // This is not a directory, skip it - continue + // Now map from lock files to session directories + let lock_file_to_session_dir: FnvHashMap> = + lock_files.into_iter() + .map(|lock_file_name| { + assert!(lock_file_name.ends_with(LOCK_FILE_EXT)); + let dir_prefix_end = lock_file_name.len() - LOCK_FILE_EXT.len(); + let session_dir = { + let dir_prefix = &lock_file_name[0 .. dir_prefix_end]; + session_directories.iter() + .find(|dir_name| dir_name.starts_with(dir_prefix)) + }; + (lock_file_name, session_dir.map(String::clone)) + }) + .collect(); + + // Delete all lock files, that don't have an associated directory. They must + // be some kind of leftover + for (lock_file_name, directory_name) in &lock_file_to_session_dir { + if directory_name.is_none() { + let timestamp = match extract_timestamp_from_session_dir(lock_file_name) { + Ok(timestamp) => timestamp, + Err(()) => { + debug!("Found lock-file with malformed timestamp: {}", + crate_directory.join(&lock_file_name).display()); + // Ignore it + continue + } + }; + + let lock_file_path = crate_directory.join(&**lock_file_name); + + if is_old_enough_to_be_collected(timestamp) { + debug!("garbage_collect_session_directories() - deleting \ + garbage lock file: {}", lock_file_path.display()); + delete_session_dir_lock_file(sess, &lock_file_path); + } else { + debug!("garbage_collect_session_directories() - lock file with \ + no session dir not old enough to be collected: {}", + lock_file_path.display()); } - } else { - // Some error occurred while trying to determine the file type, - // skip it - continue } + } + + // Filter out `None` directories + let lock_file_to_session_dir: FnvHashMap = + lock_file_to_session_dir.into_iter() + .filter_map(|(lock_file_name, directory_name)| { + directory_name.map(|n| (lock_file_name, n)) + }) + .collect(); + + let mut deletion_candidates = vec![]; + let mut definitely_delete = vec![]; + for (lock_file_name, directory_name) in &lock_file_to_session_dir { debug!("garbage_collect_session_directories() - inspecting: {}", directory_name); - match extract_timestamp_from_session_dir(&directory_name) { - Ok(timestamp) => { - let lock_file_path = crate_directory.join(&*directory_name) - .join(LOCK_FILE_NAME); - - if !is_finalized(&directory_name) { - let ten_seconds = Duration::from_secs(10); - - // When cleaning out "-working" session directories, i.e. - // session directories that might still be in use by another - // compiler instance, we only look a directories that are - // at least ten seconds old. This is supposed to reduce the - // chance of deleting a directory in the time window where - // the process has allocated the directory but has not yet - // acquired the file-lock on it. - if timestamp < SystemTime::now() - ten_seconds { - debug!("garbage_collect_session_directories() - \ - attempting to collect"); - - // Try to acquire the directory lock. If we can't, it - // means that the owning process is still alive and we - // leave this directory alone. - match flock::Lock::new(&lock_file_path, - false, // don't wait - false, // don't create the lock-file - true) { // get an exclusive lock - Ok(lock) => { - debug!("garbage_collect_session_directories() - \ - successfully acquired lock"); - - // Note that we are holding on to the lock - definitely_delete.push((dir_entry.path(), - Some(lock))); - } - Err(_) => { - debug!("garbage_collect_session_directories() - \ - not collecting, still in use"); - } - } - } else { - debug!("garbage_collect_session_directories() - \ - private session directory too new"); - } - } else { - match flock::Lock::new(&lock_file_path, - false, // don't wait - false, // don't create the lock-file - true) { // get an exclusive lock - Ok(lock) => { - debug!("garbage_collect_session_directories() - \ - successfully acquired lock"); - debug!("garbage_collect_session_directories() - adding \ - deletion candidate: {}", directory_name); - - // Note that we are holding on to the lock - deletion_candidates.push((timestamp, - dir_entry.path(), - Some(lock))); - } - Err(_) => { - debug!("garbage_collect_session_directories() - \ + let timestamp = match extract_timestamp_from_session_dir(directory_name) { + Ok(timestamp) => timestamp, + Err(()) => { + debug!("Found session-dir with malformed timestamp: {}", + crate_directory.join(directory_name).display()); + // Ignore it + continue + } + }; + + if is_finalized(directory_name) { + let lock_file_path = crate_directory.join(lock_file_name); + match flock::Lock::new(&lock_file_path, + false, // don't wait + false, // don't create the lock-file + true) { // get an exclusive lock + Ok(lock) => { + debug!("garbage_collect_session_directories() - \ + successfully acquired lock"); + debug!("garbage_collect_session_directories() - adding \ + deletion candidate: {}", directory_name); + + // Note that we are holding on to the lock + deletion_candidates.push((timestamp, + crate_directory.join(directory_name), + Some(lock))); + } + Err(_) => { + debug!("garbage_collect_session_directories() - \ not collecting, still in use"); - } - } } } - Err(_) => { - // Malformed timestamp in directory, delete it - definitely_delete.push((dir_entry.path(), None)); - - debug!("garbage_collect_session_directories() - encountered \ - malformed session directory: {}", directory_name); + } else if is_old_enough_to_be_collected(timestamp) { + // When cleaning out "-working" session directories, i.e. + // session directories that might still be in use by another + // compiler instance, we only look a directories that are + // at least ten seconds old. This is supposed to reduce the + // chance of deleting a directory in the time window where + // the process has allocated the directory but has not yet + // acquired the file-lock on it. + + // Try to acquire the directory lock. If we can't, it + // means that the owning process is still alive and we + // leave this directory alone. + let lock_file_path = crate_directory.join(lock_file_name); + match flock::Lock::new(&lock_file_path, + false, // don't wait + false, // don't create the lock-file + true) { // get an exclusive lock + Ok(lock) => { + debug!("garbage_collect_session_directories() - \ + successfully acquired lock"); + + // Note that we are holding on to the lock + definitely_delete.push((crate_directory.join(directory_name), + Some(lock))); + } + Err(_) => { + debug!("garbage_collect_session_directories() - \ + not collecting, still in use"); + } } + } else { + debug!("garbage_collect_session_directories() - not finalized, not \ + old enough"); } } @@ -739,8 +827,11 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { compilation session directory `{}`: {}", path.display(), err)); + } else { + delete_session_dir_lock_file(sess, &lock_file_path(&path)); } + // Let's make it explicit that the file lock is released at this point, // or rather, that we held on to it until here mem::drop(lock); @@ -755,6 +846,8 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { compilation session directory `{}`: {}", path.display(), err)); + } else { + delete_session_dir_lock_file(sess, &lock_file_path(&path)); } // Let's make it explicit that the file lock is released at this point, @@ -809,7 +902,7 @@ fn test_all_except_most_recent() { #[test] fn test_timestamp_serialization() { for i in 0 .. 1_000u64 { - let time = UNIX_EPOCH + Duration::new(i * 3_434_578, (i as u32) * 239_676); + let time = UNIX_EPOCH + Duration::new(i * 3_434_578, (i as u32) * 239_000); let s = timestamp_to_string(time); assert_eq!(time, string_to_timestamp(&s).unwrap()); } @@ -821,17 +914,17 @@ fn test_find_source_directory_in_iter() { // Find newest assert_eq!(find_source_directory_in_iter( - vec![PathBuf::from("./sess-3234-0000"), - PathBuf::from("./sess-2234-0000"), - PathBuf::from("./sess-1234-0000")].into_iter(), &already_visited), - Some(PathBuf::from("./sess-3234-0000"))); + vec![PathBuf::from("crate-dir/sess-3234-0000-svh"), + PathBuf::from("crate-dir/sess-2234-0000-svh"), + PathBuf::from("crate-dir/sess-1234-0000-svh")].into_iter(), &already_visited), + Some(PathBuf::from("crate-dir/sess-3234-0000-svh"))); // Filter out "-working" assert_eq!(find_source_directory_in_iter( - vec![PathBuf::from("./sess-3234-0000-working"), - PathBuf::from("./sess-2234-0000"), - PathBuf::from("./sess-1234-0000")].into_iter(), &already_visited), - Some(PathBuf::from("./sess-2234-0000"))); + vec![PathBuf::from("crate-dir/sess-3234-0000-working"), + PathBuf::from("crate-dir/sess-2234-0000-svh"), + PathBuf::from("crate-dir/sess-1234-0000-svh")].into_iter(), &already_visited), + Some(PathBuf::from("crate-dir/sess-2234-0000-svh"))); // Handle empty assert_eq!(find_source_directory_in_iter(vec![].into_iter(), &already_visited), @@ -839,9 +932,9 @@ fn test_find_source_directory_in_iter() { // Handle only working assert_eq!(find_source_directory_in_iter( - vec![PathBuf::from("./sess-3234-0000-working"), - PathBuf::from("./sess-2234-0000-working"), - PathBuf::from("./sess-1234-0000-working")].into_iter(), &already_visited), + vec![PathBuf::from("crate-dir/sess-3234-0000-working"), + PathBuf::from("crate-dir/sess-2234-0000-working"), + PathBuf::from("crate-dir/sess-1234-0000-working")].into_iter(), &already_visited), None); } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index cc4966eadae91..48f95430f26b6 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -59,7 +59,6 @@ pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Err(()) => { // Something went wrong while trying to allocate the session // directory. Don't try to use it any further. - let _ = garbage_collect_session_directories(tcx.sess); return } } From 004a7eb127eca62908b6c4ff7d24a9685f21ae85 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 25 Aug 2016 20:48:13 -0400 Subject: [PATCH 363/768] Fix rustbuild --- src/librustdoc/Cargo.toml | 1 + src/rustc/Cargo.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 3e510bdc9002e..d66d2001f2304 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -16,6 +16,7 @@ rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_driver = { path = "../librustc_driver" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index c0db651d7d2b4..fde2f83e220f9 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -363,6 +363,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", "rustc_driver 0.0.0", "rustc_errors 0.0.0", "rustc_lint 0.0.0", From b67f57afdd80e75c93c4ae49e12b8bb16d209916 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Aug 2016 12:26:20 -0400 Subject: [PATCH 364/768] incr. comp.: Fix test_timestamp_serialization so it does not overflow on some 32bit systems. --- src/librustc_incremental/persist/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 6eb3124e08eec..9e4a16fd43c0d 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -902,9 +902,9 @@ fn test_all_except_most_recent() { #[test] fn test_timestamp_serialization() { for i in 0 .. 1_000u64 { - let time = UNIX_EPOCH + Duration::new(i * 3_434_578, (i as u32) * 239_000); + let time = UNIX_EPOCH + Duration::new(i * 1_434_578, (i as u32) * 239_000); let s = timestamp_to_string(time); - assert_eq!(time, string_to_timestamp(&s).unwrap()); + assert_eq!(Ok(time), string_to_timestamp(&s)); } } From a3dc5f95aa06b26a056f67cdc5e8438e80e8394c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Aug 2016 16:50:24 -0400 Subject: [PATCH 365/768] incr.comp.: Make path's of session directories slightly shorter. By using "s-" instead of "sess-" as a prefix and encoding numbers as base36 instead of base16. --- src/librustc_incremental/persist/fs.rs | 113 ++++++++++++++++--------- 1 file changed, 75 insertions(+), 38 deletions(-) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 9e4a16fd43c0d..809e1324c1efe 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -45,7 +45,7 @@ //! that are consistent with the state of the source code it was compiled //! from, with no need to change them ever again. At this point, the compiler //! finalizes and "publishes" its private session directory by renaming it -//! from "sess-{timestamp}-{random}-working" to "sess-{timestamp}-{SVH}". +//! from "s-{timestamp}-{random}-working" to "s-{timestamp}-{SVH}". //! 6. At this point the "old" session directory that we copied our data from //! at the beginning of the session has become obsolete because we have just //! published a more current version. Thus the compiler will delete it. @@ -201,7 +201,7 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { loop { // Generate a session directory of the form: // - // {incr-comp-dir}/{crate-name-and-disambiguator}/sess-{timestamp}-{random}-working + // {incr-comp-dir}/{crate-name-and-disambiguator}/s-{timestamp}-{random}-working let session_dir = generate_session_dir_path(&crate_dir); debug!("session-dir: {}", session_dir.display()); @@ -265,7 +265,7 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { /// This function finalizes and thus 'publishes' the session directory by -/// renaming it to `sess-{timestamp}-{svh}` and releasing the file lock. +/// renaming it to `s-{timestamp}-{svh}` and releasing the file lock. /// If there have been compilation errors, however, this function will just /// delete the presumably invalid session directory. pub fn finalize_session_directory(sess: &Session, svh: Svh) { @@ -302,7 +302,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { .to_string_lossy(); assert_no_characters_lost(&old_sub_dir_name); - // Keep the 'sess-{timestamp}-{random-number}' prefix, but replace the + // Keep the 's-{timestamp}-{random-number}' prefix, but replace the // '-working' part with the SVH of the crate let dash_indices: Vec<_> = old_sub_dir_name.match_indices("-") .map(|(idx, _)| idx) @@ -313,11 +313,11 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { incr_comp_session_dir.display()) } - // State: "sess-{timestamp}-{random-number}-" + // State: "s-{timestamp}-{random-number}-" let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[2] + 1]); // Append the svh - new_sub_dir_name.push_str(&svh.to_string()); + new_sub_dir_name.push_str(&encode_base_36(svh.as_u64())); // Create the full path let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name); @@ -405,14 +405,16 @@ fn copy_files(target_dir: &Path, } /// Generate unique directory path of the form: -/// {crate_dir}/sess-{timestamp}-{random-number}-working +/// {crate_dir}/s-{timestamp}-{random-number}-working fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { let timestamp = timestamp_to_string(SystemTime::now()); debug!("generate_session_dir_path: timestamp = {}", timestamp); let random_number = thread_rng().next_u32(); debug!("generate_session_dir_path: random_number = {}", random_number); - let directory_name = format!("sess-{}-{:x}-working", timestamp, random_number); + let directory_name = format!("s-{}-{}-working", + timestamp, + encode_base_36(random_number as u64)); debug!("generate_session_dir_path: directory_name = {}", directory_name); let directory_path = crate_dir.join(directory_name); debug!("generate_session_dir_path: directory_path = {}", directory_path.display()); @@ -517,12 +519,12 @@ fn is_finalized(directory_name: &str) -> bool { } fn is_session_directory(directory_name: &str) -> bool { - directory_name.starts_with("sess-") && + directory_name.starts_with("s-") && !directory_name.ends_with(LOCK_FILE_EXT) } fn is_session_directory_lock_file(file_name: &str) -> bool { - file_name.starts_with("sess-") && file_name.ends_with(LOCK_FILE_EXT) + file_name.starts_with("s-") && file_name.ends_with(LOCK_FILE_EXT) } fn extract_timestamp_from_session_dir(directory_name: &str) @@ -541,15 +543,31 @@ fn extract_timestamp_from_session_dir(directory_name: &str) string_to_timestamp(&directory_name[dash_indices[0]+1 .. dash_indices[1]]) } +const BASE_36: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyz"; + +fn encode_base_36(mut n: u64) -> String { + let mut s = Vec::with_capacity(13); + loop { + s.push(BASE_36[(n % 36) as usize]); + n /= 36; + + if n == 0 { + break; + } + } + s.reverse(); + String::from_utf8(s).unwrap() +} + fn timestamp_to_string(timestamp: SystemTime) -> String { let duration = timestamp.duration_since(UNIX_EPOCH).unwrap(); let micros = duration.as_secs() * 1_000_000 + (duration.subsec_nanos() as u64) / 1000; - format!("{:x}", micros) + encode_base_36(micros) } fn string_to_timestamp(s: &str) -> Result { - let micros_since_unix_epoch = u64::from_str_radix(s, 16); + let micros_since_unix_epoch = u64::from_str_radix(s, 36); if micros_since_unix_epoch.is_err() { return Err(()) @@ -591,7 +609,8 @@ pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: ast::CrateNum) -> Option Date: Fri, 26 Aug 2016 16:53:19 -0400 Subject: [PATCH 366/768] incr.comp.: Make compiletest generate shorter cache directory names. --- src/tools/compiletest/src/runtest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 60a0d8f0b865f..aa4510746fdc3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2041,7 +2041,7 @@ actual:\n\ /// Directory where incremental work products are stored. fn incremental_dir(&self) -> PathBuf { - self.output_base_name().with_extension("incremental") + self.output_base_name().with_extension("inc") } fn run_rmake_test(&self) { From 68d2275a97f62c2b3399b49453876dd56e82f0eb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sat, 27 Aug 2016 14:37:40 -0400 Subject: [PATCH 367/768] Fix tidy-errors --- src/librustc_incremental/persist/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 809e1324c1efe..b0d71e47e409e 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -412,7 +412,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { let random_number = thread_rng().next_u32(); debug!("generate_session_dir_path: random_number = {}", random_number); - let directory_name = format!("s-{}-{}-working", + let directory_name = format!("s-{}-{}-working", timestamp, encode_base_36(random_number as u64)); debug!("generate_session_dir_path: directory_name = {}", directory_name); @@ -1005,7 +1005,7 @@ fn test_find_metadata_hashes_iter() None ); } - + #[test] fn test_encode_base_36() { fn test(n: u64) { From 50b008ae3b9d15765d829ba336856f7057c9bb0c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 13:38:09 -0400 Subject: [PATCH 368/768] compiletest: Canonicalize paths when remove incr.comp. dir, enabling longer paths --- src/tools/compiletest/src/runtest.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index aa4510746fdc3..228d6ada01dcc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1976,7 +1976,10 @@ actual:\n\ // runs. let incremental_dir = self.incremental_dir(); if incremental_dir.exists() { - fs::remove_dir_all(&incremental_dir).unwrap(); + // Canonicalizing the path will convert it to the //?/ format + // on Windows, which enables paths longer than 260 character + let canonicalized = incremental_dir.canonicalize().unwrap(); + fs::remove_dir_all(canonicalized).unwrap(); } fs::create_dir_all(&incremental_dir).unwrap(); From bcd2f905c46158f9137fa5b63aafebcb60083385 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 14:18:26 -0400 Subject: [PATCH 369/768] incr.comp.: Canonicalize path to session directory before deleteing it. --- src/librustc_incremental/persist/fs.rs | 34 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index b0d71e47e409e..4ad4b115759c4 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -250,7 +250,7 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { // Try to remove the session directory we just allocated. We don't // know if there's any garbage in it from the failed copy action. - if let Err(err) = std_fs::remove_dir_all(&session_dir) { + if let Err(err) = safe_remove_dir_all(&session_dir) { tcx.sess.warn(&format!("Failed to delete partly initialized \ session dir `{}`: {}", session_dir.display(), @@ -282,7 +282,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { debug!("finalize_session_directory() - invalidating session directory: {}", incr_comp_session_dir.display()); - if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) { + if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) { sess.warn(&format!("Error deleting incremental compilation \ session directory `{}`: {}", incr_comp_session_dir.display(), @@ -460,7 +460,7 @@ fn lock_directory(sess: &Session, fn delete_session_dir_lock_file(sess: &Session, lock_file_path: &Path) { - if let Err(err) = std_fs::remove_file(&lock_file_path) { + if let Err(err) = safe_remove_file(&lock_file_path) { sess.warn(&format!("Error deleting lock file for incremental \ compilation session directory `{}`: {}", lock_file_path.display(), @@ -841,7 +841,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - if let Err(err) = std_fs::remove_dir_all(&path) { + if let Err(err) = safe_remove_dir_all(&path) { sess.warn(&format!("Failed to garbage collect finalized incremental \ compilation session directory `{}`: {}", path.display(), @@ -860,7 +860,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - if let Err(err) = std_fs::remove_dir_all(&path) { + if let Err(err) = safe_remove_dir_all(&path) { sess.warn(&format!("Failed to garbage collect incremental \ compilation session directory `{}`: {}", path.display(), @@ -893,6 +893,30 @@ fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option< } } +/// Since paths of artifacts within session directories can get quite long, we +/// need to support deleting files with very long paths. The regular +/// WinApi functions only support paths up to 260 characters, however. In order +/// to circumvent this limitation, we canonicalize the path of the directory +/// before passing it to std::fs::remove_dir_all(). This will convert the path +/// into the '\\?\' format, which supports much longer paths. +fn safe_remove_dir_all(p: &Path) -> io::Result<()> { + if p.exists() { + let canonicalized = try!(p.canonicalize()); + std_fs::remove_dir_all(canonicalized) + } else { + Ok(()) + } +} + +fn safe_remove_file(p: &Path) -> io::Result<()> { + if p.exists() { + let canonicalized = try!(p.canonicalize()); + std_fs::remove_file(canonicalized) + } else { + Ok(()) + } +} + #[test] fn test_all_except_most_recent() { assert_eq!(all_except_most_recent( From 61a639ec4e0006f21253e8133cd1da980ce042d1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 29 Aug 2016 22:53:18 +0300 Subject: [PATCH 370/768] llvm: backport "[SimplifyCFG] Hoisting invalidates metadata". --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/test/run-pass/issue-36023.rs | 32 ++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/issue-36023.rs diff --git a/src/llvm b/src/llvm index c3eb3c7608f43..eee68eafa7e8e 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit c3eb3c7608f439231d0c1340af6b720f113b4bf4 +Subproject commit eee68eafa7e8e4ce996b49f5551636639a6c331a diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 59c6d53bfa3b9..67f8730c25825 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-08-17 +2016-08-23 diff --git a/src/test/run-pass/issue-36023.rs b/src/test/run-pass/issue-36023.rs new file mode 100644 index 0000000000000..f6c03b384f23d --- /dev/null +++ b/src/test/run-pass/issue-36023.rs @@ -0,0 +1,32 @@ +// 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. + +use std::ops::Deref; + +fn main() { + if env_var("FOOBAR").as_ref().map(Deref::deref).ok() == Some("yes") { + panic!() + } + + let env_home: Result = Ok("foo-bar-baz".to_string()); + let env_home = env_home.as_ref().map(Deref::deref).ok(); + + if env_home == Some("") { panic!() } +} + +#[inline(never)] +fn env_var(s: &str) -> Result { + Err(VarError::NotPresent) +} + +pub enum VarError { + NotPresent, + NotUnicode(String), +} From 987ef784fd9cf4e9039f84e3a052e81349108b69 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 29 Aug 2016 22:31:28 +0300 Subject: [PATCH 371/768] Fix the test_variadic_ptr fn on printf-less sys Fixes #36076 --- src/libcoretest/ptr.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index e0a9f4e5d422c..f7fe61896f85e 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -173,12 +173,16 @@ fn test_unsized_unique() { } #[test] -fn test_variadic_fnptr() { +#[allow(warnings)] +// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the +// ABI, or even point to an actual executable code, because the function itself is never invoked. +#[no_mangle] +pub fn test_variadic_fnptr() { use core::hash::{Hash, SipHasher}; - extern "C" { - fn printf(_: *const u8, ...); + extern { + fn test_variadic_fnptr(_: u64, ...) -> f64; } - let p: unsafe extern "C" fn(*const u8, ...) = printf; + let p: unsafe extern fn(u64, ...) -> f64 = test_variadic_fnptr; let q = p.clone(); assert_eq!(p, q); assert!(!(p < q)); From 175d434c99a29de6bb9293a2fa3b7c94ef51c3da Mon Sep 17 00:00:00 2001 From: arthurprs Date: Mon, 29 Aug 2016 23:12:08 +0200 Subject: [PATCH 372/768] Remove BinaryHeap bounds checking --- src/libcollections/binary_heap.rs | 43 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 5ece27372e130..0b923468c7416 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -884,58 +884,61 @@ struct Hole<'a, T: 'a> { impl<'a, T> Hole<'a, T> { /// Create a new Hole at index `pos`. - fn new(data: &'a mut [T], pos: usize) -> Self { - unsafe { - let elt = ptr::read(&data[pos]); - Hole { - data: data, - elt: Some(elt), - pos: pos, - } + /// + /// Unsafe because pos must be within the data slice. + #[inline] + unsafe fn new(data: &'a mut [T], pos: usize) -> Self { + debug_assert!(pos < data.len()); + let elt = ptr::read(&data[pos]); + Hole { + data: data, + elt: Some(elt), + pos: pos, } } - #[inline(always)] + #[inline] fn pos(&self) -> usize { self.pos } /// Return a reference to the element removed - #[inline(always)] + #[inline] fn element(&self) -> &T { self.elt.as_ref().unwrap() } /// Return a reference to the element at `index`. /// - /// Panics if the index is out of bounds. - /// - /// Unsafe because index must not equal pos. - #[inline(always)] + /// Unsafe because index must be within the data slice and not equal to pos. + #[inline] unsafe fn get(&self, index: usize) -> &T { debug_assert!(index != self.pos); - &self.data[index] + debug_assert!(index < self.data.len()); + self.data.get_unchecked(index) } /// Move hole to new location /// - /// Unsafe because index must not equal pos. - #[inline(always)] + /// Unsafe because index must be within the data slice and not equal to pos. + #[inline] unsafe fn move_to(&mut self, index: usize) { debug_assert!(index != self.pos); - let index_ptr: *const _ = &self.data[index]; - let hole_ptr = &mut self.data[self.pos]; + debug_assert!(index < self.data.len()); + let index_ptr: *const _ = self.data.get_unchecked(index); + let hole_ptr = self.data.get_unchecked_mut(self.pos); ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); self.pos = index; } } impl<'a, T> Drop for Hole<'a, T> { + #[inline] fn drop(&mut self) { // fill the hole again unsafe { let pos = self.pos; - ptr::write(&mut self.data[pos], self.elt.take().unwrap()); + ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap()); } } } From f53415fe0ded6c889f89890a0af0cd4066372980 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 30 Aug 2016 02:16:18 +0300 Subject: [PATCH 373/768] Unignore the json tests on 32-bit platforms cc #14064 --- src/libserialize/json.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 6c4b6c4506b81..a032332ada440 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -3592,7 +3592,6 @@ mod tests { } } #[test] - #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) fn test_streaming_parser() { assert_stream_equal( r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#, @@ -3631,7 +3630,6 @@ mod tests { } #[test] - #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) fn test_read_object_streaming() { assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3))); assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2))); @@ -3715,7 +3713,6 @@ mod tests { ); } #[test] - #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) fn test_read_array_streaming() { assert_stream_equal( "[]", From 6355528ffda28e77850f739d5c51ab48e8a68bb1 Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Mon, 29 Aug 2016 11:55:30 +1000 Subject: [PATCH 374/768] E0164 Update error format #35269 - Fixes #35269 - Part of #35233 r? @jonathandturner --- src/librustc_typeck/check/_match.rs | 3 ++- src/test/compile-fail/E0164.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 78175c85b19bf..225468cb9f40c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -574,7 +574,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, pat.id, pat.span, msg); } else { - span_err!(tcx.sess, pat.span, E0164, "{}", msg); + struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) + .span_label(pat.span, &format!("not a tuple variant or struct")).emit(); on_error(); } }; diff --git a/src/test/compile-fail/E0164.rs b/src/test/compile-fail/E0164.rs index 491b2e9e5b246..1665a80bead77 100644 --- a/src/test/compile-fail/E0164.rs +++ b/src/test/compile-fail/E0164.rs @@ -13,6 +13,7 @@ enum Foo { B { i: u32 } } fn bar(foo: Foo) -> u32 { match foo { Foo::B(i) => i, //~ ERROR E0164 + //~| NOTE not a tuple variant or struct } } From 28c5edb9f6a35dcd1bf4af102457d26a2de9d76e Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Mon, 29 Aug 2016 12:52:02 +1000 Subject: [PATCH 375/768] E0165 Update error format #35270 - Fixes #35270 - Part of #35233 r? @jonathandturner --- src/librustc_const_eval/check_match.rs | 5 ++++- src/test/compile-fail/E0165.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 82c142c919e34..e71a780dd89bc 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -324,7 +324,10 @@ fn check_arms(cx: &MatchCheckCtxt, let &(ref first_arm_pats, _) = &arms[0]; let first_pat = &first_arm_pats[0]; let span = first_pat.span; - span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern"); + struct_span_err!(cx.tcx.sess, span, E0165, + "irrefutable while-let pattern") + .span_label(span, &format!("irrefutable pattern")) + .emit(); }, hir::MatchSource::ForLoopDesugar => { diff --git a/src/test/compile-fail/E0165.rs b/src/test/compile-fail/E0165.rs index cca714bbcc1bf..142635fc6ee45 100644 --- a/src/test/compile-fail/E0165.rs +++ b/src/test/compile-fail/E0165.rs @@ -13,6 +13,7 @@ struct Irrefutable(i32); fn main() { let irr = Irrefutable(0); while let Irrefutable(x) = irr { //~ ERROR E0165 + //~| irrefutable pattern // ... } } From 2967dcc4d7bf0722fb348092a254aaa12deaa6d8 Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Mon, 29 Aug 2016 13:05:06 +1000 Subject: [PATCH 376/768] E0184 Update error format #35275 - Fixes #35275 - Part of #35233 r? @jonathandturner --- src/librustc_typeck/coherence/mod.rs | 6 ++++-- src/test/compile-fail/E0184.rs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 7d6cee7b3bac1..f743ef2187561 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -348,9 +348,11 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { .emit(); } Err(CopyImplementationError::HasDestructor) => { - span_err!(tcx.sess, span, E0184, + struct_span_err!(tcx.sess, span, E0184, "the trait `Copy` may not be implemented for this type; \ - the type has a destructor"); + the type has a destructor") + .span_label(span, &format!("Copy not allowed on types with destructors")) + .emit(); } } }); diff --git a/src/test/compile-fail/E0184.rs b/src/test/compile-fail/E0184.rs index 5d72d00ffe876..9ec2eeba5cc5f 100644 --- a/src/test/compile-fail/E0184.rs +++ b/src/test/compile-fail/E0184.rs @@ -9,6 +9,8 @@ // except according to those terms. #[derive(Copy)] //~ ERROR E0184 + //~| NOTE Copy not allowed on types with destructors + //~| NOTE in this expansion of #[derive(Copy)] struct Foo; impl Drop for Foo { From 8341f6451bef4fa16ba6a51d4d73923f2f1b539d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 30 Aug 2016 05:34:21 +0300 Subject: [PATCH 377/768] Fix run-pass/signal-exit-status to not trigger UB by writing to NULL. --- src/test/run-pass/signal-exit-status.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index c7759ca743bbb..8a2bbc83c424e 100644 --- a/src/test/run-pass/signal-exit-status.rs +++ b/src/test/run-pass/signal-exit-status.rs @@ -18,7 +18,7 @@ pub fn main() { let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "signal" { // Raise a segfault. - unsafe { *(0 as *mut isize) = 0; } + unsafe { *(1 as *mut isize) = 0; } } else { let status = Command::new(&args[0]).arg("signal").status().unwrap(); assert!(status.code().is_none()); From 10b8e0ed6720e7e7ec7df8fd15671cb293342e20 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 29 Aug 2016 23:35:50 -0400 Subject: [PATCH 378/768] rustbook chapters/sections should be an ordered list. --- src/tools/rustbook/build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/rustbook/build.rs b/src/tools/rustbook/build.rs index 6014439fafcf9..09c2d2510e317 100644 --- a/src/tools/rustbook/build.rs +++ b/src/tools/rustbook/build.rs @@ -61,9 +61,9 @@ fn write_toc(book: &Book, current_page: &BookItem, out: &mut Write) -> io::Resul section, item.title)?; if !item.children.is_empty() { - writeln!(out, "

")?; + writeln!(out, "")?; } writeln!(out, "")?; @@ -71,9 +71,9 @@ fn write_toc(book: &Book, current_page: &BookItem, out: &mut Write) -> io::Resul } writeln!(out, "
")?; - writeln!(out, "
    ")?; + writeln!(out, "
      ")?; walk_items(&book.chapters[..], "", ¤t_page, out)?; - writeln!(out, "
")?; + writeln!(out, "")?; writeln!(out, "
")?; Ok(()) From c36ccf7912a1dd229cda0c2443cad31c0e5f8fd6 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Tue, 30 Aug 2016 06:42:56 +0200 Subject: [PATCH 379/768] doc: make TcpListener example more simple --- src/libstd/net/tcp.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index dcd3652af876b..3c5f07c3e33a6 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -45,7 +45,6 @@ pub struct TcpStream(net_imp::TcpStream); /// /// ```no_run /// use std::net::{TcpListener, TcpStream}; -/// use std::thread; /// /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); /// @@ -57,17 +56,11 @@ pub struct TcpStream(net_imp::TcpStream); /// for stream in listener.incoming() { /// match stream { /// Ok(stream) => { -/// thread::spawn(move|| { -/// // connection succeeded -/// handle_client(stream) -/// }); +/// handle_client(stream); /// } /// Err(e) => { /* connection failed */ } /// } /// } -/// -/// // close the socket server -/// drop(listener); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); From fb65fe95ebb51ae2fc153d96127cfd6b5860dd02 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Tue, 30 Aug 2016 10:29:24 +0530 Subject: [PATCH 380/768] Update compiler error 0034 to use new format. --- src/librustc_typeck/check/method/suggest.rs | 1 + src/test/compile-fail/E0034.rs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f9699a55f5068..46b3f503b6e76 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -242,6 +242,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { MethodError::Ambiguity(sources) => { let mut err = struct_span_err!(self.sess(), span, E0034, "multiple applicable items in scope"); + err.span_label(span, &format!("multiple `{}` found", item_name)); report_candidates(&mut err, sources); err.emit(); diff --git a/src/test/compile-fail/E0034.rs b/src/test/compile-fail/E0034.rs index 669bece0f7d17..136a74f7a8b74 100644 --- a/src/test/compile-fail/E0034.rs +++ b/src/test/compile-fail/E0034.rs @@ -18,9 +18,17 @@ trait Trait2 { fn foo(); } -impl Trait1 for Test { fn foo() {} } -impl Trait2 for Test { fn foo() {} } +impl Trait1 for Test { + fn foo() {} + //~^ NOTE candidate #1 is defined in an impl of the trait `Trait1` for the type `Test` +} + +impl Trait2 for Test { + fn foo() {} + //~^ NOTE candidate #2 is defined in an impl of the trait `Trait2` for the type `Test` +} fn main() { - Test::foo() //~ ERROR E0034 + Test::foo() //~ ERROR multiple applicable items in scope + //~| NOTE multiple `foo` found } From 02f081c0b53cad0bcfe1d20ebb892f06ffa996ff Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 29 Aug 2016 11:14:25 +0000 Subject: [PATCH 381/768] Future proof `libsyntax_ext` for `union`. --- src/libsyntax_ext/deriving/bounds.rs | 1 + src/libsyntax_ext/deriving/clone.rs | 1 + src/libsyntax_ext/deriving/cmp/eq.rs | 1 + src/libsyntax_ext/deriving/cmp/ord.rs | 1 + src/libsyntax_ext/deriving/cmp/partial_eq.rs | 1 + src/libsyntax_ext/deriving/cmp/partial_ord.rs | 1 + src/libsyntax_ext/deriving/debug.rs | 1 + src/libsyntax_ext/deriving/decodable.rs | 1 + src/libsyntax_ext/deriving/default.rs | 1 + src/libsyntax_ext/deriving/encodable.rs | 1 + src/libsyntax_ext/deriving/generic/mod.rs | 3 +++ src/libsyntax_ext/deriving/hash.rs | 1 + src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs | 1 + .../run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs | 1 + 14 files changed, 16 insertions(+) diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index cfc98bf36871f..efb2fe5eb3b0f 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -40,6 +40,7 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: true, methods: Vec::new(), associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index ce8ce2209d8c4..f1a3a1f41b14e 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -80,6 +80,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "clone", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 2515435abeb9e..425a47a991bc4 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -50,6 +50,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "assert_receiver_is_total_eq", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 31194b04fa6e4..6b2e36e63b657 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -32,6 +32,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "cmp", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index f70e0cf4ac457..64b8829dad7b1 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -97,6 +97,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: methods, associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 9e9b2f020622f..99d60c43c5457 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -88,6 +88,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, additional_bounds: vec![], generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: methods, associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index a31c695e36049..b974699003b97 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -35,6 +35,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "fmt", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index f395f7bd0c4c4..22b9eb8e75445 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -62,6 +62,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "decode", generics: LifetimeBounds { diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 449c1ff066b3b..b15fd2b49a655 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -32,6 +32,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "default", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 940fdf037711f..a4074184b6e81 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -138,6 +138,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec!( MethodDef { name: "encode", diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index a8b682d81599a..5c636d43a7142 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -228,6 +228,9 @@ pub struct TraitDef<'a> { /// Is it an `unsafe` trait? pub is_unsafe: bool, + /// Can this trait be derived for unions? + pub supports_unions: bool, + pub methods: Vec>, pub associated_types: Vec<(ast::Ident, Ty<'a>)>, diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 81c8e7112dbd5..0941ebca868e3 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -36,6 +36,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "hash", generics: LifetimeBounds { diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 274e430bbea74..6b688b006bd4a 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -49,6 +49,7 @@ fn expand(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), associated_types: vec![], is_unsafe: false, + supports_unions: false, methods: vec![ MethodDef { name: "total_sum", diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 91b4b74797a83..c6174745bfc06 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -51,6 +51,7 @@ fn expand(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), associated_types: vec![], is_unsafe: false, + supports_unions: false, methods: vec![ MethodDef { name: "total_sum", From 34e18175768bc9147f86ed44cd5f6c055468854e Mon Sep 17 00:00:00 2001 From: Cristi Cobzarenco Date: Tue, 30 Aug 2016 11:01:08 +0100 Subject: [PATCH 382/768] add test for #14875 --- src/test/run-pass/issue-14875.rs | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/run-pass/issue-14875.rs diff --git a/src/test/run-pass/issue-14875.rs b/src/test/run-pass/issue-14875.rs new file mode 100644 index 0000000000000..ad19a9be76f88 --- /dev/null +++ b/src/test/run-pass/issue-14875.rs @@ -0,0 +1,43 @@ +// 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. + +// Check that values are not leaked when a dtor panics (#14875) + +use std::panic::{self, UnwindSafe}; + +struct SetInnerOnDrop<'a>(&'a mut bool); + +impl<'a> UnwindSafe for SetInnerOnDrop<'a> {} + +impl<'a> Drop for SetInnerOnDrop<'a> { + fn drop(&mut self) { + *self.0 = true; + } +} + +struct PanicOnDrop; +impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("test panic"); + } +} + + +fn main() { + let mut set_on_drop = false; + { + let set_inner_on_drop = SetInnerOnDrop(&mut set_on_drop); + let _ = panic::catch_unwind(|| { + let _set_inner_on_drop = set_inner_on_drop; + let _panic_on_drop = PanicOnDrop; + }); + } + assert!(set_on_drop); +} From 516519ee9af3235d5a5ed9bb7afa5bb1a27a8ddf Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Mon, 27 Jun 2016 02:34:02 +0200 Subject: [PATCH 383/768] Allow specification of the system V AMD64 ABI constraint. This can be specified using `extern sysV64 fn` on all platforms --- src/doc/book/ffi.md | 1 + src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/abi.rs | 1 + src/libsyntax/abi.rs | 2 ++ 4 files changed, 5 insertions(+) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index ca104ff29ace3..44cc75f8fed1a 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` +* `sysV64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 754910c246d6f..92fe568a72c57 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -42,6 +42,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + X86_64_SysV = 78, X86_64_Win64 = 79, X86_VectorCall = 80 } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36bad..9f3c20a4fd096 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -269,6 +269,7 @@ impl FnType { Vectorcall => llvm::X86_VectorCall, C => llvm::CCallConv, Win64 => llvm::X86_64_Win64, + SysV64 => llvm::X86_64_SysV, // These API constants ought to be more specific... Cdecl => llvm::CCallConv, diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index c959e2108f5a7..9fb2b539b8fe8 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -39,6 +39,7 @@ pub enum Abi { Vectorcall, Aapcs, Win64, + SysV64, // Multiplatform ABIs second Rust, @@ -86,6 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, + AbiData {abi: Abi::SysV64, name: "sysV64" }, // Cross-platform ABIs // From 30c4173cb8f942afbb1588174e5867eb780cdaa0 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Thu, 7 Jul 2016 10:27:30 +0200 Subject: [PATCH 384/768] Change ABI string from sysV64 to sysv64 --- src/doc/book/ffi.md | 2 +- src/libsyntax/abi.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 44cc75f8fed1a..1dea15311ce82 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,7 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` -* `sysV64` +* `sysv64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 9fb2b539b8fe8..64a71133a8c02 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -87,7 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, - AbiData {abi: Abi::SysV64, name: "sysV64" }, + AbiData {abi: Abi::SysV64, name: "sysv64" }, // Cross-platform ABIs // From 0e58a5d139772404ab936b6c7679e9ff936101c4 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 15:14:51 +0200 Subject: [PATCH 385/768] Feature gate the sysv64 abi as feature(abi_sysv64) and add tests --- src/libsyntax/feature_gate.rs | 23 +++- src/test/codegen/abi-sysv64.rs | 24 ++++ .../compile-fail/feature-gate-abi-sysv64.rs | 19 +++ .../run-pass/abi-sysv64-register-usage.rs | 125 ++++++++++++++++++ 4 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/test/codegen/abi-sysv64.rs create mode 100644 src/test/compile-fail/feature-gate-abi-sysv64.rs create mode 100644 src/test/run-pass/abi-sysv64-register-usage.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1e15c1563561c..18924a3dc2535 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -281,7 +281,11 @@ declare_features! ( (active, never_type, "1.13.0", Some(35121)), // Allows all literals in attribute lists and values of key-value pairs. - (active, attr_literals, "1.13.0", Some(34981)) + (active, attr_literals, "1.13.0", Some(34981)), + + // Allows the sysV64 ABI to be specified on all platforms + // instead of just the platforms on which it is the C ABI + (active, abi_sysv64, "1.13.0", None) ); declare_features! ( @@ -811,21 +815,26 @@ macro_rules! gate_feature_post { impl<'a> PostExpansionVisitor<'a> { fn check_abi(&self, abi: Abi, span: Span) { match abi { - Abi::RustIntrinsic => + Abi::RustIntrinsic => { gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"), + "intrinsics are subject to change"); + }, Abi::PlatformIntrinsic => { gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy") + "platform intrinsics are experimental and possibly buggy"); }, Abi::Vectorcall => { gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change") - } + "vectorcall is experimental and subject to change"); + }, Abi::RustCall => { gate_feature_post!(&self, unboxed_closures, span, "rust-call ABI is subject to change"); - } + }, + Abi::SysV64 => { + gate_feature_post!(&self, abi_sysv64, span, + "sysv64 ABI is experimental and subject to change"); + }, _ => {} } } diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs new file mode 100644 index 0000000000000..2b8e8a1b6b2c7 --- /dev/null +++ b/src/test/codegen/abi-sysv64.rs @@ -0,0 +1,24 @@ +// 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. + +// Checks if the correct annotation for the sysv64 ABI is passed to +// llvm. Also checks that the abi-sysv64 feature gate allows usage +// of the sysv64 abi. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(abi_sysv64)] + +// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi +#[no_mangle] +pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { + a * 2 +} diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs new file mode 100644 index 0000000000000..2a4aae8c06bba --- /dev/null +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -0,0 +1,19 @@ +// 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. + +// Test that the sysv64 ABI cannot be used when abi-sysv64 feature +// gate is not used. + +extern "sysv64" fn foo() {} +//~^ ERROR sysv64 ABI is experimental and subject to change + +fn main() { + foo(); +} diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs new file mode 100644 index 0000000000000..5e58240359e6c --- /dev/null +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -0,0 +1,125 @@ +// 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. + +// Checks if the correct registers are being used to pass arguments +// when the sysv64 ABI is specified. + +#![feature(abi_sysv64)] +#![feature(naked_functions)] +#![feature(asm)] + +#[naked] +#[inline(never)] +#[allow(unused_variables)] +pub unsafe extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + // this assembly checks all registers for specific values, and puts in rax + // how many values were correct. + asm!("cmp rdi, 0x1; + xor rax, rax; + setz al; + + cmp rsi, 0x2; + xor rdi, rdi + setz dil; + add rax, rdi; + + cmp rdx, 0x3; + setz dil; + add rax, rdi; + + cmp rcx, 0x4; + setz dil; + add rax, rdi; + + cmp r8, 0x5; + setz dil; + add rax, rdi; + + cmp r9, 0x6; + setz dil; + add rax, rdi; + + movd esi, xmm0; + cmp rsi, 0x3F800000; + setz dil; + add rax, rdi; + + movd esi, xmm1; + cmp rsi, 0x40000000; + setz dil; + add rax, rdi; + + movd esi, xmm2; + cmp rsi, 0x40800000; + setz dil; + add rax, rdi; + + movd esi, xmm3; + cmp rsi, 0x41000000; + setz dil; + add rax, rdi; + + movd esi, xmm4; + cmp rsi, 0x41800000; + setz dil; + add rax, rdi; + + movd esi, xmm5; + cmp rsi, 0x42000000; + setz dil; + add rax, rdi; + + movd esi, xmm6; + cmp rsi, 0x42800000; + setz dil; + add rax, rdi; + + movd esi, xmm7; + cmp rsi, 0x43000000; + setz dil; + add rax, rdi; + ret + " :::: "intel"); + unreachable!(); +} + +// this struct contains 8 i64's, while only 6 can be passed in registers. +#[derive(PartialEq, Eq, Debug)] +pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); + +#[inline(never)] +pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { + foo.0 *= 1; + foo.1 *= 2; + foo.2 *= 3; + foo.3 *= 4; + foo.4 *= 5; + foo.5 *= 6; + foo.6 *= 7; + foo.7 *= 8; + foo +} + +pub fn main() { + assert_eq!(unsafe { + all_the_registers(1, 2, 3, 4, 5, 6, + 1.0, 2.0, 4.0, 8.0, + 16.0, 32.0, 64.0, 128.0) + }, 14); + + assert_eq!( + large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), + LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) + ); +} From eef4434bf8ebcf2f9377166ff069656a1708586d Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 19:45:15 +0200 Subject: [PATCH 386/768] Add the sysv64 calling convention to the list of known calling conventions and add the feature(abi_sysv64) to the list of known features --- src/doc/reference.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index be3559a588089..ec2d3e2822e20 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings: * `extern "cdecl"` -- The default for x86\_32 C code. * `extern "stdcall"` -- The default for the Win32 API on x86\_32. * `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "sysv64"` -- The default for C code on non-Windows x86\_64. * `extern "aapcs"` -- The default for ARM. * `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's `__fastcall` and GCC and clang's `__attribute__((fastcall))` @@ -2485,6 +2486,9 @@ The currently implemented features of the reference compiler are: * - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. +* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention + (e.g. `extern "sysv64" func fn_();`) + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a From 0e30446259be88af7b9ae6c733b49fc0c88bd7ce Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Tue, 30 Aug 2016 03:54:29 +0200 Subject: [PATCH 387/768] Select the proper x86_64 ABI based first and foremost on the specified calling convention instead of just looking at the selected platform --- src/librustc_trans/abi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 9f3c20a4fd096..7f209dde27db9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -484,7 +484,9 @@ impl FnType { match &ccx.sess().target.target.arch[..] { "x86" => cabi_x86::compute_abi_info(ccx, self), - "x86_64" => if ccx.sess().target.target.options.is_like_windows { + "x86_64" => if abi == Abi::SysV64 { + cabi_x86_64::compute_abi_info(ccx, self); + } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows { cabi_x86_win64::compute_abi_info(ccx, self); } else { cabi_x86_64::compute_abi_info(ccx, self); From d282a633fa6f511f087a53976ce71c269d14c861 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 20:29:14 +0200 Subject: [PATCH 388/768] Guard against platforms on which the sysv64 calling convention is not valid in non-codegen tests. Remove false positive in a test that relied on the exact formatting of an error string and rewrite the sysv64 register allocation test at it was triggering undefined behaviour --- .../compile-fail/feature-gate-abi-sysv64.rs | 6 + .../run-pass/abi-sysv64-register-usage.rs | 147 ++++++++---------- src/test/ui/codemap_tests/unicode.stderr | 2 +- 3 files changed, 71 insertions(+), 84 deletions(-) diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs index 2a4aae8c06bba..d7c012743231b 100644 --- a/src/test/compile-fail/feature-gate-abi-sysv64.rs +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -11,9 +11,15 @@ // Test that the sysv64 ABI cannot be used when abi-sysv64 feature // gate is not used. +// ignore-android +// ignore-arm +// ignore-aarch64 + +#[cfg(target_arch = "x86_64")] extern "sysv64" fn foo() {} //~^ ERROR sysv64 ABI is experimental and subject to change +#[cfg(target_arch = "x86_64")] fn main() { foo(); } diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs index 5e58240359e6c..7e3b32122ac23 100644 --- a/src/test/run-pass/abi-sysv64-register-usage.rs +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -11,93 +11,42 @@ // Checks if the correct registers are being used to pass arguments // when the sysv64 ABI is specified. +// ignore-android +// ignore-arm +// ignore-aarch64 + #![feature(abi_sysv64)] -#![feature(naked_functions)] #![feature(asm)] -#[naked] -#[inline(never)] -#[allow(unused_variables)] -pub unsafe extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, - rcx: i64, r8 : i64, r9 : i64, - xmm0: f32, xmm1: f32, xmm2: f32, - xmm3: f32, xmm4: f32, xmm5: f32, - xmm6: f32, xmm7: f32) -> i64 { - // this assembly checks all registers for specific values, and puts in rax - // how many values were correct. - asm!("cmp rdi, 0x1; - xor rax, rax; - setz al; - - cmp rsi, 0x2; - xor rdi, rdi - setz dil; - add rax, rdi; - - cmp rdx, 0x3; - setz dil; - add rax, rdi; - - cmp rcx, 0x4; - setz dil; - add rax, rdi; - - cmp r8, 0x5; - setz dil; - add rax, rdi; - - cmp r9, 0x6; - setz dil; - add rax, rdi; - - movd esi, xmm0; - cmp rsi, 0x3F800000; - setz dil; - add rax, rdi; - - movd esi, xmm1; - cmp rsi, 0x40000000; - setz dil; - add rax, rdi; - - movd esi, xmm2; - cmp rsi, 0x40800000; - setz dil; - add rax, rdi; - - movd esi, xmm3; - cmp rsi, 0x41000000; - setz dil; - add rax, rdi; - - movd esi, xmm4; - cmp rsi, 0x41800000; - setz dil; - add rax, rdi; - - movd esi, xmm5; - cmp rsi, 0x42000000; - setz dil; - add rax, rdi; - - movd esi, xmm6; - cmp rsi, 0x42800000; - setz dil; - add rax, rdi; - - movd esi, xmm7; - cmp rsi, 0x43000000; - setz dil; - add rax, rdi; - ret - " :::: "intel"); - unreachable!(); +#[cfg(target_arch = "x86_64")] +pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + assert_eq!(rdi, 1); + assert_eq!(rsi, 2); + assert_eq!(rdx, 3); + assert_eq!(rcx, 4); + assert_eq!(r8, 5); + assert_eq!(r9, 6); + assert_eq!(xmm0, 1.0f32); + assert_eq!(xmm1, 2.0f32); + assert_eq!(xmm2, 4.0f32); + assert_eq!(xmm3, 8.0f32); + assert_eq!(xmm4, 16.0f32); + assert_eq!(xmm5, 32.0f32); + assert_eq!(xmm6, 64.0f32); + assert_eq!(xmm7, 128.0f32); + 42 } // this struct contains 8 i64's, while only 6 can be passed in registers. +#[cfg(target_arch = "x86_64")] #[derive(PartialEq, Eq, Debug)] pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); +#[cfg(target_arch = "x86_64")] #[inline(never)] pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { foo.0 *= 1; @@ -111,15 +60,47 @@ pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct foo } +#[cfg(target_arch = "x86_64")] pub fn main() { - assert_eq!(unsafe { - all_the_registers(1, 2, 3, 4, 5, 6, - 1.0, 2.0, 4.0, 8.0, - 16.0, 32.0, 64.0, 128.0) - }, 14); + let result: i64; + unsafe { + asm!("mov rdi, 1; + mov rsi, 2; + mov rdx, 3; + mov rcx, 4; + mov r8, 5; + mov r9, 6; + mov eax, 0x3F800000; + movd xmm0, eax; + mov eax, 0x40000000; + movd xmm1, eax; + mov eax, 0x40800000; + movd xmm2, eax; + mov eax, 0x41000000; + movd xmm3, eax; + mov eax, 0x41800000; + movd xmm4, eax; + mov eax, 0x42000000; + movd xmm5, eax; + mov eax, 0x42800000; + movd xmm6, eax; + mov eax, 0x43000000; + movd xmm7, eax; + call r10 + " + : "={rax}"(result) + : "{r10}"(all_the_registers as usize) + : "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory" + : "intel", "alignstack" + ) + } + assert_eq!(result, 42); assert_eq!( large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) ); } + +#[cfg(not(target_arch = "x86_64"))] +pub fn main() {} \ No newline at end of file diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index aa42ae341c545..a748e13ecf102 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,4 +1,4 @@ -error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} From 46a719e2ccc03f22537b1a3ce9e345770ca4e1ba Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Tue, 30 Aug 2016 03:24:34 +0200 Subject: [PATCH 389/768] Remove useless //ignore-arch directives on a compile-fail test, and add another test that checks if the sysv64 abi corresponds to the same rules as the C abi on unix platforms --- .../compile-fail/feature-gate-abi-sysv64.rs | 6 - src/test/run-pass/abi-sysv64-arg-passing.rs | 341 ++++++++++++++++++ 2 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/abi-sysv64-arg-passing.rs diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs index d7c012743231b..2a4aae8c06bba 100644 --- a/src/test/compile-fail/feature-gate-abi-sysv64.rs +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -11,15 +11,9 @@ // Test that the sysv64 ABI cannot be used when abi-sysv64 feature // gate is not used. -// ignore-android -// ignore-arm -// ignore-aarch64 - -#[cfg(target_arch = "x86_64")] extern "sysv64" fn foo() {} //~^ ERROR sysv64 ABI is experimental and subject to change -#[cfg(target_arch = "x86_64")] fn main() { foo(); } diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs new file mode 100644 index 0000000000000..3f6ae71ffa8e7 --- /dev/null +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -0,0 +1,341 @@ +// 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. + +// Checks if the "sysv64" calling convention behaves the same as the +// "C" calling convention on platforms where both should be the same + +// This file contains versions of the following run-pass tests with +// the calling convention changed to "sysv64" + +// cabi-int-widening +// extern-pass-char +// extern-pass-u32 +// extern-pass-u64 +// extern-pass-double +// extern-pass-empty +// extern-pass-TwoU8s +// extern-pass-TwoU16s +// extern-pass-TwoU32s +// extern-pass-TwoU64s +// extern-return-TwoU8s +// extern-return-TwoU16s +// extern-return-TwoU32s +// extern-return-TwoU64s +// foreign-fn-with-byval +// issue-28676 +// struct-return + +// ignore-android +// ignore-arm +// ignore-aarch64 +// ignore-msvc + +// note: msvc is ignored as rust_test_helpers does not have the sysv64 abi on msvc + +#![feature(abi_sysv64)] +#[allow(dead_code)] +#[allow(improper_ctypes)] + +#[cfg(target_arch = "x86_64")] +mod tests { + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU8s { + one: u8, two: u8 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU16s { + one: u16, two: u16 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU32s { + one: u32, two: u32 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU64s { + one: u64, two: u64 + } + + #[repr(C)] + pub struct ManyInts { + arg1: i8, + arg2: i16, + arg3: i32, + arg4: i16, + arg5: i8, + arg6: TwoU8s, + } + + #[repr(C)] + pub struct Empty; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct S { + x: u64, + y: u64, + z: u64, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Floats { a: f64, b: u8, c: f64 } + + #[link(name = "rust_test_helpers")] + extern "sysv64" { + pub fn rust_int8_to_int32(_: i8) -> i32; + pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; + pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; + pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; + pub fn rust_dbg_extern_identity_double(v: f64) -> f64; + pub fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts); + pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; + pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; + pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; + pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; + pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; + pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; + pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; + pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; + pub fn get_x(x: S) -> u64; + pub fn get_y(x: S) -> u64; + pub fn get_z(x: S) -> u64; + pub fn get_c_many_params(_: *const (), _: *const (), + _: *const (), _: *const (), f: Quad) -> u64; + pub fn rust_dbg_abi_1(q: Quad) -> Quad; + pub fn rust_dbg_abi_2(f: Floats) -> Floats; + } + + pub fn cabi_int_widening() { + let x = unsafe { + rust_int8_to_int32(-1) + }; + + assert!(x == -1); + } + + pub fn extern_pass_char() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u8(22)); + } + } + + pub fn extern_pass_u32() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u32(22)); + } + } + + pub fn extern_pass_u64() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u64(22)); + } + } + + pub fn extern_pass_double() { + unsafe { + assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64)); + } + } + + pub fn extern_pass_empty() { + unsafe { + let x = ManyInts { + arg1: 2, + arg2: 3, + arg3: 4, + arg4: 5, + arg5: 6, + arg6: TwoU8s { one: 7, two: 8, } + }; + let y = ManyInts { + arg1: 1, + arg2: 2, + arg3: 3, + arg4: 4, + arg5: 5, + arg6: TwoU8s { one: 6, two: 7, } + }; + let empty = Empty; + rust_dbg_extern_empty_struct(x, empty, y); + } + } + + pub fn extern_pass_twou8s() { + unsafe { + let x = TwoU8s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU8s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou16s() { + unsafe { + let x = TwoU16s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU16s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou32s() { + unsafe { + let x = TwoU32s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU32s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou64s() { + unsafe { + let x = TwoU64s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU64s(x); + assert_eq!(x, y); + } + } + + pub fn extern_return_twou8s() { + unsafe { + let y = rust_dbg_extern_return_TwoU8s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou16s() { + unsafe { + let y = rust_dbg_extern_return_TwoU16s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou32s() { + unsafe { + let y = rust_dbg_extern_return_TwoU32s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou64s() { + unsafe { + let y = rust_dbg_extern_return_TwoU64s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + #[inline(never)] + fn indirect_call(func: unsafe extern "sysv64" fn(s: S) -> u64, s: S) -> u64 { + unsafe { + func(s) + } + } + + pub fn foreign_fn_with_byval() { + let s = S { x: 1, y: 2, z: 3 }; + assert_eq!(s.x, indirect_call(get_x, s)); + assert_eq!(s.y, indirect_call(get_y, s)); + assert_eq!(s.z, indirect_call(get_z, s)); + } + + fn test() { + use std::ptr; + unsafe { + let null = ptr::null(); + let q = Quad { + a: 1, + b: 2, + c: 3, + d: 4 + }; + assert_eq!(get_c_many_params(null, null, null, null, q), q.c); + } + } + + pub fn issue_28676() { + test(); + } + + fn test1() { + unsafe { + let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa, + b: 0xbbbb_bbbb_bbbb_bbbb, + c: 0xcccc_cccc_cccc_cccc, + d: 0xdddd_dddd_dddd_dddd }; + let qq = rust_dbg_abi_1(q); + println!("a: {:x}", qq.a as usize); + println!("b: {:x}", qq.b as usize); + println!("c: {:x}", qq.c as usize); + println!("d: {:x}", qq.d as usize); + assert_eq!(qq.a, q.c + 1); + assert_eq!(qq.b, q.d - 1); + assert_eq!(qq.c, q.a + 1); + assert_eq!(qq.d, q.b - 1); + } + } + + fn test2() { + unsafe { + let f = Floats { a: 1.234567890e-15_f64, + b: 0b_1010_1010, + c: 1.0987654321e-15_f64 }; + let ff = rust_dbg_abi_2(f); + println!("a: {}", ff.a as f64); + println!("b: {}", ff.b as usize); + println!("c: {}", ff.c as f64); + assert_eq!(ff.a, f.c + 1.0f64); + assert_eq!(ff.b, 0xff); + assert_eq!(ff.c, f.a - 1.0f64); + } + } + + pub fn struct_return() { + test1(); + test2(); + } +} + +#[cfg(target_arch = "x86_64")] +fn main() { + use tests::*; + cabi_int_widening(); + extern_pass_char(); + extern_pass_u32(); + extern_pass_u64(); + extern_pass_double(); + extern_pass_empty(); + extern_pass_twou8s(); + extern_pass_twou16s(); + extern_pass_twou32s(); + extern_pass_twou64s(); + extern_return_twou8s(); + extern_return_twou16s(); + extern_return_twou32s(); + extern_return_twou64s(); + foreign_fn_with_byval(); + issue_28676(); + struct_return(); +} + +#[cfg(not(target_arch = "x86_64"))] +fn main() { + +} From 77cd09a88cd21f22865287025dafc1252856c5d9 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Tue, 30 Aug 2016 10:21:27 +0530 Subject: [PATCH 390/768] Update E0520 to new error format Fixes #36112. Part of #35233. r? @jonathandturner --- src/librustc_typeck/check/mod.rs | 12 ++++++++---- src/test/compile-fail/E0520.rs | 6 +++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8f2dc42726696..e73c3e2de5320 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -903,14 +903,18 @@ fn report_forbidden_specialization<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let mut err = struct_span_err!( tcx.sess, impl_item.span, E0520, - "item `{}` is provided by an `impl` that specializes \ - another, but the item in the parent `impl` is not \ - marked `default` and so it cannot be specialized.", + "`{}` specializes an item from a parent `impl`, but \ + neither that item nor the `impl` are marked `default`", impl_item.name); + err.span_label(impl_item.span, &format!("cannot specialize default item `{}`", + impl_item.name)); match tcx.span_of_impl(parent_impl) { Ok(span) => { - err.span_note(span, "parent implementation is here:"); + err.span_label(span, &"parent `impl` is here"); + err.note(&format!("to specialize, either the parent `impl` or `{}` \ + in the parent `impl` must be marked `default`", + impl_item.name)); } Err(cname) => { err.note(&format!("parent implementation is in crate `{}`", cname)); diff --git a/src/test/compile-fail/E0520.rs b/src/test/compile-fail/E0520.rs index bb52843ee7835..0bb8faea62e1e 100644 --- a/src/test/compile-fail/E0520.rs +++ b/src/test/compile-fail/E0520.rs @@ -19,11 +19,15 @@ impl SpaceLlama for T { } impl SpaceLlama for T { +//~^ NOTE parent `impl` is here fn fly(&self) {} } impl SpaceLlama for i32 { - default fn fly(&self) {} //~ ERROR E0520 + default fn fly(&self) {} + //~^ ERROR E0520 + //~| NOTE cannot specialize default item `fly` + //~| NOTE either the parent `impl` or `fly` in the parent `impl` must be marked `default` } fn main() { From bab60124a5069ae6be3591ee43632de8b848c5fd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 30 Aug 2016 10:21:33 -0500 Subject: [PATCH 391/768] rustbuild: fix building std for musl targets closes #36143 --- src/bootstrap/compile.rs | 6 +++--- src/libstd/build.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 155848901cdb4..6b3b5cf8cda76 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -93,16 +93,16 @@ pub fn std_link(build: &Build, add_to_sysroot(&out_dir, &libdir); if target.contains("musl") && !target.contains("mips") { - copy_third_party_objects(build, target, &libdir); + copy_third_party_objects(build, &libdir); } } /// Copies the crt(1,i,n).o startup objects /// /// Only required for musl targets that statically link to libc -fn copy_third_party_objects(build: &Build, target: &str, into: &Path) { +fn copy_third_party_objects(build: &Build, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { - copy(&compiler_file(build.cc(target), obj), &into.join(obj)); + copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj)); } } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9018e48d06bd1..535ce53a0fbd9 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -35,7 +35,7 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else { + } else if !target.contains("musl") { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=pthread"); From 8f8d88290be865f411afed0fb1132af1959362a9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 30 Aug 2016 10:25:43 -0500 Subject: [PATCH 392/768] for mips-musl pass -ldl and co to the linker --- src/libstd/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 535ce53a0fbd9..2d540c6b59ac0 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -35,7 +35,7 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") { + } else if !target.contains("musl") || target.contains("mips") { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=pthread"); From 150599d01d2d8f8ec410ac6509478084ee920eb4 Mon Sep 17 00:00:00 2001 From: ggomez Date: Tue, 30 Aug 2016 12:54:51 +0200 Subject: [PATCH 393/768] Add E0530 error explanation --- src/librustc_resolve/diagnostics.rs | 38 +++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 5183d68065c7d..f8f90bdb4e7f5 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1270,7 +1270,42 @@ trait Foo {} impl Foo for i32 {} ``` -"## +"##, + +E0530: r##" +A binding shadowed something it shouldn't. + +Erroneous code example: + +```compile_fail,E0530 +static TEST: i32 = 0; + +let r: (i32, i32) = (0, 0); +match r { + TEST => {} // error: match bindings cannot shadow statics +} +``` + +To fix this error, just change the binding's name in order to avoid shadowing +one of the following: + +* struct name +* struct/enum variant +* static +* const +* associated const + +Fixed example: + +``` +static TEST: i32 = 0; + +let r: (i32, i32) = (0, 0); +match r { + something => {} // ok! +} +``` +"##, } @@ -1289,7 +1324,6 @@ register_diagnostics! { // E0419, merged into 531 // E0420, merged into 532 // E0421, merged into 531 - E0530, // X bindings cannot shadow Ys E0531, // unresolved pattern path kind `name` E0532, // expected pattern path kind, found another pattern path kind // E0427, merged into 530 From 37bf449de4ff1d6519b577d014fbe17ccdce29b9 Mon Sep 17 00:00:00 2001 From: ggomez Date: Tue, 30 Aug 2016 13:13:37 +0200 Subject: [PATCH 394/768] Add new error code tests --- src/test/compile-fail/E0528.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0529.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0530.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0534.rs | 14 ++++++++++++++ src/test/compile-fail/E0535.rs | 14 ++++++++++++++ src/test/compile-fail/E0536.rs | 14 ++++++++++++++ src/test/compile-fail/E0537.rs | 14 ++++++++++++++ src/test/compile-fail/E0558.rs | 14 ++++++++++++++ src/test/compile-fail/E0559.rs | 17 +++++++++++++++++ src/test/compile-fail/E560.rs | 17 +++++++++++++++++ 10 files changed, 160 insertions(+) create mode 100644 src/test/compile-fail/E0528.rs create mode 100644 src/test/compile-fail/E0529.rs create mode 100644 src/test/compile-fail/E0530.rs create mode 100644 src/test/compile-fail/E0534.rs create mode 100644 src/test/compile-fail/E0535.rs create mode 100644 src/test/compile-fail/E0536.rs create mode 100644 src/test/compile-fail/E0537.rs create mode 100644 src/test/compile-fail/E0558.rs create mode 100644 src/test/compile-fail/E0559.rs create mode 100644 src/test/compile-fail/E560.rs diff --git a/src/test/compile-fail/E0528.rs b/src/test/compile-fail/E0528.rs new file mode 100644 index 0000000000000..27187bb5aba08 --- /dev/null +++ b/src/test/compile-fail/E0528.rs @@ -0,0 +1,19 @@ +// 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. + +#![feature(slice_patterns)] + +fn main() { + let r = &[1, 2]; + match r { + &[a, b, c, rest..] => { //~ ERROR E0528 + } + } +} diff --git a/src/test/compile-fail/E0529.rs b/src/test/compile-fail/E0529.rs new file mode 100644 index 0000000000000..488fe7c7763ae --- /dev/null +++ b/src/test/compile-fail/E0529.rs @@ -0,0 +1,19 @@ +// 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. + +#![feature(slice_patterns)] + +fn main() { + let r: f32 = 1.0; + match r { + [a, b] => { //~ ERROR E0529 + } + } +} diff --git a/src/test/compile-fail/E0530.rs b/src/test/compile-fail/E0530.rs new file mode 100644 index 0000000000000..4f674d0e67106 --- /dev/null +++ b/src/test/compile-fail/E0530.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + static TEST: i32 = 0; + + let r: (i32, i32) = (0, 0); + match r { + TEST => {} //~ ERROR E0530 + } +} diff --git a/src/test/compile-fail/E0534.rs b/src/test/compile-fail/E0534.rs new file mode 100644 index 0000000000000..8c036e6076d1d --- /dev/null +++ b/src/test/compile-fail/E0534.rs @@ -0,0 +1,14 @@ +// 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. + +#[inline()] //~ ERROR E0534 +pub fn something() {} + +fn main() {} diff --git a/src/test/compile-fail/E0535.rs b/src/test/compile-fail/E0535.rs new file mode 100644 index 0000000000000..17558cc05c612 --- /dev/null +++ b/src/test/compile-fail/E0535.rs @@ -0,0 +1,14 @@ +// 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. + +#[inline(unknown)] //~ ERROR E0535 +pub fn something() {} + +fn main() {} diff --git a/src/test/compile-fail/E0536.rs b/src/test/compile-fail/E0536.rs new file mode 100644 index 0000000000000..127bdc258d947 --- /dev/null +++ b/src/test/compile-fail/E0536.rs @@ -0,0 +1,14 @@ +// 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. + +#[cfg(not())] //~ ERROR E0536 +pub fn something() {} + +pub fn main() {} diff --git a/src/test/compile-fail/E0537.rs b/src/test/compile-fail/E0537.rs new file mode 100644 index 0000000000000..497936fbcd28e --- /dev/null +++ b/src/test/compile-fail/E0537.rs @@ -0,0 +1,14 @@ +// 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. + +#[cfg(unknown())] //~ ERROR E0537 +pub fn something() {} + +pub fn main() {} diff --git a/src/test/compile-fail/E0558.rs b/src/test/compile-fail/E0558.rs new file mode 100644 index 0000000000000..4ab0506a9c0cd --- /dev/null +++ b/src/test/compile-fail/E0558.rs @@ -0,0 +1,14 @@ +// 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. + +#[export_name] //~ ERROR E0558 +pub fn something() {} + +fn main() {} diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs new file mode 100644 index 0000000000000..80eeb203a850e --- /dev/null +++ b/src/test/compile-fail/E0559.rs @@ -0,0 +1,17 @@ +// 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. + +enum Field { + Fool { x: u32 }, +} + +fn main() { + let s = Field::Fool { joke: 0 }; //~ ERROR E0559 +} diff --git a/src/test/compile-fail/E560.rs b/src/test/compile-fail/E560.rs new file mode 100644 index 0000000000000..ec9b86ee1f00f --- /dev/null +++ b/src/test/compile-fail/E560.rs @@ -0,0 +1,17 @@ +// 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. + +struct Simba { + mother: u32, +} + +fn main() { + let s = Simba { mother: 1, father: 0 }; //~ ERROR E0560 +} From f48d3859bc90e6e8a2e5455845b13d55bb8720ab Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 29 Aug 2016 07:17:27 -0400 Subject: [PATCH 395/768] Implement `Debug` for `std::path::Components`. --- src/libstd/path.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 67219b6fd1b9c..791b7b2288d5d 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -639,6 +639,25 @@ pub struct Iter<'a> { inner: Components<'a>, } +#[stable(feature = "path_components_debug", since = "1.13.0")] +impl<'a> fmt::Debug for Components<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct DebugHelper<'a>(&'a Path); + + impl<'a> fmt::Debug for DebugHelper<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.0.components()) + .finish() + } + } + + f.debug_tuple("Components") + .field(&DebugHelper(self.as_path())) + .finish() + } +} + impl<'a> Components<'a> { // how long is the prefix, if any? #[inline] @@ -3483,4 +3502,25 @@ mod tests { ); } } + + #[test] + fn test_components_debug() { + let path = Path::new("/tmp"); + + let mut components = path.components(); + + let expected = "Components([RootDir, Normal(\"tmp\")])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + + let _ = components.next().unwrap(); + let expected = "Components([Normal(\"tmp\")])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + + let _ = components.next().unwrap(); + let expected = "Components([])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + } } From dd72b6b91f88b82f1f564ca6dfeec621bd6fa3ec Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 30 Aug 2016 00:03:29 +0300 Subject: [PATCH 396/768] fix broken type parameter indexing logic in wfcheck Fixes #36075 --- src/librustc/ty/mod.rs | 9 ++++-- src/librustc_typeck/check/wfcheck.rs | 31 ++++++------------- src/librustc_typeck/collect.rs | 24 ++++++-------- .../constrained_type_params.rs | 24 +++++++++----- src/test/run-pass/issue-36075.rs | 22 +++++++++++++ 5 files changed, 65 insertions(+), 45 deletions(-) create mode 100644 src/test/run-pass/issue-36075.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 759dc30037210..4b2af26bb8d99 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -717,11 +717,16 @@ pub struct RegionParameterDef<'tcx> { impl<'tcx> RegionParameterDef<'tcx> { pub fn to_early_bound_region(&self) -> ty::Region { - ty::ReEarlyBound(ty::EarlyBoundRegion { + ty::ReEarlyBound(self.to_early_bound_region_data()) + } + + pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { + ty::EarlyBoundRegion { index: self.index, name: self.name, - }) + } } + pub fn to_bound_region(&self) -> ty::BoundRegion { // this is an early bound region, so unaffected by #32330 ty::BoundRegion::BrNamed(self.def_id, self.name, Issue32330::WontChange) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6b6a688bf1d18..e90b0ad32c9a2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -457,44 +457,31 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let variances = self.tcx().item_variances(item_def_id); let mut constrained_parameters: FnvHashSet<_> = - variances[ast_generics.lifetimes.len()..] - .iter().enumerate() + variances.iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) - .map(|(index, _)| self.param_ty(ast_generics, index)) - .map(|p| Parameter::Type(p)) + .map(|(index, _)| Parameter(index as u32)) .collect(); identify_constrained_type_params(ty_predicates.predicates.as_slice(), None, &mut constrained_parameters); - for (index, &variance) in variances.iter().enumerate() { - let (span, name) = if index < ast_generics.lifetimes.len() { - if variance != ty::Bivariant { - continue; - } + for (index, _) in variances.iter().enumerate() { + if constrained_parameters.contains(&Parameter(index as u32)) { + continue; + } + let (span, name) = if index < ast_generics.lifetimes.len() { (ast_generics.lifetimes[index].lifetime.span, ast_generics.lifetimes[index].lifetime.name) } else { - let index = index - ast_generics.lifetimes.len(); - let param_ty = self.param_ty(ast_generics, index); - if constrained_parameters.contains(&Parameter::Type(param_ty)) { - continue; - } - (ast_generics.ty_params[index].span, param_ty.name) + (ast_generics.ty_params[index].span, + ast_generics.ty_params[index].name) }; self.report_bivariance(span, name); } } - fn param_ty(&self, ast_generics: &hir::Generics, index: usize) -> ty::ParamTy { - ty::ParamTy { - idx: index as u32, - name: ast_generics.ty_params[index].name - } - } - fn report_bivariance(&self, span: Span, param_name: ast::Name) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 30b9d15587069..0097991210d83 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2158,7 +2158,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generics = generics_of_def_id(ccx, impl_def_id); for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) { let param_ty = ty::ParamTy::for_def(ty_param); - if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { + if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); } } @@ -2189,23 +2189,19 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None }) .flat_map(|ty| ctp::parameters_for(&ty, true)) - .filter_map(|p| match p { - ctp::Parameter::Type(_) => None, - ctp::Parameter::Region(r) => Some(r), - }) .collect(); - for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() { - let region = ty::EarlyBoundRegion { - index: index as u32, - name: lifetime_def.lifetime.name - }; + for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() + .zip(&ast_generics.lifetimes) + { + let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); + if - lifetimes_in_associated_types.contains(®ion) && // (*) - !input_parameters.contains(&ctp::Parameter::Region(region)) + lifetimes_in_associated_types.contains(¶m) && // (*) + !input_parameters.contains(¶m) { - report_unused_parameter(ccx, lifetime_def.lifetime.span, - "lifetime", ®ion.name.to_string()); + report_unused_parameter(ccx, lifetime.lifetime.span, + "lifetime", &lifetime.lifetime.name.to_string()); } } diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 9e5c3a5d575bf..39f9e4316b9c7 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -13,9 +13,14 @@ use rustc::ty::fold::{TypeFoldable, TypeVisitor}; use rustc::util::nodemap::FnvHashSet; #[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum Parameter { - Type(ty::ParamTy), - Region(ty::EarlyBoundRegion), +pub struct Parameter(pub u32); + +impl From for Parameter { + fn from(param: ty::ParamTy) -> Self { Parameter(param.idx) } +} + +impl From for Parameter { + fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } } /// If `include_projections` is false, returns the list of parameters that are @@ -49,8 +54,8 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { // projections are not injective return false; } - ty::TyParam(ref d) => { - self.parameters.push(Parameter::Type(d.clone())); + ty::TyParam(data) => { + self.parameters.push(Parameter::from(data)); } _ => {} } @@ -61,7 +66,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { match *r { ty::ReEarlyBound(data) => { - self.parameters.push(Parameter::Region(data)); + self.parameters.push(Parameter::from(data)); } _ => {} } @@ -141,13 +146,15 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> // * ::Item = T // * T: Debug // * U: Iterator + debug!("setup_constraining_predicates: predicates={:?} \ + impl_trait_ref={:?} input_parameters={:?}", + predicates, impl_trait_ref, input_parameters); let mut i = 0; let mut changed = true; while changed { changed = false; for j in i..predicates.len() { - if let ty::Predicate::Projection(ref poly_projection) = predicates[j] { // Note that we can skip binder here because the impl // trait ref never contains any late-bound regions. @@ -181,5 +188,8 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> i += 1; changed = true; } + debug!("setup_constraining_predicates: predicates={:?} \ + i={} impl_trait_ref={:?} input_parameters={:?}", + predicates, i, impl_trait_ref, input_parameters); } } diff --git a/src/test/run-pass/issue-36075.rs b/src/test/run-pass/issue-36075.rs new file mode 100644 index 0000000000000..fe399e10c1c3f --- /dev/null +++ b/src/test/run-pass/issue-36075.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. + +trait DeclarationParser { + type Declaration; +} + +struct DeclarationListParser<'i, I, P> + where P: DeclarationParser +{ + input: &'i (), + parser: P +} + +fn main() {} From bdfcd782bc3fe3d59bd584684c13aca3daa7f562 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Sun, 28 Aug 2016 17:55:07 +0200 Subject: [PATCH 397/768] Update E0318 to new format --- src/librustc_typeck/coherence/orphan.rs | 10 +++++++--- .../typeck-default-trait-impl-outside-crate.rs | 5 ++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index a3c043fe7cbd3..bcce64cb110c6 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -347,15 +347,19 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { return; } } - hir::ItemDefaultImpl(..) => { + hir::ItemDefaultImpl(_, ref item_trait_ref) => { // "Trait" impl debug!("coherence2::orphan check: default trait impl {}", self.tcx.map.node_to_string(item.id)); let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); if trait_ref.def_id.krate != LOCAL_CRATE { - span_err!(self.tcx.sess, item.span, E0318, + struct_span_err!(self.tcx.sess, item_trait_ref.path.span, E0318, "cannot create default implementations for traits outside the \ - crate they're defined in; define a new trait instead"); + crate they're defined in; define a new trait instead") + .span_label(item_trait_ref.path.span, + &format!("`{}` trait not defined in this crate", + item_trait_ref.path)) + .emit(); return; } } diff --git a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs index 09b97dfb30f24..4d71517e06058 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs @@ -10,7 +10,6 @@ #![feature(optin_builtin_traits)] -impl Copy for .. {} -//~^ ERROR E0318 - +impl Copy for .. {} //~ ERROR E0318 + //~^ NOTE `Copy` trait not defined in this crate fn main() {} From 8ca9fa11f9a04a7ffa4cded6775336d55268e7ac Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Tue, 23 Aug 2016 11:23:42 -0400 Subject: [PATCH 398/768] add evocative examples for `BitOr` and `BitXor` These are exactly equivalent to PR #35809, with one caveat: I do not believe there is a non-bitwise binary "xor" operator in Rust, so here it's expressed as (a || b) && !(a && b). r? @GuillaumeGomez improved documentation a la PR #35993 --- src/libcore/ops.rs | 99 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 18 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 282f281047e47..f551357341d3e 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -807,25 +807,55 @@ bitand_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// /// # Examples /// -/// A trivial implementation of `BitOr`. When `Foo | Foo` happens, it ends up -/// calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`. +/// In this example, the `|` operator is lifted to a trivial `Scalar` type. /// /// ``` /// use std::ops::BitOr; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); /// -/// impl BitOr for Foo { -/// type Output = Foo; +/// impl BitOr for Scalar { +/// type Output = Self; /// -/// fn bitor(self, _rhs: Foo) -> Foo { -/// println!("Bitwise Or-ing!"); -/// self +/// // rhs is the "right-hand side" of the expression `a | b` +/// fn bitor(self, rhs: Self) -> Self { +/// Scalar(self.0 | rhs.0) +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Scalar(true) | Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(true) | Scalar(false), Scalar(true)); +/// assert_eq!(Scalar(false) | Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(false) | Scalar(false), Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitOr` trait is implemented for a `BooleanVector` +/// struct. +/// +/// ``` +/// use std::ops::BitOr; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitOr for BooleanVector { +/// type Output = Self; +/// +/// fn bitor(self, BooleanVector(rhs): Self) -> Self { +/// let BooleanVector(lhs) = self; +/// assert_eq!(lhs.len(), rhs.len()); +/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) /// } /// } /// /// fn main() { -/// Foo | Foo; +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, true, true, false]); +/// assert_eq!(bv1 | bv2, expected); /// } /// ``` #[lang = "bitor"] @@ -860,25 +890,58 @@ bitor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// /// # Examples /// -/// A trivial implementation of `BitXor`. When `Foo ^ Foo` happens, it ends up -/// calling `bitxor`, and therefore, `main` prints `Bitwise Xor-ing!`. +/// In this example, the `^` operator is lifted to a trivial `Scalar` type. /// /// ``` /// use std::ops::BitXor; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); /// -/// impl BitXor for Foo { -/// type Output = Foo; +/// impl BitXor for Scalar { +/// type Output = Self; /// -/// fn bitxor(self, _rhs: Foo) -> Foo { -/// println!("Bitwise Xor-ing!"); -/// self +/// // rhs is the "right-hand side" of the expression `a ^ b` +/// fn bitxor(self, rhs: Self) -> Self { +/// Scalar(self.0 ^ rhs.0) +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Scalar(true) ^ Scalar(true), Scalar(false)); +/// assert_eq!(Scalar(true) ^ Scalar(false), Scalar(true)); +/// assert_eq!(Scalar(false) ^ Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(false) ^ Scalar(false), Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitXor` trait is implemented for a `BooleanVector` +/// struct. +/// +/// ``` +/// use std::ops::BitXor; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitXor for BooleanVector { +/// type Output = Self; +/// +/// fn bitxor(self, BooleanVector(rhs): Self) -> Self { +/// let BooleanVector(lhs) = self; +/// assert_eq!(lhs.len(), rhs.len()); +/// BooleanVector(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| (*x || *y) && !(*x && *y)) +/// .collect()) /// } /// } /// /// fn main() { -/// Foo ^ Foo; +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![false, true, true, false]); +/// assert_eq!(bv1 ^ bv2, expected); /// } /// ``` #[lang = "bitxor"] From 507fe146377171013e445783ba00ad8ff2c35e69 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Tue, 30 Aug 2016 22:46:52 +0300 Subject: [PATCH 399/768] update E0265 to new format --- src/librustc_passes/static_recursion.rs | 14 ++++++++------ src/test/compile-fail/issue-23302.rs | 8 ++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index 8b2943a33c006..d23f77af32155 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -126,7 +126,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { idstack: Vec::new(), } } - fn with_item_id_pushed(&mut self, id: ast::NodeId, f: F) + fn with_item_id_pushed(&mut self, id: ast::NodeId, f: F, span: Span) where F: Fn(&mut Self) { if self.idstack.iter().any(|&x| x == id) { @@ -150,7 +150,9 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { "recursive static"); } } else { - span_err!(self.sess, *self.root_span, E0265, "recursive constant"); + struct_span_err!(self.sess, span, E0265, "recursive constant") + .span_label(span, &format!("recursion not allowed in constant")) + .emit(); } return; } @@ -203,7 +205,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { fn visit_item(&mut self, it: &'ast hir::Item) { - self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it)); + self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span); } fn visit_enum_def(&mut self, @@ -233,16 +235,16 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { // If `maybe_expr` is `None`, that's because no discriminant is // specified that affects this variant. Thus, no risk of recursion. if let Some(expr) = maybe_expr { - self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr)); + self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span); } } fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) { - self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti)); + self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti), ti.span); } fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) { - self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii)); + self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii), ii.span); } fn visit_expr(&mut self, e: &'ast hir::Expr) { diff --git a/src/test/compile-fail/issue-23302.rs b/src/test/compile-fail/issue-23302.rs index 7ac8cf45edbef..35f32d16a9a2a 100644 --- a/src/test/compile-fail/issue-23302.rs +++ b/src/test/compile-fail/issue-23302.rs @@ -12,13 +12,21 @@ // the appropriate error (rather than, say, blowing the stack). enum X { A = X::A as isize, //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant } // Since `Y::B` here defaults to `Y::A+1`, this is also a // recursive definition. enum Y { A = Y::B as isize, //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant B, } +const A: i32 = B; //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant + +const B: i32 = A; //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant + fn main() { } From ba69bc8b405f7e48eebda9f08f06fdf23af9027f Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Tue, 23 Aug 2016 11:41:04 -0400 Subject: [PATCH 400/768] replace `BitAndAssign` example with something more evocative This is the augmented-assignment version of PR #35809. r? @GuillaumeGomez improved documentation a la PR #35993 --- src/libcore/ops.rs | 60 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 282f281047e47..1bac3224d318b 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1291,24 +1291,66 @@ rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `BitAndAssign`. When `Foo &= Foo` happens, it ends up -/// calling `bitand_assign`, and therefore, `main` prints `Bitwise And-ing!`. +/// In this example, the `&=` operator is lifted to a trivial `Scalar` type. /// /// ``` /// use std::ops::BitAndAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); /// -/// impl BitAndAssign for Foo { -/// fn bitand_assign(&mut self, _rhs: Foo) { -/// println!("Bitwise And-ing!"); +/// impl BitAndAssign for Scalar { +/// // rhs is the "right-hand side" of the expression `a &= b` +/// fn bitand_assign(&mut self, rhs: Self) { +/// *self = Scalar(self.0 & rhs.0) /// } /// } /// -/// # #[allow(unused_assignments)] /// fn main() { -/// let mut foo = Foo; -/// foo &= Foo; +/// let mut scalar = Scalar(true); +/// scalar &= Scalar(true); +/// assert_eq!(scalar, Scalar(true)); +/// +/// let mut scalar = Scalar(true); +/// scalar &= Scalar(false); +/// assert_eq!(scalar, Scalar(false)); +/// +/// let mut scalar = Scalar(false); +/// scalar &= Scalar(true); +/// assert_eq!(scalar, Scalar(false)); +/// +/// let mut scalar = Scalar(false); +/// scalar &= Scalar(false); +/// assert_eq!(scalar, Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitAndAssign` trait is implemented for a +/// `BooleanVector` struct. +/// +/// ``` +/// use std::ops::BitAndAssign; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitAndAssign for BooleanVector { +/// // rhs is the "right-hand side" of the expression `a &= b` +/// fn bitand_assign(&mut self, rhs: Self) { +/// assert_eq!(self.0.len(), rhs.0.len()); +/// *self = BooleanVector(self.0 +/// .iter() +/// .zip(rhs.0.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()); +/// } +/// } +/// +/// fn main() { +/// let mut bv = BooleanVector(vec![true, true, false, false]); +/// bv &= BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, false, false, false]); +/// assert_eq!(bv, expected); /// } /// ``` #[lang = "bitand_assign"] From d3a6ea52d750499abfaed307cee519879ecbb4c9 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Sun, 28 Aug 2016 01:12:54 +0530 Subject: [PATCH 401/768] Update compiler error E0076 to use new error format Fixes #35221 part of #35233 --- src/librustc_typeck/check/mod.rs | 4 +++- src/test/compile-fail/E0076.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 16300d869abf5..bd52967e72a43 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1228,7 +1228,9 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::Node } let e = fields[0].ty(tcx, substs); if !fields.iter().all(|f| f.ty(tcx, substs) == e) { - span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); + struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") + .span_label(sp, &format!("SIMD elements must have the same type")) + .emit(); return; } match e.sty { diff --git a/src/test/compile-fail/E0076.rs b/src/test/compile-fail/E0076.rs index b0f02a03e0051..c31dc62eb666b 100644 --- a/src/test/compile-fail/E0076.rs +++ b/src/test/compile-fail/E0076.rs @@ -11,7 +11,9 @@ #![feature(repr_simd)] #[repr(simd)] -struct Bad(u16, u32, u32); //~ ERROR E0076 +struct Bad(u16, u32, u32); +//~^ ERROR E0076 +//~| NOTE SIMD elements must have the same type fn main() { } From 3401f4ed3daf842138d72b1e53bf29067d82e590 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:23:35 +0200 Subject: [PATCH 402/768] Add E0466 error explanation --- src/librustc_metadata/diagnostics.rs | 38 +++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 099ec62b38de7..f0652f23a5900 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -91,6 +91,43 @@ You need to link your code to the relevant crate in order to be able to use it well, and you link to them the same way. "##, +E0466: r##" +Macro import declarations were malformed. + +Erroneous code examples: + +```compile_fail,E0466 +#[macro_use(a_macro(another_macro))] // error: invalid import declaration +extern crate some_crate; + +#[macro_use(i_want = "some_macros")] // error: invalid import declaration +extern crate another_crate; +``` + +This is a syntax error at the level of attribute declarations. The proper +syntax for macro imports is the following: + +```ignore +// In some_crate: +#[macro_export] +macro_rules! get_tacos { + ... +} + +#[macro_export] +macro_rules! get_pimientos { + ... +} + +// In your crate: +#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and +extern crate some_crate; // `get_pimientos` macros from some_crate. +``` + +If you would like to import all exported macros, write `macro_use` with no +arguments. +"##, + } register_diagnostics! { @@ -102,7 +139,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0466, // bad macro import E0467, // bad macro reexport E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found From b9eaeb12648e1b26ef86d9efc24f0f456c5d8e2c Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:25:17 +0200 Subject: [PATCH 403/768] Add E0467 error explanation --- src/librustc_metadata/diagnostics.rs | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index f0652f23a5900..5127936b2e23d 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -128,6 +128,35 @@ If you would like to import all exported macros, write `macro_use` with no arguments. "##, +E0467: r##" +Macro reexport declarations were empty or malformed. + +Erroneous code examples: + +```compile_fail,E0467 +#[macro_reexport] // error: no macros listed for export +extern crate macros_for_good; + +#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier +extern crate other_macros_for_good; +``` + +This is a syntax error at the level of attribute declarations. + +Currently, `macro_reexport` requires at least one macro name to be listed. +Unlike `macro_use`, listing no names does not reexport all macros from the +given crate. + +Decide which macros you would like to export and list them properly. + +These are proper reexport declarations: + +```ignore +#[macro_reexport(some_macro, another_macro)] +extern crate macros_for_good; +``` +"##, + } register_diagnostics! { @@ -139,7 +168,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0467, // bad macro reexport E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found E0470, // reexported macro not found From e32dad3a7e3425b9707d7ae944298fa3a2fb7314 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:29:07 +0200 Subject: [PATCH 404/768] Add E0468 error explanation --- src/librustc_metadata/diagnostics.rs | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 5127936b2e23d..42f607ccca089 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -157,6 +157,34 @@ extern crate macros_for_good; ``` "##, +E0468: r##" +A non-root module attempts to import macros from another crate. + +Example of erroneous code: + +```compile_fail,E0468 +mod foo { + #[macro_use(helpful_macro)] // error: must be at crate root to import + extern crate some_crate; // macros from another crate + helpful_macro!(...) +} +``` + +Only `extern crate` imports at the crate root level are allowed to import +macros. + +Either move the macro import to crate root or do without the foreign macros. +This will work: + +```ignore +#[macro_use(helpful_macro)] +extern crate some_crate; + +mod foo { + helpful_macro!(...) +} +``` +"##, } register_diagnostics! { @@ -168,7 +196,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) From 980402cd11422bbf41d6c5d2c71c3bffb8fbd8d7 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:33:35 +0200 Subject: [PATCH 405/768] Add E0469 error explanation --- src/librustc_metadata/diagnostics.rs | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 42f607ccca089..f3189bbaa0752 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -185,6 +185,49 @@ mod foo { } ``` "##, + +E0469: r##" +A macro listed for import was not found. + +Erroneous code example: + +```compile_fail,E0469 +#[macro_use(drink, be_merry)] // error: imported macro not found +extern crate collections; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for import, and that the crate +in question exports them. + +A working version would be: + +```ignore +// In some_crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your crate: +#[macro_use(eat, drink)] +extern crate some_crate; //ok! +``` +"##, + } register_diagnostics! { @@ -196,7 +239,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0469, // imported macro not found E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) E0523, // two dependencies have same (crate-name, disambiguator) but different SVH From 5629f7e62114e8da941dc08e2deae4afd92129dc Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:39:04 +0200 Subject: [PATCH 406/768] Add E0470 error explanation --- src/librustc_metadata/diagnostics.rs | 45 ++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index f3189bbaa0752..3218930746683 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -211,7 +211,7 @@ in question exports them. A working version would be: ```ignore -// In some_crate: +// In some_crate crate: #[macro_export] macro_rules! eat { ... @@ -228,6 +228,48 @@ extern crate some_crate; //ok! ``` "##, +E0470: r##" +A macro listed for reexport was not found. + +Erroneous code example: + +```compile_fail,E0470 +#[macro_reexport(drink, be_merry)] +extern crate collections; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for reexport, and that the crate +in question exports them. + +A working version: + +```ignore +// In some_crate crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your_crate: +#[macro_reexport(eat, drink)] +extern crate some_crate; +``` +"##, + } register_diagnostics! { @@ -239,7 +281,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) E0523, // two dependencies have same (crate-name, disambiguator) but different SVH } From 25145b2ef18b872bf46b939126d607b9107e9966 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 30 Aug 2016 16:30:57 -0500 Subject: [PATCH 407/768] copy_third_party_objects -> copy_musl_third_party_objects --- src/bootstrap/compile.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 6b3b5cf8cda76..5a73f2e21bc0d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -93,14 +93,14 @@ pub fn std_link(build: &Build, add_to_sysroot(&out_dir, &libdir); if target.contains("musl") && !target.contains("mips") { - copy_third_party_objects(build, &libdir); + copy_musl_third_party_objects(build, &libdir); } } /// Copies the crt(1,i,n).o startup objects /// /// Only required for musl targets that statically link to libc -fn copy_third_party_objects(build: &Build, into: &Path) { +fn copy_musl_third_party_objects(build: &Build, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj)); } From 268b3f58184cc7efa8196a28cccffcc01a5d61ac Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 30 Aug 2016 09:29:22 -0400 Subject: [PATCH 408/768] Implement `Debug` for `std::path::Iter`. --- src/libstd/path.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 791b7b2288d5d..dbf17b3c813f6 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -837,6 +837,25 @@ impl<'a> AsRef for Components<'a> { } } +#[stable(feature = "path_iter_debug", since = "1.13.0")] +impl<'a> fmt::Debug for Iter<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct DebugHelper<'a>(&'a Path); + + impl<'a> fmt::Debug for DebugHelper<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.0.iter()) + .finish() + } + } + + f.debug_tuple("Iter") + .field(&DebugHelper(self.as_path())) + .finish() + } +} + impl<'a> Iter<'a> { /// Extracts a slice corresponding to the portion of the path remaining for iteration. #[stable(feature = "rust1", since = "1.0.0")] @@ -3523,4 +3542,26 @@ mod tests { let actual = format!("{:?}", components); assert_eq!(expected, actual); } + + #[cfg(unix)] + #[test] + fn test_iter_debug() { + let path = Path::new("/tmp"); + + let mut iter = path.iter(); + + let expected = "Iter([\"/\", \"tmp\"])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + + let _ = iter.next().unwrap(); + let expected = "Iter([\"tmp\"])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + + let _ = iter.next().unwrap(); + let expected = "Iter([])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + } } From d4ca5613a043e5f2b0ac8b4d7770be1f7f6e2349 Mon Sep 17 00:00:00 2001 From: Eugene R Gonzalez Date: Wed, 17 Aug 2016 21:02:53 -0400 Subject: [PATCH 409/768] Change E0259 to the new error format Fixed E0259 unit test Added name of conflict to E0259's note --- src/librustc_resolve/lib.rs | 6 +++++- src/test/compile-fail/E0259.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d90a932a63d86..51f093054650d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3366,7 +3366,11 @@ impl<'a> Resolver<'a> { }; let mut err = match (old_binding.is_extern_crate(), binding.is_extern_crate()) { - (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg), + (true, true) => { + let mut e = struct_span_err!(self.session, span, E0259, "{}", msg); + e.span_label(span, &format!("`{}` was already imported", name)); + e + }, (true, _) | (_, true) if binding.is_import() || old_binding.is_import() => { let mut e = struct_span_err!(self.session, span, E0254, "{}", msg); e.span_label(span, &"already imported"); diff --git a/src/test/compile-fail/E0259.rs b/src/test/compile-fail/E0259.rs index 6b7e86138594b..d3e876e2527fe 100644 --- a/src/test/compile-fail/E0259.rs +++ b/src/test/compile-fail/E0259.rs @@ -9,6 +9,10 @@ // except according to those terms. extern crate collections; -extern crate libc as collections; //~ ERROR E0259 +//~^ NOTE previous import of `collections` here + +extern crate libc as collections; +//~^ ERROR E0259 +//~| NOTE `collections` was already imported fn main() {} From e0279d71926d0fd7925f55f600bc9947dd070e68 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 31 Aug 2016 16:40:43 +1200 Subject: [PATCH 410/768] Normalize the function signature of closures Previously we didn't normalize the function signatures used for closures. This didn't cause a problem in most cases, but caused an ICE in during MIR type checking. Fixes #36139 --- src/librustc_typeck/astconv.rs | 7 ++++- src/librustc_typeck/check/closure.rs | 2 ++ .../issue-36139-normalize-closure-sig.rs | 28 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-36139-normalize-closure-sig.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f24a7cf2121eb..844b39c6d16f7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1877,11 +1877,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::DefaultReturn(..) => self.tcx().mk_nil(), }; + let input_tys = self_ty.into_iter().chain(arg_tys).collect(); + + debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys); + debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); + (self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: ty::Binder(ty::FnSig { - inputs: self_ty.into_iter().chain(arg_tys).collect(), + inputs: input_tys, output: output_ty, variadic: decl.variadic }), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 46e8c27f6d33b..aa61974e03908 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -74,6 +74,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = self.tcx.liberate_late_bound_regions( self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); + let fn_sig = + (**self).normalize_associated_types_in(body.span, body.id, &fn_sig); check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body); diff --git a/src/test/run-pass/issue-36139-normalize-closure-sig.rs b/src/test/run-pass/issue-36139-normalize-closure-sig.rs new file mode 100644 index 0000000000000..adde0ed306674 --- /dev/null +++ b/src/test/run-pass/issue-36139-normalize-closure-sig.rs @@ -0,0 +1,28 @@ +// 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. + +// Previously the closure's argument would be inferred to +// >::Item, causing an error in MIR type +// checking + +trait ITrait<'a> {type Item;} + +struct S {} + +impl<'a> ITrait<'a> for S { type Item = &'a mut usize; } + +fn m(_: F) + where I: for<'a> ITrait<'a>, + F: for<'a> FnMut(>::Item) { } + + +fn main() { + m::(|x| { *x += 1; }); +} From 42b75a5c18463b4fef98267663fab13d265eac3e Mon Sep 17 00:00:00 2001 From: Chris Wong Date: Sun, 3 Jul 2016 15:24:27 +1200 Subject: [PATCH 411/768] Warn about multiple conflicting #[repr] hints Closes #34622 --- src/librustc/diagnostics.rs | 1 + src/librustc/hir/check_attr.rs | 19 +++++++++++- src/libsyntax/attr.rs | 5 ++-- .../compile-fail/conflicting-repr-hints.rs | 30 +++++++++++++++++++ src/test/run-pass/mir_adt_construction.rs | 2 +- 5 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/conflicting-repr-hints.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 38c60a0b7c7c1..de68cc707ad7a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1804,4 +1804,5 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0491, // in type `..`, reference has a longer lifetime than the data it... E0495, // cannot infer an appropriate lifetime due to conflicting requirements + E0566 // conflicting representation hints } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 21143f93a7da8..53624702c848b 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -52,6 +52,7 @@ impl<'a> CheckAttrVisitor<'a> { } }; + let mut conflicting_reprs = 0; for word in words { let name = match word.name() { Some(word) => word, @@ -60,13 +61,24 @@ impl<'a> CheckAttrVisitor<'a> { let message = match &*name { "C" => { + conflicting_reprs += 1; if target != Target::Struct && target != Target::Enum { "attribute should be applied to struct or enum" } else { continue } } - "packed" | "simd" => { + "packed" => { + // Do not increment conflicting_reprs here, because "packed" + // can be used to modify another repr hint + if target != Target::Struct { + "attribute should be applied to struct" + } else { + continue + } + } + "simd" => { + conflicting_reprs += 1; if target != Target::Struct { "attribute should be applied to struct" } else { @@ -76,6 +88,7 @@ impl<'a> CheckAttrVisitor<'a> { "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "isize" | "usize" => { + conflicting_reprs += 1; if target != Target::Enum { "attribute should be applied to enum" } else { @@ -87,6 +100,10 @@ impl<'a> CheckAttrVisitor<'a> { span_err!(self.sess, attr.span, E0517, "{}", message); } + if conflicting_reprs > 1 { + span_warn!(self.sess, attr.span, E0566, + "conflicting representation hints"); + } } fn check_attribute(&self, attr: &ast::Attribute, target: Target) { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 6060ff529f215..703f3f7adf910 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -904,9 +904,8 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec } }; - match hint { - Some(h) => acc.push(h), - None => { } + if let Some(h) = hint { + acc.push(h); } } else { span_err!(diagnostic, item.span, E0553, diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs new file mode 100644 index 0000000000000..9e0c0d845ca24 --- /dev/null +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -0,0 +1,30 @@ +// 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. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +#[repr(C)] +enum A { A } + +#[repr(u64)] +enum B { B } + +#[repr(C, u64)] //~ WARNING conflicting representation hints +enum C { C } + +#[repr(u32, u64)] //~ WARNING conflicting representation hints +enum D { D } + +#[repr(C, packed)] +struct E(i32); + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/run-pass/mir_adt_construction.rs b/src/test/run-pass/mir_adt_construction.rs index dae843bba9fa6..6b47721ab4b32 100644 --- a/src/test/run-pass/mir_adt_construction.rs +++ b/src/test/run-pass/mir_adt_construction.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[repr(C, u32)] +#[repr(C)] enum CEnum { Hello = 30, World = 60 From 189dee6da11c36bf074fc2e568d356a1bae46b91 Mon Sep 17 00:00:00 2001 From: zjhmale Date: Mon, 29 Aug 2016 22:49:16 +0800 Subject: [PATCH 412/768] Update E0393 to new error format --- src/librustc_typeck/astconv.rs | 13 +++++++------ src/test/compile-fail/E0393.rs | 5 ++++- src/test/compile-fail/issue-21950.rs | 7 +++++-- src/test/compile-fail/issue-22370.rs | 4 +++- src/test/compile-fail/issue-22560.rs | 10 +++++++--- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f24a7cf2121eb..e04bd581f4648 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -515,12 +515,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // defaults. This will lead to an ICE if we are not // careful! if default_needs_object_self(def) { - span_err!(tcx.sess, span, E0393, - "the type parameter `{}` must be explicitly specified \ - in an object type because its default value `{}` references \ - the type `Self`", - def.name, - default); + struct_span_err!(tcx.sess, span, E0393, + "the type parameter `{}` must be explicitly specified", + def.name) + .span_label(span, &format!("missing reference to `{}`", def.name)) + .note(&format!("because of the default `Self` reference, \ + type parameters must be specified on object types")) + .emit(); tcx.types.err } else { // This is a default type parameter. diff --git a/src/test/compile-fail/E0393.rs b/src/test/compile-fail/E0393.rs index 1b89555c8ced1..f045e873519cd 100644 --- a/src/test/compile-fail/E0393.rs +++ b/src/test/compile-fail/E0393.rs @@ -10,7 +10,10 @@ trait A {} -fn together_we_will_rule_the_galaxy(son: &A) {} //~ ERROR E0393 +fn together_we_will_rule_the_galaxy(son: &A) {} +//~^ ERROR E0393 +//~| NOTE missing reference to `T` +//~| NOTE because of the default `Self` reference, type parameters must be specified on object types fn main() { } diff --git a/src/test/compile-fail/issue-21950.rs b/src/test/compile-fail/issue-21950.rs index 1028923ec82fd..935f3480db24a 100644 --- a/src/test/compile-fail/issue-21950.rs +++ b/src/test/compile-fail/issue-21950.rs @@ -15,6 +15,9 @@ use std::ops::Add; fn main() { let x = &10 as &Add; - //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self` - //~| ERROR the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified + //~^ ERROR E0393 + //~| NOTE missing reference to `RHS` + //~| NOTE because of the default `Self` reference, type parameters must be specified on object types + //~| ERROR E0191 + //~| NOTE missing associated type `Output` value } diff --git a/src/test/compile-fail/issue-22370.rs b/src/test/compile-fail/issue-22370.rs index 4c6652d812c8c..51f342e3f0a43 100644 --- a/src/test/compile-fail/issue-22370.rs +++ b/src/test/compile-fail/issue-22370.rs @@ -13,6 +13,8 @@ trait A {} fn f(a: &A) {} -//~^ ERROR the type parameter `T` must be explicitly specified in an object type because its default value `Self` references the type `Self` +//~^ ERROR E0393 +//~| NOTE missing reference to `T` +//~| NOTE because of the default `Self` reference, type parameters must be specified on object types fn main() {} diff --git a/src/test/compile-fail/issue-22560.rs b/src/test/compile-fail/issue-22560.rs index 20ec2d64ae6a8..45b110bf5631d 100644 --- a/src/test/compile-fail/issue-22560.rs +++ b/src/test/compile-fail/issue-22560.rs @@ -13,9 +13,13 @@ use std::ops::{Add, Sub}; type Test = Add + - //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self` - //~^^ ERROR the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified [E0191] + //~^ ERROR E0393 + //~| NOTE missing reference to `RHS` + //~| NOTE because of the default `Self` reference, type parameters must be specified on object types + //~| ERROR E0191 + //~| NOTE missing associated type `Output` value Sub; - //~^ ERROR only the builtin traits can be used as closure or object bounds + //~^ ERROR E0225 + //~| NOTE non-builtin trait used as bounds fn main() { } From 56edae2f424ab0e8325c826a1d0b83783b47adaa Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 31 Aug 2016 13:50:58 +0200 Subject: [PATCH 413/768] Fix typo in PartialOrd docs --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 907dd1508d8be..670978a2d49af 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -383,7 +383,7 @@ impl PartialOrd for Ordering { /// } /// ``` /// -/// You may also find it useful to use `partial_cmp()` on your type`s fields. Here +/// You may also find it useful to use `partial_cmp()` on your type's fields. Here /// is an example of `Person` types who have a floating-point `height` field that /// is the only field to be used for sorting: /// From 69f0cee85dab86b8a27321cfce45adcb1f549d0c Mon Sep 17 00:00:00 2001 From: William Lee Date: Tue, 30 Aug 2016 17:30:08 -0400 Subject: [PATCH 414/768] Bonus fix for #35280. Part of #35233. Fixes #36057. Adding expanded notes/context for what trait a parameter shadows as part of E0194 error messages. --- src/librustc_typeck/check/wfcheck.rs | 28 ++++++++++++++++++++++------ src/test/compile-fail/E0194.rs | 4 ++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a236c8baa9f9c..435442bd30a65 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -16,7 +16,7 @@ use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::nodemap::FnvHashSet; +use rustc::util::nodemap::{FnvHashSet, FnvHashMap}; use syntax::ast; use syntax_pos::Span; @@ -519,11 +519,26 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) { let parent = tcx.lookup_generics(generics.parent.unwrap()); - let impl_params: FnvHashSet<_> = parent.types.iter().map(|tp| tp.name).collect(); + let impl_params: FnvHashMap<_, _> = parent.types + .iter() + .map(|tp| (tp.name, tp.def_id)) + .collect(); for method_param in &generics.types { - if impl_params.contains(&method_param.name) { - error_194(tcx, span, method_param.name); + if impl_params.contains_key(&method_param.name) { + // Tighten up the span to focus on only the shadowing type + let shadow_node_id = tcx.map.as_local_node_id(method_param.def_id).unwrap(); + let type_span = match tcx.map.opt_span(shadow_node_id) { + Some(osp) => osp, + None => span + }; + + // The expectation here is that the original trait declaration is + // local so it should be okay to just unwrap everything. + let trait_def_id = impl_params.get(&method_param.name).unwrap(); + let trait_node_id = tcx.map.as_local_node_id(*trait_def_id).unwrap(); + let trait_decl_span = tcx.map.opt_span(trait_node_id).unwrap(); + error_194(tcx, type_span, trait_decl_span, method_param.name); } } } @@ -630,10 +645,11 @@ fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::N err } -fn error_194(tcx: TyCtxt, span: Span, name: ast::Name) { +fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: ast::Name) { struct_span_err!(tcx.sess, span, E0194, "type parameter `{}` shadows another type parameter of the same name", name) - .span_label(span, &format!("`{}` shadows another type parameter", name)) + .span_label(span, &format!("shadows another type parameter")) + .span_label(trait_decl_span, &format!("first `{}` declared here", name)) .emit(); } diff --git a/src/test/compile-fail/E0194.rs b/src/test/compile-fail/E0194.rs index fa94c88328a86..6b1f718dd76c5 100644 --- a/src/test/compile-fail/E0194.rs +++ b/src/test/compile-fail/E0194.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo { +trait Foo { //~ NOTE first `T` declared here fn do_something(&self) -> T; fn do_something_else(&self, bar: T); //~^ ERROR E0194 - //~| NOTE `T` shadows another type parameter + //~| NOTE shadows another type parameter } fn main() { From ad447a12b5b057802a434eb02373a966328cb3f9 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Wed, 31 Aug 2016 15:52:10 +0200 Subject: [PATCH 415/768] Add a tracking issue to the feature gate of the sysv64 ABI --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 18924a3dc2535..e224e30b1a2a4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -285,7 +285,7 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI - (active, abi_sysv64, "1.13.0", None) + (active, abi_sysv64, "1.13.0", Some(36167)) ); declare_features! ( From 5b5b8536b039b1574f1426aa136f2d527e9e6b58 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Wed, 31 Aug 2016 01:04:56 +0200 Subject: [PATCH 416/768] Update man pages --- man/rustc.1 | 2 +- man/rustdoc.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/rustc.1 b/man/rustc.1 index 0eaf89a560fb8..1656255956191 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -1,4 +1,4 @@ -.TH RUSTC "1" "August 2016" "rustc 1.12.0" "User Commands" +.TH RUSTC "1" "September 2016" "rustc 1.13.0" "User Commands" .SH NAME rustc \- The Rust compiler .SH SYNOPSIS diff --git a/man/rustdoc.1 b/man/rustdoc.1 index 3fb5757f4ff24..4d885bd14363f 100644 --- a/man/rustdoc.1 +++ b/man/rustdoc.1 @@ -1,4 +1,4 @@ -.TH RUSTDOC "1" "August 2016" "rustdoc 1.12.0" "User Commands" +.TH RUSTDOC "1" "September 2016" "rustdoc 1.13.0" "User Commands" .SH NAME rustdoc \- generate documentation from Rust source code .SH SYNOPSIS From b712f74508f278a407b27c5b66d3dff1637bb6fa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Aug 2016 00:07:03 +0200 Subject: [PATCH 417/768] Add missing urls into convert module --- src/libcore/convert.rs | 55 ++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 8e7e2abfc1e17..5191cd7601064 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -42,17 +42,23 @@ /// A cheap, reference-to-reference conversion. /// -/// `AsRef` is very similar to, but different than, `Borrow`. See +/// `AsRef` is very similar to, but different than, [`Borrow`]. See /// [the book][book] for more. /// /// [book]: ../../book/borrow-and-asref.html +/// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// /// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an `Option` or a `Result`. +/// returns an [`Option`] or a [`Result`]. +/// +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html /// /// # Examples /// -/// Both `String` and `&str` implement `AsRef`: +/// Both [`String`] and `&str` implement `AsRef`: +/// +/// [`String`]: ../../std/string/struct.String.html /// /// ``` /// fn is_hello>(s: T) { @@ -81,7 +87,10 @@ pub trait AsRef { /// A cheap, mutable reference-to-mutable reference conversion. /// /// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an `Option` or a `Result`. +/// returns an [`Option`] or a [`Result`]. +/// +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html /// /// # Generic Impls /// @@ -97,16 +106,16 @@ pub trait AsMut { /// A conversion that consumes `self`, which may or may not be expensive. /// -/// **Note: this trait must not fail**. If the conversion can fail, use `TryInto` or a dedicated -/// method which returns an `Option` or a `Result`. +/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated +/// method which returns an [`Option`] or a [`Result`]. /// /// Library authors should not directly implement this trait, but should prefer implementing -/// the `From` trait, which offers greater flexibility and provides an equivalent `Into` +/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into` /// implementation for free, thanks to a blanket implementation in the standard library. /// /// # Examples /// -/// `String` implements `Into>`: +/// [`String`] implements `Into>`: /// /// ``` /// fn is_hello>>(s: T) { @@ -120,9 +129,15 @@ pub trait AsMut { /// /// # Generic Impls /// -/// - `From for U` implies `Into for T` -/// - `into()` is reflexive, which means that `Into for T` is implemented +/// - `[From][From] for U` implies `Into for T` +/// - [`into()`] is reflexive, which means that `Into for T` is implemented /// +/// [`TryInto`]: trait.TryInto.html +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`String`]: ../../std/string/struct.String.html +/// [From]: trait.From.html +/// [`into()`]: trait.Into.html#tymethod.into #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. @@ -132,12 +147,12 @@ pub trait Into: Sized { /// Construct `Self` via a conversion. /// -/// **Note: this trait must not fail**. If the conversion can fail, use `TryFrom` or a dedicated -/// method which returns an `Option` or a `Result`. +/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated +/// method which returns an [`Option`] or a [`Result`]. /// /// # Examples /// -/// `String` implements `From<&str>`: +/// [`String`] implements `From<&str>`: /// /// ``` /// let string = "hello".to_string(); @@ -147,9 +162,15 @@ pub trait Into: Sized { /// ``` /// # Generic impls /// -/// - `From for U` implies `Into for T` -/// - `from()` is reflexive, which means that `From for T` is implemented +/// - `From for U` implies `[Into] for T` +/// - [`from()`] is reflexive, which means that `From for T` is implemented /// +/// [`TryFrom`]: trait.TryFrom.html +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`String`]: ../../std/string/struct.String.html +/// [Into]: trait.Into.html +/// [`from()`]: trait.From.html#tymethod.from #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. @@ -160,8 +181,10 @@ pub trait From: Sized { /// An attempted conversion that consumes `self`, which may or may not be expensive. /// /// Library authors should not directly implement this trait, but should prefer implementing -/// the `TryFrom` trait, which offers greater flexibility and provides an equivalent `TryInto` +/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto` /// implementation for free, thanks to a blanket implementation in the standard library. +/// +/// [`TryFrom`]: trait.TryFrom.html #[unstable(feature = "try_from", issue = "33417")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. From 3f7432a39926e555f47725f27c48c79b9b6e4897 Mon Sep 17 00:00:00 2001 From: Chiu-Hsiang Hsu Date: Wed, 31 Aug 2016 22:45:05 +0800 Subject: [PATCH 418/768] Change 'rustc::plugin' to 'rustc_plugin' in doc comment --- src/librustc_plugin/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index e60a657ba193d..91e0fd636c9c1 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -27,7 +27,7 @@ //! //! extern crate rustc; //! -//! use rustc::plugin::Registry; +//! use rustc_plugin::Registry; //! //! #[plugin_registrar] //! pub fn plugin_registrar(reg: &mut Registry) { From 96e3103cfec430ef03dee1a9125f2f519c7ebc22 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 18 Aug 2016 17:50:28 +0200 Subject: [PATCH 419/768] Improve Path and PathBuf docs --- src/libstd/fs.rs | 7 +- src/libstd/path.rs | 176 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 149 insertions(+), 34 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index b78db24e44b70..f8b816d548a49 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1511,8 +1511,11 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// Returns an iterator over the entries within a directory. /// -/// The iterator will yield instances of `io::Result`. New errors may -/// be encountered after an iterator is initially constructed. +/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. +/// New errors may be encountered after an iterator is initially constructed. +/// +/// [`io::Result`]: ../io/type.Result.html +/// [`DirEntry`]: struct.DirEntry.html /// /// # Platform-specific behavior /// diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 2d19561139b58..ac750d5009f49 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -986,11 +986,16 @@ impl<'a> cmp::Ord for Components<'a> { // Basic types and traits //////////////////////////////////////////////////////////////////////////////// -/// An owned, mutable path (akin to `String`). +/// An owned, mutable path (akin to [`String`]). /// -/// This type provides methods like `push` and `set_extension` that mutate the -/// path in place. It also implements `Deref` to `Path`, meaning that all -/// methods on `Path` slices are available on `PathBuf` values as well. +/// This type provides methods like [`push`] and [`set_extension`] that mutate +/// the path in place. It also implements [`Deref`] to [`Path`], meaning that +/// all methods on [`Path`] slices are available on `PathBuf` values as well. +/// +/// [`String`]: ../string/struct.String.html +/// [`Path`]: struct.Path.html +/// [`push`]: struct.PathBuf.html#method.push +/// [`set_extension`]: struct.PathBuf.html#method.set_extension /// /// More details about the overall approach can be found in /// the module documentation. @@ -1017,12 +1022,31 @@ impl PathBuf { } /// Allocates an empty `PathBuf`. + /// + /// # Examples + /// + /// ``` + /// use std::path::PathBuf; + /// + /// let path = PathBuf::new(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> PathBuf { PathBuf { inner: OsString::new() } } - /// Coerces to a `Path` slice. + /// Coerces to a [`Path`] slice. + /// + /// [`Path`]: struct.Path.html + /// + /// # Examples + /// + /// ``` + /// use std::path::{Path, PathBuf}; + /// + /// let p = PathBuf::from("/test"); + /// assert_eq!(Path::new("/test"), p.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &Path { self @@ -1087,10 +1111,26 @@ impl PathBuf { self.inner.push(path); } - /// Truncate `self` to `self.parent()`. + /// Truncate `self` to [`self.parent()`]. /// - /// Returns false and does nothing if `self.file_name()` is `None`. + /// Returns false and does nothing if [`self.file_name()`] is `None`. /// Otherwise, returns `true`. + /// + /// [`self.parent()`]: struct.PathBuf.html#method.parent + /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// + /// # Examples + /// + /// ``` + /// use std::path::{Path, PathBuf}; + /// + /// let mut p = PathBuf::from("/test/test.rs"); + /// + /// p.pop(); + /// assert_eq!(Path::new("/test"), p.as_path()); + /// p.pop(); + /// assert_eq!(Path::new("/"), p.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pop(&mut self) -> bool { match self.parent().map(|p| p.as_u8_slice().len()) { @@ -1102,11 +1142,13 @@ impl PathBuf { } } - /// Updates `self.file_name()` to `file_name`. + /// Updates [`self.file_name()`] to `file_name`. /// - /// If `self.file_name()` was `None`, this is equivalent to pushing + /// If [`self.file_name()`] was `None`, this is equivalent to pushing /// `file_name`. /// + /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// /// # Examples /// /// ``` @@ -1133,12 +1175,29 @@ impl PathBuf { self.push(file_name); } - /// Updates `self.extension()` to `extension`. + /// Updates [`self.extension()`] to `extension`. + /// + /// If [`self.file_name()`] is `None`, does nothing and returns `false`. + /// + /// Otherwise, returns `true`; if [`self.extension()`] is `None`, the + /// extension is added; otherwise it is replaced. + /// + /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// [`self.extension()`]: struct.PathBuf.html#method.extension + /// + /// # Examples + /// + /// ``` + /// use std::path::{Path, PathBuf}; /// - /// If `self.file_name()` is `None`, does nothing and returns `false`. + /// let mut p = PathBuf::from("/feel/the"); /// - /// Otherwise, returns `true`; if `self.extension()` is `None`, the extension - /// is added; otherwise it is replaced. + /// p.set_extension("force"); + /// assert_eq!(Path::new("/feel/the.force"), p.as_path()); + /// + /// p.set_extension("dark_side"); + /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_extension>(&mut self, extension: S) -> bool { self._set_extension(extension.as_ref()) @@ -1163,7 +1222,18 @@ impl PathBuf { true } - /// Consumes the `PathBuf`, yielding its internal `OsString` storage. + /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage. + /// + /// [`OsString`]: ../ffi/struct.OsString.html + /// + /// # Examples + /// + /// ``` + /// use std::path::PathBuf; + /// + /// let p = PathBuf::from("/the/head"); + /// let os_str = p.into_os_string(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_os_string(self) -> OsString { self.inner @@ -1301,7 +1371,7 @@ impl Into for PathBuf { } } -/// A slice of a path (akin to `str`). +/// A slice of a path (akin to [`str`]). /// /// This type supports a number of operations for inspecting a path, including /// breaking the path into its components (separated by `/` or `\`, depending on @@ -1310,7 +1380,10 @@ impl Into for PathBuf { /// the module documentation. /// /// This is an *unsized* type, meaning that it must always be used behind a -/// pointer like `&` or `Box`. +/// pointer like `&` or [`Box`]. +/// +/// [`str`]: ../primitive.str.html +/// [`Box`]: ../boxed/struct.Box.html /// /// # Examples /// @@ -1372,7 +1445,9 @@ impl Path { unsafe { mem::transmute(s.as_ref()) } } - /// Yields the underlying `OsStr` slice. + /// Yields the underlying [`OsStr`] slice. + /// + /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples /// @@ -1387,10 +1462,12 @@ impl Path { &self.inner } - /// Yields a `&str` slice if the `Path` is valid unicode. + /// Yields a [`&str`] slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// + /// [`&str`]: ../primitive.str.html + /// /// # Examples /// /// ``` @@ -1404,10 +1481,12 @@ impl Path { self.inner.to_str() } - /// Converts a `Path` to a `Cow`. + /// Converts a `Path` to a [`Cow`]. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// /// # Examples /// /// ``` @@ -1421,7 +1500,9 @@ impl Path { self.inner.to_string_lossy() } - /// Converts a `Path` to an owned `PathBuf`. + /// Converts a `Path` to an owned [`PathBuf`]. + /// + /// [`PathBuf`]: struct.PathBuf.html /// /// # Examples /// @@ -1569,6 +1650,18 @@ impl Path { /// /// If `base` is not a prefix of `self` (i.e. `starts_with` /// returns `false`), returns `Err`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/test/haha/foo.txt"); + /// + /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("test").is_ok(), false); + /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); + /// ``` #[stable(since = "1.7.0", feature = "path_strip_prefix")] pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P) -> Result<&'a Path, StripPrefixError> @@ -1630,7 +1723,9 @@ impl Path { iter_after(self.components().rev(), child.components().rev()).is_some() } - /// Extracts the stem (non-extension) portion of `self.file_name()`. + /// Extracts the stem (non-extension) portion of [`self.file_name()`]. + /// + /// [`self.file_name()`]: struct.Path.html#method.file_name /// /// The stem is: /// @@ -1653,7 +1748,9 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) } - /// Extracts the extension of `self.file_name()`, if possible. + /// Extracts the extension of [`self.file_name()`], if possible. + /// + /// [`self.file_name()`]: struct.Path.html#method.file_name /// /// The extension is: /// @@ -1676,9 +1773,12 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after)) } - /// Creates an owned `PathBuf` with `path` adjoined to `self`. + /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. + /// + /// See [`PathBuf::push`] for more details on what it means to adjoin a path. /// - /// See `PathBuf::push` for more details on what it means to adjoin a path. + /// [`PathBuf`]: struct.PathBuf.html + /// [`PathBuf::push`]: struct.PathBuf.html#method.push /// /// # Examples /// @@ -1698,9 +1798,12 @@ impl Path { buf } - /// Creates an owned `PathBuf` like `self` but with the given file name. + /// Creates an owned [`PathBuf`] like `self` but with the given file name. /// - /// See `PathBuf::set_file_name` for more details. + /// See [`PathBuf::set_file_name`] for more details. + /// + /// [`PathBuf`]: struct.PathBuf.html + /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name /// /// # Examples /// @@ -1721,9 +1824,12 @@ impl Path { buf } - /// Creates an owned `PathBuf` like `self` but with the given extension. + /// Creates an owned [`PathBuf`] like `self` but with the given extension. + /// + /// See [`PathBuf::set_extension`] for more details. /// - /// See `PathBuf::set_extension` for more details. + /// [`PathBuf`]: struct.PathBuf.html + /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension /// /// # Examples /// @@ -1771,7 +1877,9 @@ impl Path { } } - /// Produce an iterator over the path's components viewed as `OsStr` slices. + /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// + /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples /// @@ -1790,9 +1898,11 @@ impl Path { Iter { inner: self.components() } } - /// Returns an object that implements `Display` for safely printing paths + /// Returns an object that implements [`Display`] for safely printing paths /// that may contain non-Unicode data. /// + /// [`Display`]: ../fmt/trait.Display.html + /// /// # Examples /// /// ``` @@ -1854,11 +1964,13 @@ impl Path { /// Returns an iterator over the entries within a directory. /// - /// The iterator will yield instances of `io::Result`. New errors may - /// be encountered after an iterator is initially constructed. + /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New + /// errors may be encountered after an iterator is initially constructed. /// /// This is an alias to [`fs::read_dir`]. /// + /// [`io::Result`]: ../io/type.Result.html + /// [`DirEntry`]: ../fs/struct.DirEntry.html /// [`fs::read_dir`]: ../fs/fn.read_dir.html #[stable(feature = "path_ext", since = "1.5.0")] pub fn read_dir(&self) -> io::Result { From 638b7c89e6c3de5c21cf10ea28b8b8ea259b5f27 Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Sun, 28 Aug 2016 12:51:00 +0200 Subject: [PATCH 420/768] Updated E0493 to new format. --- src/librustc_mir/transform/qualify_consts.rs | 4 ++++ src/test/compile-fail/E0493.rs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9e076851bc37d..a6f6faf246969 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -252,11 +252,15 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg); + if self.mode != Mode::Const { help!(&mut err, "in Nightly builds, add `#![feature(drop_types_in_const)]` \ to the crate attributes to enable"); + } else { + err.span_label(self.span, &format!("constants cannot have destructors")); } + err.emit(); } diff --git a/src/test/compile-fail/E0493.rs b/src/test/compile-fail/E0493.rs index 689f469533d96..d5b29a628f0bd 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/compile-fail/E0493.rs @@ -16,7 +16,9 @@ impl Drop for Foo { fn drop(&mut self) {} } -const F : Foo = Foo { a : 0 }; //~ ERROR E0493 +const F : Foo = Foo { a : 0 }; +//~^ ERROR constants are not allowed to have destructors [E0493] +//~| NOTE constants cannot have destructors fn main() { } From 52c2d87aa989eb83bfe61884e3c5f24cb5e923d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Aug 2016 17:18:25 -0400 Subject: [PATCH 421/768] remove unused normalize field --- src/librustc/infer/mod.rs | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9854cd95397b7..37c2a8f0d2cfc 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // avoid reporting the same error twice. pub reported_trait_errors: RefCell>>, - // This is a temporary field used for toggling on normalization in the inference context, - // as we move towards the approach described here: - // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293 - // At a point sometime in the future normalization will be done by the typing context - // directly. - normalize: bool, - // Sadly, the behavior of projection varies a bit depending on the // stage of compilation. The specifics are given in the // documentation for `Reveal`. @@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tables: Option>>, param_env: Option>, projection_mode: Reveal, - normalize: bool } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { @@ -473,7 +465,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { tables: tables.map(RefCell::new), param_env: param_env, projection_mode: projection_mode, - normalize: false } } @@ -485,7 +476,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { tables: None, param_env: None, projection_mode: projection_mode, - normalize: false } } @@ -506,7 +496,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), reported_trait_errors: RefCell::new(FnvHashSet()), - normalize: false, projection_mode: Reveal::NotSpecializable, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), @@ -525,7 +514,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { ref tables, ref mut param_env, projection_mode, - normalize } = *self; let tables = if let Some(ref tables) = *tables { InferTables::Local(tables) @@ -547,7 +535,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), reported_trait_errors: RefCell::new(FnvHashSet()), - normalize: normalize, projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), @@ -1702,17 +1689,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let closure_ty = self.tcx.closure_type(def_id, substs); - if self.normalize { - let closure_ty = self.tcx.erase_regions(&closure_ty); - - if !closure_ty.has_projection_types() { - return closure_ty; - } - - self.normalize_projections_in(&closure_ty) - } else { - closure_ty - } + closure_ty } } From b44d94a5162ee4b2e20f4ae82328f3e7f6a152b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 7 Aug 2016 06:41:17 -0400 Subject: [PATCH 422/768] remove unneccessary uses of `drain_fulfillment_cx` There were various places that we are invoking `drain_fulfillment_cx` with a "result" of `()`. This is kind of pointless, since it amounts to just a call to `select_all_or_error` along with some extra overhead. --- src/librustc/traits/specialize/mod.rs | 35 +++++++++++++++------------ src/librustc_trans/common.rs | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 9acfe2754820c..0604136ec6018 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -207,24 +207,27 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, for oblig in obligations.into_iter() { fulfill_cx.register_predicate_obligation(&infcx, oblig); } + match fulfill_cx.select_all_or_error(infcx) { + Err(errors) => { + // no dice! + debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ + {:?}", + source_trait_ref, + target_trait_ref, + errors, + infcx.parameter_environment.caller_bounds); + Err(()) + } - if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) { - // no dice! - debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ - {:?}", - source_trait_ref, - target_trait_ref, - errors, - infcx.parameter_environment.caller_bounds); - Err(()) - } else { - debug!("fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, - target_trait_ref); + Ok(()) => { + debug!("fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, + target_trait_ref); - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + } } } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d5dcae5f6b0a4..95a38cd21d936 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1028,7 +1028,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fulfill_cx.register_predicate_obligation(&infcx, obligation); } - infcx.drain_fulfillment_cx(&mut fulfill_cx, &()).is_ok() + fulfill_cx.select_all_or_error(infcx).is_ok() }) } From 4eb7362c2c8e614b25aa7daa286805ce1382c6af Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Aug 2016 09:40:12 -0400 Subject: [PATCH 423/768] simplify DepNode for trait selection --- src/librustc/dep_graph/dep_node.rs | 7 ++-- src/librustc/infer/mod.rs | 56 ++++++++++++------------------ src/librustc/ty/mod.rs | 3 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans/monomorphize.rs | 4 +++ 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e95fbcc89175a..18179027c25de 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -132,7 +132,7 @@ pub enum DepNode { // which would yield an overly conservative dep-graph. TraitItems(D), ReprHints(D), - TraitSelect(D, Vec), + TraitSelect(Vec), } impl DepNode { @@ -237,10 +237,9 @@ impl DepNode { TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), - TraitSelect(ref d, ref type_ds) => { - let d = try_opt!(op(d)); + TraitSelect(ref type_ds) => { let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect()); - Some(TraitSelect(d, type_ds)) + Some(TraitSelect(type_ds)) } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 37c2a8f0d2cfc..836e52ea45a59 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -670,6 +670,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) } + /// Finishes processes any obligations that remain in the + /// fulfillment context, and then returns the result with all type + /// variables removed and regions erased. Because this is intended + /// for use after type-check has completed, if any errors occur, + /// it will panic. It is used during normalization and other cases + /// where processing the obligations in `fulfill_cx` may cause + /// type inference variables that appear in `result` to be + /// unified, and hence we need to process those obligations to get + /// the complete picture of the type. pub fn drain_fulfillment_cx_or_panic(&self, span: Span, fulfill_cx: &mut traits::FulfillmentContext<'tcx>, @@ -679,47 +688,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("drain_fulfillment_cx_or_panic()"); - let when = "resolving bounds after type-checking"; - let v = match self.drain_fulfillment_cx(fulfill_cx, result) { - Ok(v) => v, + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(self) { + Ok(()) => { } Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` {}", errors, when); + span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", + errors); } - }; + } - match self.tcx.lift_to_global(&v) { - Some(v) => v, + let result = self.resolve_type_vars_if_possible(result); + let result = self.tcx.erase_regions(&result); + + match self.tcx.lift_to_global(&result) { + Some(result) => result, None => { - span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when); + span_bug!(span, "Uninferred types/regions in `{:?}`", result); } } } - /// Finishes processes any obligations that remain in the fulfillment - /// context, and then "freshens" and returns `result`. This is - /// primarily used during normalization and other cases where - /// processing the obligations in `fulfill_cx` may cause type - /// inference variables that appear in `result` to be unified, and - /// hence we need to process those obligations to get the complete - /// picture of the type. - pub fn drain_fulfillment_cx(&self, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> Result>> - where T : TypeFoldable<'tcx> - { - debug!("drain_fulfillment_cx(result={:?})", - result); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - fulfill_cx.select_all_or_error(self)?; - - let result = self.resolve_type_vars_if_possible(result); - Ok(self.tcx.erase_regions(&result)) - } - pub fn projection_mode(&self) -> Reveal { self.projection_mode } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1ea82a9c639d8..a00ea8de7e71d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -958,8 +958,9 @@ impl<'tcx> TraitPredicate<'tcx> { _ => None }) + .chain(iter::once(self.def_id())) .collect(); - DepNode::TraitSelect(self.def_id(), def_ids) + DepNode::TraitSelect(def_ids) } pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 95a38cd21d936..9758fc074464e 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1028,7 +1028,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fulfill_cx.register_predicate_obligation(&infcx, obligation); } - fulfill_cx.select_all_or_error(infcx).is_ok() + fulfill_cx.select_all_or_error(&infcx).is_ok() }) } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 0ffb83067f91c..4dd5797a31827 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -48,7 +48,11 @@ pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> T where T: TransNormalize<'tcx> { + debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); + debug!("apply_param_substs: substituted={:?}{}", + substituted, + if substituted.has_projection_types() { " [needs projection]" } else { "" }); tcx.normalize_associated_type(&substituted) } From 72694d582931348f6ac18620c8b4ce5c9c9c7a3e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Aug 2016 20:50:19 -0400 Subject: [PATCH 424/768] give `apply_param_substs` a `SharedCrateContext` I plan to put a cache on the shared context, for now at least. --- src/librustc_trans/base.rs | 6 ++--- src/librustc_trans/callee.rs | 20 +++++++-------- src/librustc_trans/collector.rs | 40 +++++++++++++++-------------- src/librustc_trans/common.rs | 4 +-- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/monomorphize.rs | 4 ++- src/librustc_trans/partitioning.rs | 17 +++++++----- src/librustc_trans/trans_item.rs | 2 +- 9 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index fa10adf6c118e..99126095ede3e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1128,7 +1128,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty; let fn_ty = ccx.tcx().erase_regions(&fn_ty); - let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig()); let sig = ccx.tcx().normalize_associated_type(&sig); @@ -1151,7 +1151,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::set_frame_pointer_elimination(ccx, llfndecl); let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty; - let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &ctor_ty); + let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty); let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); let sig = ccx.tcx().normalize_associated_type(&sig); @@ -1894,7 +1894,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a }; let codegen_units = time(time_passes, "codegen unit partitioning", || { - partitioning::partition(scx.tcx(), + partitioning::partition(scx, items.iter().cloned(), strategy, &inlining_map, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index a30f8f291a677..33cacbe194bb0 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -28,7 +28,7 @@ use base; use base::*; use build::*; use closure; -use common::{self, Block, Result, CrateContext, FunctionContext}; +use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext}; use consts; use debuginfo::DebugLoc; use declare; @@ -37,7 +37,7 @@ use monomorphize::{self, Instance}; use trans_item::TransItem; use type_of; use Disr; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::hir; use syntax_pos::DUMMY_SP; @@ -97,7 +97,7 @@ impl<'tcx> Callee<'tcx> { return Callee::trait_method(ccx, trait_id, def_id, substs); } - let fn_ty = def_ty(tcx, def_id, substs); + let fn_ty = def_ty(ccx.shared(), def_id, substs); if let ty::TyFnDef(_, _, f) = fn_ty.sty { if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic { return Callee { @@ -155,20 +155,20 @@ impl<'tcx> Callee<'tcx> { vtable_closure.substs, trait_closure_kind); - let method_ty = def_ty(tcx, def_id, substs); + let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) } traits::VtableFnPointer(vtable_fn_pointer) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty); - let method_ty = def_ty(tcx, def_id, substs); + let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) } traits::VtableObject(ref data) => { Callee { data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)), - ty: def_ty(tcx, def_id, substs) + ty: def_ty(ccx.shared(), def_id, substs) } } vtable => { @@ -244,12 +244,12 @@ impl<'tcx> Callee<'tcx> { } /// Given a DefId and some Substs, produces the monomorphic item type. -fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = tcx.lookup_item_type(def_id).ty; - monomorphize::apply_param_substs(tcx, substs, &ty) + let ty = shared.tcx().lookup_item_type(def_id).ty; + monomorphize::apply_param_substs(shared, substs, &ty) } /// Translates an adapter that implements the `Fn` trait for a fn @@ -407,7 +407,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = tcx.normalize_associated_type(&substs); let instance = Instance::new(def_id, substs); let item_ty = ccx.tcx().lookup_item_type(def_id).ty; - let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &item_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { return (llfn, fn_ty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ba979813aa1f0..c82bfa5c91ba1 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -459,7 +459,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { format!("Could not find MIR for closure: {:?}", def_id) }); - let concrete_substs = monomorphize::apply_param_substs(self.scx.tcx(), + let concrete_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs.func_substs); let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); @@ -477,11 +477,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = monomorphize::apply_param_substs(self.scx.tcx(), + let target_ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &target_ty); let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = monomorphize::apply_param_substs(self.scx.tcx(), + let source_ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &source_ty); let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, @@ -508,7 +508,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id)); let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id); let exchange_malloc_fn_trans_item = - create_fn_trans_item(self.scx.tcx(), + create_fn_trans_item(self.scx, exchange_malloc_fn_def_id, empty_substs, self.param_substs); @@ -531,7 +531,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let ty = lvalue.ty(self.mir, self.scx.tcx()) .to_ty(self.scx.tcx()); - let ty = monomorphize::apply_param_substs(self.scx.tcx(), + let ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &ty); assert!(ty.is_normalized_for_trans()); @@ -555,7 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // references to `const` items if let mir::Literal::Item { def_id, substs } = constant.literal { let tcx = self.scx.tcx(); - let substs = monomorphize::apply_param_substs(tcx, + let substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs); @@ -613,7 +613,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // result in a translation item ... if can_result_in_trans_item(self.scx.tcx(), callee_def_id) { // ... and create one if it does. - let trans_item = create_fn_trans_item(self.scx.tcx(), + let trans_item = create_fn_trans_item(self.scx, callee_def_id, callee_substs, self.param_substs); @@ -670,7 +670,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => { let operand_ty = args[0].ty(self.mir, tcx); if let ty::TyRawPtr(mt) = operand_ty.sty { - let operand_ty = monomorphize::apply_param_substs(tcx, + let operand_ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &mt.ty); let ty = glue::get_drop_glue_type(tcx, operand_ty); @@ -732,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id)); let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id); let exchange_free_fn_trans_item = - create_fn_trans_item(scx.tcx(), + create_fn_trans_item(scx, exchange_free_fn_def_id, fn_substs, Substs::empty(scx.tcx())); @@ -769,7 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, }; if can_have_local_instance(scx.tcx(), destructor_did) { - let trans_item = create_fn_trans_item(scx.tcx(), + let trans_item = create_fn_trans_item(scx, destructor_did, substs, Substs::empty(scx.tcx())); @@ -800,7 +800,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyStruct(ref adt_def, substs) | ty::TyEnum(ref adt_def, substs) => { for field in adt_def.all_fields() { - let field_type = monomorphize::apply_param_substs(scx.tcx(), + let field_type = monomorphize::apply_param_substs(scx, substs, &field.unsubst_ty()); let field_type = glue::get_drop_glue_type(scx.tcx(), field_type); @@ -894,8 +894,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, callee_substs, param_substs); - - let rcvr_substs = monomorphize::apply_param_substs(tcx, + let rcvr_substs = monomorphize::apply_param_substs(scx, param_substs, &callee_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); @@ -1016,11 +1015,13 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } -fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn create_fn_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId, fn_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) -> TransItem<'tcx> { + let tcx = scx.tcx(); + debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})", def_id_to_string(tcx, def_id), fn_substs, @@ -1029,7 +1030,7 @@ fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // We only get here, if fn_def_id either designates a local item or // an inlineable external item. Non-inlineable external items are // ignored because we don't want to generate any code for them. - let concrete_substs = monomorphize::apply_param_substs(tcx, + let concrete_substs = monomorphize::apply_param_substs(scx, param_substs, &fn_substs); assert!(concrete_substs.is_normalized_for_trans()); @@ -1063,7 +1064,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, // create translation items .filter_map(|impl_method| { if can_have_local_instance(scx.tcx(), impl_method.method.def_id) { - Some(create_fn_trans_item(scx.tcx(), + Some(create_fn_trans_item(scx, impl_method.method.def_id, impl_method.substs, Substs::empty(scx.tcx()))) @@ -1114,7 +1115,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemImpl(..) => { if self.mode == TransItemCollectionMode::Eager { - create_trans_items_for_default_impls(self.scx.tcx(), + create_trans_items_for_default_impls(self.scx, item, self.output); } @@ -1202,9 +1203,10 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } -fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, item: &'tcx hir::Item, output: &mut Vec>) { + let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, _, @@ -1255,7 +1257,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if can_have_local_instance(tcx, method.def_id) { let empty_substs = tcx.erase_regions(&mth.substs); - let item = create_fn_trans_item(tcx, + let item = create_fn_trans_item(scx, method.def_id, callee_substs, empty_substs); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 9758fc074464e..c51b32331112e 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -350,7 +350,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { pub fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.tcx(), + monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value) } @@ -519,7 +519,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { pub fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.tcx(), + monomorphize::apply_param_substs(self.fcx.ccx.shared(), self.fcx.param_substs, value) } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 5e248261e1185..a3a7a79fb58be 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -414,7 +414,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty; let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty); - let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(), + let impl_self_ty = monomorphize::apply_param_substs(cx.shared(), instance.substs, &impl_self_ty); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1badfdba6603f..ade266a580e78 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -258,7 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.tcx(), + monomorphize::apply_param_substs(self.ccx.shared(), self.substs, value) } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 4dd5797a31827..66b227fe5c54d 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -42,12 +42,13 @@ impl<'tcx> Instance<'tcx> { /// Monomorphizes a type from the AST by first applying the in-scope /// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, param_substs: &Substs<'tcx>, value: &T) -> T where T: TransNormalize<'tcx> { + let tcx = scx.tcx(); debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); debug!("apply_param_substs: substituted={:?}{}", @@ -65,3 +66,4 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } + diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 7341e8db41de5..a161bd199b1f6 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -117,6 +117,7 @@ //! inlining, even when they are not marked #[inline]. use collector::InliningMap; +use context::SharedCrateContext; use llvm; use monomorphize; use rustc::dep_graph::{DepNode, WorkProductId}; @@ -250,7 +251,7 @@ impl<'tcx> CodegenUnit<'tcx> { // Anything we can't find a proper codegen unit for goes into this. const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; -pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_items: I, strategy: PartitioningStrategy, inlining_map: &InliningMap<'tcx>, @@ -258,6 +259,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> Vec> where I: Iterator> { + let tcx = scx.tcx(); + if let PartitioningStrategy::FixedUnitCount(1) = strategy { // If there is only a single codegen-unit, we can use a very simple // scheme and don't have to bother with doing much analysis. @@ -267,7 +270,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_translation_items(tcx, + let mut initial_partitioning = place_root_translation_items(scx, trans_items, reachable); @@ -306,12 +309,13 @@ struct PreInliningPartitioning<'tcx> { struct PostInliningPartitioning<'tcx>(Vec>); -fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_items: I, _reachable: &NodeSet) -> PreInliningPartitioning<'tcx> where I: Iterator> { + let tcx = scx.tcx(); let mut roots = FnvHashSet(); let mut codegen_units = FnvHashMap(); @@ -319,7 +323,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let is_root = !trans_item.is_instantiated_only_on_demand(); if is_root { - let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); + let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); let is_volatile = trans_item.is_generic_fn(); let codegen_unit_name = match characteristic_def_id { @@ -477,9 +481,10 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit } } -fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, trans_item: TransItem<'tcx>) -> Option { + let tcx = scx.tcx(); match trans_item { TransItem::Fn(instance) => { // If this is a method, we want to put it into the same module as @@ -497,7 +502,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // self-type is: let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty; let impl_self_ty = tcx.erase_regions(&impl_self_ty); - let impl_self_ty = monomorphize::apply_param_substs(tcx, + let impl_self_ty = monomorphize::apply_param_substs(scx, instance.substs, &impl_self_ty); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 2c91c408487b8..8a0f37230c8df 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -176,7 +176,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; let item_ty = ccx.tcx().erase_regions(&item_ty); - let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty); + let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty); let attrs = ccx.tcx().get_attrs(instance.def); let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); From c5be6f6cc6a87368f694faf0874b3b41d359faad Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Aug 2016 20:51:09 -0400 Subject: [PATCH 425/768] add cache to shared context for proj --- src/librustc_trans/context.rs | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 7c1a607015de9..b0b7ae1f59849 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -84,6 +84,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { translation_items: RefCell>>, trait_cache: RefCell>>, + project_cache: RefCell>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -195,6 +196,46 @@ impl<'tcx> DepTrackingMapConfig for MirCache<'tcx> { } } +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_node(key: &Self::Key) -> DepNode { + // Ideally, we'd just put `key` into the dep-node, but we + // can't put full types in there. So just collect up all the + // def-ids of structs/enums as well as any traits that we + // project out of. It doesn't matter so much what we do here, + // except that if we are too coarse, we'll create overly + // coarse edges between impls and the trans. For example, if + // we just used the def-id of things we are projecting out of, + // then the key for `::T` and `::T` would both share a dep-node + // (`TraitSelect(SomeTrait)`), and hence the impls for both + // `Foo` and `Bar` would be considered inputs. So a change to + // `Bar` would affect things that just normalized `Foo`. + // Anyway, this heuristic is not ideal, but better than + // nothing. + let def_ids: Vec = + key.walk() + .filter_map(|t| match t.sty { + ty::TyStruct(adt_def, _) | + ty::TyEnum(adt_def, _) => + Some(adt_def.did), + ty::TyProjection(ref proj) => + Some(proj.trait_ref.def_id), + _ => + None + }) + .collect(); + DepNode::TraitSelect(def_ids) + } +} + /// This list owns a number of LocalCrateContexts and binds them to their common /// SharedCrateContext. This type just exists as a convenience, something to /// pass around all LocalCrateContexts with and get an iterator over them. @@ -496,6 +537,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { use_dll_storage_attrs: use_dll_storage_attrs, translation_items: RefCell::new(FnvHashSet()), trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), + project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } } @@ -519,6 +561,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.trait_cache } + pub fn project_cache(&self) -> &RefCell>> { + &self.project_cache + } + pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { &self.link_meta } From f5c775274275fa34b068ddf802bd528f790f7af8 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 1 Sep 2016 00:27:03 +0300 Subject: [PATCH 426/768] Fix optimization regressions for operations on [x; n]-initialized arrays. --- src/librustc_trans/tvec.rs | 2 +- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index 7e4719870cd83..cf897fc5a1518 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -52,7 +52,7 @@ pub fn slice_for_each<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let current = Phi(header_bcx, val_ty(start), &[start], &[bcx.llbb]); let keep_going = - ICmp(header_bcx, llvm::IntULT, current, end, DebugLoc::None); + ICmp(header_bcx, llvm::IntNE, current, end, DebugLoc::None); CondBr(header_bcx, keep_going, body_bcx.llbb, next_bcx.llbb, DebugLoc::None); let body_bcx = f(body_bcx, if zst { data_ptr } else { current }); diff --git a/src/llvm b/src/llvm index eee68eafa7e8e..16b79d01fd6d9 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit eee68eafa7e8e4ce996b49f5551636639a6c331a +Subproject commit 16b79d01fd6d942cf3c9120b92df56b13ec92665 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 67f8730c25825..1080070d21a3b 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-08-23 +2016-08-30 From 7057c421c0bb1cb75c26f7135b44cb7f98db6508 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Aug 2016 15:46:54 -0400 Subject: [PATCH 427/768] cache projections in trans --- src/librustc_trans/monomorphize.rs | 47 ++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 66b227fe5c54d..ab2a39864336f 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use common::*; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; +use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use common::*; use rustc::util::ppaux; - +use rustc::util::common::MemoizationMap; use std::fmt; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -51,10 +52,8 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, let tcx = scx.tcx(); debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); - debug!("apply_param_substs: substituted={:?}{}", - substituted, - if substituted.has_projection_types() { " [needs projection]" } else { "" }); - tcx.normalize_associated_type(&substituted) + let substituted = scx.tcx().erase_regions(&substituted); + AssociatedTypeNormalizer::new(scx).fold(&substituted) } @@ -67,3 +66,39 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } +struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> { + shared: &'a SharedCrateContext<'b, 'gcx>, +} + +impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> { + fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self { + AssociatedTypeNormalizer { + shared: shared, + } + } + + fn fold>(&mut self, value: &T) -> T { + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.shared.tcx() + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + ty + } else { + self.shared.project_cache().memoize(ty, || { + debug!("AssociatedTypeNormalizer: ty={:?}", ty); + self.shared.tcx().normalize_associated_type(&ty) + }) + } + } +} From 9a400f0a313c765ed8a39d0863321ff9e88d8961 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Wed, 31 Aug 2016 18:17:44 -0400 Subject: [PATCH 428/768] replace `../` with `../../std/` to support `core` docs --- src/libcore/ops.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 78c8fc0ac4549..e36539bf17d57 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -217,7 +217,7 @@ macro_rules! forward_ref_binop { /// [std::time::SystemTime] implements `Add`, which permits /// operations of the form `SystemTime = SystemTime + Duration`. /// -/// [std::time::SystemTime]: ../time/struct.SystemTime.html +/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Add { @@ -290,7 +290,7 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// [std::time::SystemTime] implements `Sub`, which permits /// operations of the form `SystemTime = SystemTime - Duration`. /// -/// [std::time::SystemTime]: ../time/struct.SystemTime.html +/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Sub { From 1b0476297e6d8bee01197e507f50350a748388a2 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 31 Aug 2016 15:19:43 -0700 Subject: [PATCH 429/768] Special case a few colors for Windows --- src/librustc_errors/emitter.rs | 15 +++++++++++++-- src/librustc_errors/lib.rs | 8 +++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index ed133d21b8a0f..dcdbe2a85259b 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -883,7 +883,11 @@ impl Destination { Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + if cfg!(windows) { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + } else { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + } } Style::ErrorCode => { try!(self.start_attr(term::Attr::Bold)); @@ -896,6 +900,9 @@ impl Destination { } Style::OldSchoolNoteText | Style::HeaderMsg => { try!(self.start_attr(term::Attr::Bold)); + if cfg!(windows) { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))); + } } Style::UnderlinePrimary | Style::LabelPrimary => { try!(self.start_attr(term::Attr::Bold)); @@ -904,7 +911,11 @@ impl Destination { Style::UnderlineSecondary | Style::LabelSecondary => { try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + if cfg!(windows) { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + } else { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + } } Style::NoStyle => {} Style::Level(l) => { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index c99bc47044853..d82d7dbe70f92 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -732,7 +732,13 @@ impl Level { pub fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, - Warning => term::color::YELLOW, + Warning => { + if cfg!(windows) { + term::color::BRIGHT_YELLOW + } else { + term::color::YELLOW + } + }, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), From 439afcd9747808fb187b0676d63af5375a677e3d Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 31 Aug 2016 17:48:26 -0700 Subject: [PATCH 430/768] Update error message for lifetime of borrowed values --- src/librustc_borrowck/borrowck/mod.rs | 22 ++++++++++------- .../borrowck-let-suggestion-suffixes.rs | 24 +++++++++---------- .../regions-escape-loop-via-vec.rs | 4 ++-- .../lifetimes}/borrowck-let-suggestion.rs | 5 ---- .../lifetimes/borrowck-let-suggestion.stderr | 14 +++++++++++ src/test/ui/span/issue-11925.stderr | 4 ++-- 6 files changed, 44 insertions(+), 29 deletions(-) rename src/test/{compile-fail/borrowck => ui/lifetimes}/borrowck-let-suggestion.rs (66%) create mode 100644 src/test/ui/lifetimes/borrowck-let-suggestion.stderr diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e8b44d85bf916..ac8cfa7f43709 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1029,6 +1029,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } err_out_of_scope(super_scope, sub_scope, cause) => { + let (value_kind, value_msg) = match err.cmt.cat { + mc::Categorization::Rvalue(_) => + ("temporary value", "temporary value created here"), + _ => + ("borrowed value", "does not live long enough") + }; match cause { euv::ClosureCapture(s) => { // The primary span starts out as the closure creation point. @@ -1039,13 +1045,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Some(primary) => { db.span = MultiSpan::from_span(s); db.span_label(primary, &format!("capture occurs here")); - db.span_label(s, &format!("does not live long enough")); + db.span_label(s, &value_msg); } None => () } } _ => { - db.span_label(error_span, &format!("does not live long enough")); + db.span_label(error_span, &value_msg); } } @@ -1054,14 +1060,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { match (sub_span, super_span) { (Some(s1), Some(s2)) if s1 == s2 => { - db.span_label(s1, &"borrowed value dropped before borrower"); + db.span_label(s1, &format!("{} dropped before borrower", value_kind)); db.note("values in a scope are dropped in the opposite order \ they are created"); } _ => { match sub_span { Some(s) => { - db.span_label(s, &"borrowed value must be valid until here"); + db.span_label(s, &format!("{} needs to live until here", + value_kind)); } None => { self.tcx.note_and_explain_region( @@ -1073,7 +1080,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } match super_span { Some(s) => { - db.span_label(s, &"borrowed value only valid until here"); + db.span_label(s, &format!("{} only lives until here", value_kind)); } None => { self.tcx.note_and_explain_region( @@ -1086,9 +1093,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - if let Some(span) = statement_scope_span(self.tcx, super_scope) { - db.span_help(span, - "consider using a `let` binding to increase its lifetime"); + if let Some(_) = statement_scope_span(self.tcx, super_scope) { + db.note("consider using a `let` binding to increase its lifetime"); } } diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs index 6c9f67b2b33d4..95c74348e788b 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs +++ b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs @@ -25,9 +25,9 @@ fn f() { v3.push(&'x'); // statement 6 //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime + //~| NOTE temporary value created here + //~| NOTE temporary value only lives until here + //~| NOTE consider using a `let` binding to increase its lifetime { @@ -35,26 +35,26 @@ fn f() { v4.push(&'y'); //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime + //~| NOTE temporary value created here + //~| NOTE temporary value only lives until here + //~| NOTE consider using a `let` binding to increase its lifetime } // (statement 7) - //~^ NOTE borrowed value must be valid until here + //~^ NOTE temporary value needs to live until here let mut v5 = Vec::new(); // statement 8 v5.push(&'z'); //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime + //~| NOTE temporary value created here + //~| NOTE temporary value only lives until here + //~| NOTE consider using a `let` binding to increase its lifetime v1.push(&old[0]); } //~^ NOTE borrowed value dropped before borrower -//~| NOTE borrowed value must be valid until here -//~| NOTE borrowed value must be valid until here +//~| NOTE temporary value needs to live until here +//~| NOTE temporary value needs to live until here fn main() { f(); diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs index 8c026df7d9754..f5ea7a2108e79 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs @@ -24,8 +24,8 @@ fn broken() { x += 1; //~ ERROR cannot assign //~^ NOTE assignment to borrowed `x` occurs here } - //~^ NOTE borrowed value only valid until here + //~^ NOTE borrowed value only lives until here } -//~^ NOTE borrowed value must be valid until here +//~^ NOTE borrowed value needs to live until here fn main() { } diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs b/src/test/ui/lifetimes/borrowck-let-suggestion.rs similarity index 66% rename from src/test/compile-fail/borrowck/borrowck-let-suggestion.rs rename to src/test/ui/lifetimes/borrowck-let-suggestion.rs index ef8f44c1df789..eeafaab44c620 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.rs @@ -10,12 +10,7 @@ fn f() { let x = [1].iter(); - //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime } -//~^ borrowed value must be valid until here fn main() { f(); diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr new file mode 100644 index 0000000000000..91600340019c3 --- /dev/null +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr @@ -0,0 +1,14 @@ +error: borrowed value does not live long enough + --> $DIR/borrowck-let-suggestion.rs:12:13 + | +12 | let x = [1].iter(); + | ^^^ - temporary value only lives until here + | | + | temporary value created here +13 | } + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: aborting due to previous error + diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr index d379cfc3d68a7..3fedb2884bc58 100644 --- a/src/test/ui/span/issue-11925.stderr +++ b/src/test/ui/span/issue-11925.stderr @@ -5,10 +5,10 @@ error: `x` does not live long enough | ^ | | | does not live long enough - | borrowed value only valid until here + | borrowed value only lives until here ... 23 | } - | - borrowed value must be valid until here + | - borrowed value needs to live until here error: aborting due to previous error From 00d208eea87c1cbeefb8a0a83237a71c9eea2d6c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 31 Aug 2016 22:06:01 -0400 Subject: [PATCH 431/768] remove `normalize_infer_ctxt` constructor --- src/librustc/infer/mod.rs | 11 ----------- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc_lint/types.rs | 2 +- src/librustc_trans/common.rs | 4 ++-- src/librustc_trans/context.rs | 2 +- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/meth.rs | 2 +- 7 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 836e52ea45a59..b6114f293ad3a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -468,17 +468,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { } } - pub fn normalizing_infer_ctxt(self, projection_mode: Reveal) - -> InferCtxtBuilder<'a, 'gcx, 'tcx> { - InferCtxtBuilder { - global_tcx: self, - arenas: ty::CtxtArenas::new(), - tables: None, - param_env: None, - projection_mode: projection_mode, - } - } - /// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck /// for MemCategorizationContext/ExprUseVisitor. /// If any inference functionality is used, ICEs will occur. diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 0604136ec6018..f3ba4d16eb0b2 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -147,7 +147,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .unwrap() .subst(tcx, &penv.free_substs); - let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| { + let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| { // Normalize the trait reference, adding any obligations // that arise into the impl1 assumptions. let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index b0b5947145dbf..40e78c007ccfd 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -691,7 +691,7 @@ impl LateLintPass for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types let t = cx.tcx.node_id_to_type(it.id); - let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); ty.layout(&infcx).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", t, e) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index c51b32331112e..f4682de7dff6a 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -955,7 +955,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let obligation_cause = traits::ObligationCause::misc(span, @@ -1014,7 +1014,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_and_test_predicates(predicates={:?})", predicates); - tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = traits::FulfillmentContext::new(); let cause = traits::ObligationCause::dummy(); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b0b7ae1f59849..2422b9f30069b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -996,7 +996,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout { - self.tcx().normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { + self.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| { ty.layout(&infcx).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", ty, e); }) diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 8d182a95a1ab8..9e1e415f62a67 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -113,7 +113,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match t.sty { ty::TyBox(typ) if !type_needs_drop(tcx, typ) && type_is_sized(tcx, typ) => { - tcx.normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { + tcx.infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| { let layout = t.layout(&infcx).unwrap(); if layout.size(&tcx.data_layout).bytes() == 0 { // `Box` does not allocate. diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 483bc99c310fc..e958795570eee 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -314,7 +314,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() { Some(node_item) => { - let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs); let substs = traits::translate_substs(&infcx, impl_def_id, substs, node_item.node); From cbafc5758ba905e57d3f10476deb05a79588cd81 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 12:24:55 +1200 Subject: [PATCH 432/768] save-analsysis: add save-analysis-api CLI flag --- src/librustc/session/config.rs | 10 ++++++++-- src/librustc_driver/lib.rs | 5 ++++- src/librustc_save_analysis/lib.rs | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b129..8eb80472d6e09 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -848,9 +848,13 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate"), save_analysis: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in JSON format) information in addition to normal output"), + "write syntax and type analysis (in JSON format) information, \ + addition to normal output"), save_analysis_csv: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in CSV format) information in addition to normal output"), + "write syntax and type analysis (in CSV format) information, in addition to normal output"), + save_analysis_api: bool = (false, parse_bool, [UNTRACKED], + "write syntax and type analysis information for opaque libraries (in JSON format), \ + in addition to normal output"), print_move_fragments: bool = (false, parse_bool, [UNTRACKED], "print out move-fragment data for every fn"), flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED], @@ -2359,6 +2363,8 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.save_analysis_csv = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + opts.debugging_opts.save_analysis_api = true; + assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.print_move_fragments = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.flowgraph_print_loans = true; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index efadf1ff488df..95f8aa620a91a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -555,7 +555,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn save_analysis(sess: &Session) -> bool { sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.save_analysis_csv || + sess.opts.debugging_opts.save_analysis_api } fn save_analysis_format(sess: &Session) -> save::Format { @@ -563,6 +564,8 @@ fn save_analysis_format(sess: &Session) -> save::Format { save::Format::Json } else if sess.opts.debugging_opts.save_analysis_csv { save::Format::Csv + } else if sess.opts.debugging_opts.save_analysis_api { + save::Format::JsonApi } else { unreachable!(); } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index db535e22f194d..77273bd3f2ed2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -727,13 +727,14 @@ impl Visitor for PathCollector { pub enum Format { Csv, Json, + JsonApi, } impl Format { fn extension(&self) -> &'static str { match *self { Format::Csv => ".csv", - Format::Json => ".json", + Format::Json | Format::JsonApi => ".json", } } } @@ -803,6 +804,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, match format { Format::Csv => dump!(CsvDumper::new(output)), Format::Json => dump!(JsonDumper::new(output)), + Format::JsonApi => /* TODO */ dump!(JsonDumper::new(output)), } } From c7dfc89f854f629816253f84ac0cc15d7792d63f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 13:29:12 +1200 Subject: [PATCH 433/768] JsonApiDumper --- src/librustc_save_analysis/json_api_dumper.rs | 356 ++++++++++++++++++ src/librustc_save_analysis/lib.rs | 4 +- 2 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 src/librustc_save_analysis/json_api_dumper.rs diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs new file mode 100644 index 0000000000000..e92c23d7d7c5a --- /dev/null +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -0,0 +1,356 @@ +// 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. + +use std::io::Write; + +use rustc::hir::def_id::DefId; +use rustc_serialize::json::as_json; + +use external_data::*; +use data::VariableKind; +use dump::Dump; + +pub struct JsonApiDumper<'b, W: Write + 'b> { + output: &'b mut W, + result: Analysis, +} + +impl<'b, W: Write> JsonApiDumper<'b, W> { + pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> { + JsonApiDumper { output: writer, result: Analysis::new() } + } +} + +impl<'b, W: Write> Drop for JsonApiDumper<'b, W> { + fn drop(&mut self) { + if let Err(_) = write!(self.output, "{}", as_json(&self.result)) { + error!("Error writing output"); + } + } +} + +macro_rules! impl_fn { + ($fn_name: ident, $data_type: ident, $bucket: ident) => { + fn $fn_name(&mut self, data: $data_type) { + if let Some(datum) = From::from(data) { + self.result.$bucket.push(datum); + } + } + } +} + +impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { + fn crate_prelude(&mut self, data: CratePreludeData) { + self.result.prelude = Some(data) + } + + impl_fn!(use_data, UseData, imports); + impl_fn!(use_glob, UseGlobData, imports); + + impl_fn!(enum_data, EnumData, defs); + impl_fn!(tuple_variant, TupleVariantData, defs); + impl_fn!(struct_variant, StructVariantData, defs); + impl_fn!(struct_data, StructData, defs); + impl_fn!(trait_data, TraitData, defs); + impl_fn!(function, FunctionData, defs); + impl_fn!(method, MethodData, defs); + impl_fn!(macro_data, MacroData, defs); + impl_fn!(mod_data, ModData, defs); + impl_fn!(typedef, TypeDefData, defs); + impl_fn!(variable, VariableData, defs); +} + +// FIXME methods. The defs have information about possible overriding and the +// refs have decl information (e.g., a trait method where we know the required +// method, but not the supplied method). In both cases, we are currently +// ignoring it. + +#[derive(Debug, RustcEncodable)] +struct Analysis { + prelude: Option, + imports: Vec, + defs: Vec, +} + +impl Analysis { + fn new() -> Analysis { + Analysis { + prelude: None, + imports: vec![], + defs: vec![], + } + } +} + +// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore +// we use our own Id which is the same, but without the newtype. +#[derive(Debug, RustcEncodable)] +struct Id { + krate: u32, + index: u32, +} + +impl From for Id { + fn from(id: DefId) -> Id { + Id { + krate: id.krate, + index: id.index.as_u32(), + } + } +} + +#[derive(Debug, RustcEncodable)] +struct Import { + kind: ImportKind, + id: Id, + span: SpanData, + name: String, + value: String, +} + +#[derive(Debug, RustcEncodable)] +enum ImportKind { + Use, + GlobUse, +} + +impl From for Option { + fn from(data: UseData) -> Option { + Some(Import { + kind: ImportKind::Use, + id: From::from(data.id), + span: data.span, + name: data.name, + value: String::new(), + }) + } +} +impl From for Option { + fn from(data: UseGlobData) -> Option { + Some(Import { + kind: ImportKind::GlobUse, + id: From::from(data.id), + span: data.span, + name: "*".to_owned(), + value: data.names.join(", "), + }) + } +} + +#[derive(Debug, RustcEncodable)] +struct Def { + kind: DefKind, + id: Id, + span: SpanData, + name: String, + qualname: String, + value: String, + parent: Option, + children: Vec, + decl_id: Option, +} + +#[derive(Debug, RustcEncodable)] +enum DefKind { + // value = variant names + Enum, + // value = enum name + variant name + types + Tuple, + // value = [enum name +] name + fields + Struct, + // value = signature + Trait, + // value = type + generics + Function, + // value = type + generics + Method, + // No id, no value. + Macro, + // value = file_name + Mod, + // value = aliased type + Type, + // value = type and init expression (for all variable kinds). + Static, + Const, + Field, +} + +impl From for Option { + fn from(data: EnumData) -> Option { + Some(Def { + kind: DefKind::Enum, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.variants.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }) + } +} + +impl From for Option { + fn from(data: TupleVariantData) -> Option { + Some(Def { + kind: DefKind::Tuple, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: vec![], + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: StructVariantData) -> Option { + Some(Def { + kind: DefKind::Struct, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: vec![], + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: StructData) -> Option { + Some(Def { + kind: DefKind::Struct, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.fields.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: TraitData) -> Option { + Some(Def { + kind: DefKind::Trait, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: FunctionData) -> Option { + Some(Def { + kind: DefKind::Function, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: MethodData) -> Option { + Some(Def { + kind: DefKind::Method, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: data.decl_id.map(|id| From::from(id)), + }) + } +} +impl From for Option { + fn from(data: MacroData) -> Option { + Some(Def { + kind: DefKind::Macro, + id: From::from(null_def_id()), + span: data.span, + name: data.name, + qualname: data.qualname, + value: String::new(), + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data:ModData) -> Option { + Some(Def { + kind: DefKind::Mod, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.filename, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: TypeDefData) -> Option { + Some(Def { + kind: DefKind::Type, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: VariableData) -> Option { + Some(Def { + kind: match data.kind { + VariableKind::Static => DefKind::Static, + VariableKind::Const => DefKind::Const, + VariableKind::Local => { return None } + VariableKind::Field => DefKind::Field, + }, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }) + } +} diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 77273bd3f2ed2..5aa8bec3d36c2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -30,6 +30,7 @@ extern crate serialize as rustc_serialize; extern crate syntax_pos; mod csv_dumper; +mod json_api_dumper; mod json_dumper; mod data; mod dump; @@ -57,6 +58,7 @@ use syntax::codemap::MacroAttribute; use syntax_pos::*; pub use self::csv_dumper::CsvDumper; +pub use self::json_api_dumper::JsonApiDumper; pub use self::json_dumper::JsonDumper; pub use self::data::*; pub use self::dump::Dump; @@ -804,7 +806,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, match format { Format::Csv => dump!(CsvDumper::new(output)), Format::Json => dump!(JsonDumper::new(output)), - Format::JsonApi => /* TODO */ dump!(JsonDumper::new(output)), + Format::JsonApi => dump!(JsonApiDumper::new(output)), } } From 4e4306c6dfa7a8dd43a7ee9bbc531f4b14b03aec Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 16:46:55 +1200 Subject: [PATCH 434/768] Thread visibility info through save-analysis and filter save-analysis-api on it. --- src/librustc_save_analysis/data.rs | 47 +++- src/librustc_save_analysis/dump_visitor.rs | 39 ++- src/librustc_save_analysis/external_data.rs | 28 ++- src/librustc_save_analysis/json_api_dumper.rs | 228 ++++++++++-------- src/librustc_save_analysis/lib.rs | 15 +- 5 files changed, 235 insertions(+), 122 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 493f7669337fe..b882765788893 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -13,8 +13,9 @@ //! The `Dump` trait can be used together with `DumpVisitor` in order to //! retrieve the data from a crate. +use rustc::hir; use rustc::hir::def_id::DefId; -use syntax::ast::{CrateNum, NodeId}; +use syntax::ast::{self, CrateNum, NodeId}; use syntax_pos::Span; pub struct CrateData { @@ -76,6 +77,35 @@ pub enum Data { VariableRefData(VariableRefData), } +#[derive(Eq, PartialEq, Clone, Copy, Debug, RustcEncodable)] +pub enum Visibility { + Public, + Restricted, + Inherited, +} + +impl<'a> From<&'a ast::Visibility> for Visibility { + fn from(v: &'a ast::Visibility) -> Visibility { + match *v { + ast::Visibility::Public => Visibility::Public, + ast::Visibility::Crate(_) => Visibility::Restricted, + ast::Visibility::Restricted { .. } => Visibility::Restricted, + ast::Visibility::Inherited => Visibility::Inherited, + } + } +} + +impl<'a> From<&'a hir::Visibility> for Visibility { + fn from(v: &'a hir::Visibility) -> Visibility { + match *v { + hir::Visibility::Public => Visibility::Public, + hir::Visibility::Crate => Visibility::Restricted, + hir::Visibility::Restricted { .. } => Visibility::Restricted, + hir::Visibility::Inherited => Visibility::Inherited, + } + } +} + /// Data for the prelude of a crate. #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { @@ -103,7 +133,7 @@ pub struct EnumData { pub span: Span, pub scope: NodeId, pub variants: Vec, - + pub visibility: Visibility, } /// Data for extern crates. @@ -135,6 +165,7 @@ pub struct FunctionData { pub span: Span, pub scope: NodeId, pub value: String, + pub visibility: Visibility, } /// Data about a function call. @@ -215,6 +246,7 @@ pub struct MethodData { pub scope: NodeId, pub value: String, pub decl_id: Option, + pub visibility: Visibility, } /// Data for modules. @@ -227,6 +259,7 @@ pub struct ModData { pub scope: NodeId, pub filename: String, pub items: Vec, + pub visibility: Visibility, } /// Data for a reference to a module. @@ -248,6 +281,7 @@ pub struct StructData { pub scope: NodeId, pub value: String, pub fields: Vec, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -270,6 +304,7 @@ pub struct TraitData { pub scope: NodeId, pub value: String, pub items: Vec, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -291,6 +326,7 @@ pub struct TypeDefData { pub span: Span, pub qualname: String, pub value: String, + pub visibility: Visibility, } /// Data for a reference to a type or trait. @@ -308,7 +344,8 @@ pub struct UseData { pub span: Span, pub name: String, pub mod_id: Option, - pub scope: NodeId + pub scope: NodeId, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -316,7 +353,8 @@ pub struct UseGlobData { pub id: NodeId, pub span: Span, pub names: Vec, - pub scope: NodeId + pub scope: NodeId, + pub visibility: Visibility, } /// Data for local and global variables (consts and statics). @@ -330,6 +368,7 @@ pub struct VariableData { pub scope: NodeId, pub value: String, pub type_value: String, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index dbe956f021e4c..e0475bfed931a 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -364,7 +364,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}::{}", qualname, path_to_string(p)), type_value: typ, value: String::new(), - scope: 0 + scope: 0, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -376,6 +377,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { body: Option<&ast::Block>, id: ast::NodeId, name: ast::Name, + vis: Visibility, span: Span) { debug!("process_method: {}:{}", id, name); @@ -416,6 +418,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: method_data.qualname.clone(), value: sig_str, decl_id: decl_id, + visibility: vis, }.lower(self.tcx)); } @@ -483,7 +486,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: name, id: param.id, qualname: qualname, - value: String::new() + value: String::new(), + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -532,7 +536,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: ast::Name, span: Span, typ: &ast::Ty, - expr: &ast::Expr) { + expr: &ast::Expr, + vis: Visibility) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -546,7 +551,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, value: self.span.snippet(expr.span), type_value: ty_to_string(&typ), - scope: self.cur_scope + scope: self.cur_scope, + visibility: vis, }.lower(self.tcx)); } @@ -588,6 +594,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, value: val, fields: fields, + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -744,6 +751,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, value: val, items: methods.iter().map(|i| i.id).collect(), + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -989,7 +997,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: typ, - scope: 0 + scope: 0, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -1072,7 +1081,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> id: item.id, mod_id: mod_id, name: ident.to_string(), - scope: self.cur_scope + scope: self.cur_scope, + visibility: From::from(&item.vis), }.lower(self.tcx)); } self.write_sub_paths_truncated(path, true); @@ -1095,7 +1105,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> span: sub_span.expect("No span found for use glob"), id: item.id, names: names, - scope: self.cur_scope + scope: self.cur_scope, + visibility: From::from(&item.vis), }.lower(self.tcx)); } self.write_sub_paths(path, true); @@ -1167,7 +1178,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> name: item.ident.to_string(), id: item.id, qualname: qualname.clone(), - value: value + value: value, + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -1200,13 +1212,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> trait_item.ident.name, trait_item.span, &ty, - &expr); + &expr, + Visibility::Public); } ast::TraitItemKind::Method(ref sig, ref body) => { self.process_method(sig, body.as_ref().map(|x| &**x), trait_item.id, trait_item.ident.name, + Visibility::Public, trait_item.span); } ast::TraitItemKind::Const(_, None) | @@ -1223,13 +1237,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> impl_item.ident.name, impl_item.span, &ty, - &expr); + &expr, + From::from(&impl_item.vis)); } ast::ImplItemKind::Method(ref sig, ref body) => { self.process_method(sig, Some(body), impl_item.id, impl_item.ident.name, + From::from(&impl_item.vis), impl_item.span); } ast::ImplItemKind::Type(_) | @@ -1399,7 +1415,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: String::new(), - scope: 0 + scope: 0, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 65e4f7e869b0d..b7dded7b6247b 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -15,7 +15,7 @@ use syntax::ast::{CrateNum, NodeId}; use syntax::codemap::CodeMap; use syntax_pos::Span; -use data; +use data::{self, Visibility}; // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet pub trait Lower { @@ -91,7 +91,8 @@ pub struct EnumData { pub qualname: String, pub span: SpanData, pub scope: DefId, - pub variants: Vec + pub variants: Vec, + pub visibility: Visibility, } impl Lower for data::EnumData { @@ -106,6 +107,7 @@ impl Lower for data::EnumData { span: SpanData::from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.map), variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -166,6 +168,7 @@ pub struct FunctionData { pub span: SpanData, pub scope: DefId, pub value: String, + pub visibility: Visibility, } impl Lower for data::FunctionData { @@ -180,6 +183,7 @@ impl Lower for data::FunctionData { span: SpanData::from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.map), value: self.value, + visibility: self.visibility, } } } @@ -323,6 +327,7 @@ pub struct MethodData { pub scope: DefId, pub value: String, pub decl_id: Option, + pub visibility: Visibility, } impl Lower for data::MethodData { @@ -337,6 +342,7 @@ impl Lower for data::MethodData { qualname: self.qualname, value: self.value, decl_id: self.decl_id, + visibility: self.visibility, } } } @@ -351,6 +357,7 @@ pub struct ModData { pub scope: DefId, pub filename: String, pub items: Vec, + pub visibility: Visibility, } impl Lower for data::ModData { @@ -365,6 +372,7 @@ impl Lower for data::ModData { scope: make_def_id(self.scope, &tcx.map), filename: self.filename, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -401,6 +409,7 @@ pub struct StructData { pub scope: DefId, pub value: String, pub fields: Vec, + pub visibility: Visibility, } impl Lower for data::StructData { @@ -416,6 +425,7 @@ impl Lower for data::StructData { scope: make_def_id(self.scope, &tcx.map), value: self.value, fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -456,6 +466,7 @@ pub struct TraitData { pub scope: DefId, pub value: String, pub items: Vec, + pub visibility: Visibility, } impl Lower for data::TraitData { @@ -470,6 +481,7 @@ impl Lower for data::TraitData { scope: make_def_id(self.scope, &tcx.map), value: self.value, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -509,6 +521,7 @@ pub struct TypeDefData { pub span: SpanData, pub qualname: String, pub value: String, + pub visibility: Visibility, } impl Lower for data::TypeDefData { @@ -521,6 +534,7 @@ impl Lower for data::TypeDefData { span: SpanData::from_span(self.span, tcx.sess.codemap()), qualname: self.qualname, value: self.value, + visibility: self.visibility, } } } @@ -553,7 +567,8 @@ pub struct UseData { pub span: SpanData, pub name: String, pub mod_id: Option, - pub scope: DefId + pub scope: DefId, + pub visibility: Visibility, } impl Lower for data::UseData { @@ -566,6 +581,7 @@ impl Lower for data::UseData { name: self.name, mod_id: self.mod_id, scope: make_def_id(self.scope, &tcx.map), + visibility: self.visibility, } } } @@ -575,7 +591,8 @@ pub struct UseGlobData { pub id: DefId, pub span: SpanData, pub names: Vec, - pub scope: DefId + pub scope: DefId, + pub visibility: Visibility, } impl Lower for data::UseGlobData { @@ -587,6 +604,7 @@ impl Lower for data::UseGlobData { span: SpanData::from_span(self.span, tcx.sess.codemap()), names: self.names, scope: make_def_id(self.scope, &tcx.map), + visibility: self.visibility, } } } @@ -602,6 +620,7 @@ pub struct VariableData { pub scope: DefId, pub value: String, pub type_value: String, + pub visibility: Visibility, } impl Lower for data::VariableData { @@ -617,6 +636,7 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, + visibility: self.visibility, } } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index e92c23d7d7c5a..9cc1badf7cdd9 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId; use rustc_serialize::json::as_json; use external_data::*; -use data::VariableKind; +use data::{VariableKind, Visibility}; use dump::Dump; pub struct JsonApiDumper<'b, W: Write + 'b> { @@ -123,24 +123,30 @@ enum ImportKind { impl From for Option { fn from(data: UseData) -> Option { - Some(Import { - kind: ImportKind::Use, - id: From::from(data.id), - span: data.span, - name: data.name, - value: String::new(), - }) + match data.visibility { + Visibility::Public => Some(Import { + kind: ImportKind::Use, + id: From::from(data.id), + span: data.span, + name: data.name, + value: String::new(), + }), + _ => None, + } } } impl From for Option { fn from(data: UseGlobData) -> Option { - Some(Import { - kind: ImportKind::GlobUse, - id: From::from(data.id), - span: data.span, - name: "*".to_owned(), - value: data.names.join(", "), - }) + match data.visibility { + Visibility::Public => Some(Import { + kind: ImportKind::GlobUse, + id: From::from(data.id), + span: data.span, + name: "*".to_owned(), + value: data.names.join(", "), + }), + _ => None, + } } } @@ -185,17 +191,20 @@ enum DefKind { impl From for Option { fn from(data: EnumData) -> Option { - Some(Def { - kind: DefKind::Enum, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - parent: None, - children: data.variants.into_iter().map(|id| From::from(id)).collect(), - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Enum, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.variants.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }), + _ => None, + } } } @@ -231,7 +240,8 @@ impl From for Option { } impl From for Option { fn from(data: StructData) -> Option { - Some(Def { + match data.visibility { + Visibility::Public => Some(Def { kind: DefKind::Struct, id: From::from(data.id), span: data.span, @@ -241,52 +251,63 @@ impl From for Option { parent: None, children: data.fields.into_iter().map(|id| From::from(id)).collect(), decl_id: None, - }) + }), + _ => None, + } } } impl From for Option { fn from(data: TraitData) -> Option { - Some(Def { - kind: DefKind::Trait, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: data.items.into_iter().map(|id| From::from(id)).collect(), - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Trait, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: FunctionData) -> Option { - Some(Def { - kind: DefKind::Function, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Function, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: MethodData) -> Option { - Some(Def { - kind: DefKind::Method, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: data.decl_id.map(|id| From::from(id)), - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Method, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: data.decl_id.map(|id| From::from(id)), + }), + _ => None, + } } } impl From for Option { @@ -306,51 +327,60 @@ impl From for Option { } impl From for Option { fn from(data:ModData) -> Option { - Some(Def { - kind: DefKind::Mod, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.filename, - children: data.items.into_iter().map(|id| From::from(id)).collect(), - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Mod, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.filename, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: TypeDefData) -> Option { - Some(Def { - kind: DefKind::Type, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Type, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: VariableData) -> Option { - Some(Def { - kind: match data.kind { - VariableKind::Static => DefKind::Static, - VariableKind::Const => DefKind::Const, - VariableKind::Local => { return None } - VariableKind::Field => DefKind::Field, - }, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: match data.kind { + VariableKind::Static => DefKind::Static, + VariableKind::Const => DefKind::Const, + VariableKind::Local => { return None } + VariableKind::Field => DefKind::Field, + }, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }), + _ => None, + } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 5aa8bec3d36c2..3645eb68394d9 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -140,6 +140,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), value: make_signature(decl, generics), + visibility: From::from(&item.vis), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -164,6 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: value, type_value: ty_to_string(&typ), + visibility: From::from(&item.vis), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -179,6 +181,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), + visibility: From::from(&item.vis), })) } ast::ItemKind::Mod(ref m) => { @@ -197,6 +200,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), filename: filename, items: m.items.iter().map(|i| i.id).collect(), + visibility: From::from(&item.vis), })) } ast::ItemKind::Enum(ref def, _) => { @@ -217,6 +221,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, scope: self.enclosing_scope(item.id), variants: def.variants.iter().map(|v| v.node.data.id()).collect(), + visibility: From::from(&item.vis), })) } ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => { @@ -281,6 +286,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: scope, value: "".to_owned(), type_value: typ, + visibility: From::from(&field.vis), }) } else { None @@ -293,7 +299,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, vis) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -306,7 +312,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - result + (result, From::from(&item.vis)) } _ => { span_bug!(span, @@ -327,8 +333,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) { Some(def_id) => { match self.tcx.map.get_if_local(def_id) { - Some(NodeItem(_)) => { - format!("::{}", self.tcx.item_path_str(def_id)) + Some(NodeItem(item)) => { + (format!("::{}", self.tcx.item_path_str(def_id)), From::from(&item.vis)) } r => { span_bug!(span, @@ -369,6 +375,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(id), // FIXME you get better data here by using the visitor. value: String::new(), + visibility: vis, }) } From 4dc7b585a2d7784e5c8a8e390c77441df4aea29b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 30 Aug 2016 16:00:48 +1200 Subject: [PATCH 435/768] save-analysis: add parent info to api dumps The parent id is used for constructing rustdoc URLs by clients --- src/librustc_driver/driver.rs | 3 +- src/librustc_save_analysis/data.rs | 9 +- src/librustc_save_analysis/dump_visitor.rs | 131 ++++++++++-------- src/librustc_save_analysis/external_data.rs | 14 +- src/librustc_save_analysis/json_api_dumper.rs | 19 ++- src/librustc_save_analysis/lib.rs | 6 + src/test/run-make/save-analysis/Makefile | 1 + 7 files changed, 113 insertions(+), 70 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b5..df1378f9e0d0a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -248,7 +248,8 @@ fn keep_hygiene_data(sess: &Session) -> bool { fn keep_ast(sess: &Session) -> bool { sess.opts.debugging_opts.keep_ast || sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.save_analysis_csv || + sess.opts.debugging_opts.save_analysis_api } /// The name used for source code that doesn't originate in a file diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index b882765788893..a58cce0745f30 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -166,6 +166,7 @@ pub struct FunctionData { pub scope: NodeId, pub value: String, pub visibility: Visibility, + pub parent: Option, } /// Data about a function call. @@ -292,7 +293,8 @@ pub struct StructVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: NodeId + pub scope: NodeId, + pub parent: Option, } #[derive(Debug, RustcEncodable)] @@ -315,7 +317,8 @@ pub struct TupleVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: NodeId + pub scope: NodeId, + pub parent: Option, } /// Data for a typedef. @@ -327,6 +330,7 @@ pub struct TypeDefData { pub qualname: String, pub value: String, pub visibility: Visibility, + pub parent: Option, } /// Data for a reference to a type or trait. @@ -366,6 +370,7 @@ pub struct VariableData { pub qualname: String, pub span: Span, pub scope: NodeId, + pub parent: Option, pub value: String, pub type_value: String, pub visibility: Visibility, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index e0475bfed931a..c4eba4171de04 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -365,6 +365,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { type_value: typ, value: String::new(), scope: 0, + parent: None, visibility: Visibility::Inherited, }.lower(self.tcx)); } @@ -488,6 +489,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, value: String::new(), visibility: Visibility::Inherited, + parent: None, }.lower(self.tcx)); } } @@ -531,13 +533,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_expr(expr); } - fn process_const(&mut self, - id: ast::NodeId, - name: ast::Name, - span: Span, - typ: &ast::Ty, - expr: &ast::Expr, - vis: Visibility) { + fn process_assoc_const(&mut self, + id: ast::NodeId, + name: ast::Name, + span: Span, + typ: &ast::Ty, + expr: &ast::Expr, + parent_id: NodeId, + vis: Visibility) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -552,6 +555,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: self.span.snippet(expr.span), type_value: ty_to_string(&typ), scope: self.cur_scope, + parent: Some(parent_id), visibility: vis, }.lower(self.tcx)); } @@ -646,7 +650,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, type_value: enum_data.qualname.clone(), value: val, - scope: enum_data.scope + scope: enum_data.scope, + parent: Some(item.id), }.lower(self.tcx)); } } @@ -669,7 +674,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, type_value: enum_data.qualname.clone(), value: val, - scope: enum_data.scope + scope: enum_data.scope, + parent: Some(item.id), }.lower(self.tcx)); } } @@ -722,7 +728,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { - self.visit_impl_item(impl_item); + self.process_impl_item(impl_item, item.id); } } @@ -792,7 +798,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // walk generics and methods self.process_generic_params(generics, item.span, &qualname, item.id); for method in methods { - self.visit_trait_item(method) + self.process_trait_item(method, item.id) } } @@ -998,6 +1004,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: value, type_value: typ, scope: 0, + parent: None, visibility: Visibility::Inherited, }.lower(self.tcx)); } @@ -1046,6 +1053,57 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } + + fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: NodeId) { + self.process_macro_use(trait_item.span, trait_item.id); + match trait_item.node { + ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { + self.process_assoc_const(trait_item.id, + trait_item.ident.name, + trait_item.span, + &ty, + &expr, + trait_id, + Visibility::Public); + } + ast::TraitItemKind::Method(ref sig, ref body) => { + self.process_method(sig, + body.as_ref().map(|x| &**x), + trait_item.id, + trait_item.ident.name, + Visibility::Public, + trait_item.span); + } + ast::TraitItemKind::Const(_, None) | + ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Macro(_) => {} + } + } + + fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: NodeId) { + self.process_macro_use(impl_item.span, impl_item.id); + match impl_item.node { + ast::ImplItemKind::Const(ref ty, ref expr) => { + self.process_assoc_const(impl_item.id, + impl_item.ident.name, + impl_item.span, + &ty, + &expr, + impl_id, + From::from(&impl_item.vis)); + } + ast::ImplItemKind::Method(ref sig, ref body) => { + self.process_method(sig, + Some(body), + impl_item.id, + impl_item.ident.name, + From::from(&impl_item.vis), + impl_item.span); + } + ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Macro(_) => {} + } + } } impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> { @@ -1180,6 +1238,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> qualname: qualname.clone(), value: value, visibility: From::from(&item.vis), + parent: None, }.lower(self.tcx)); } @@ -1204,55 +1263,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { - self.process_macro_use(trait_item.span, trait_item.id); - match trait_item.node { - ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { - self.process_const(trait_item.id, - trait_item.ident.name, - trait_item.span, - &ty, - &expr, - Visibility::Public); - } - ast::TraitItemKind::Method(ref sig, ref body) => { - self.process_method(sig, - body.as_ref().map(|x| &**x), - trait_item.id, - trait_item.ident.name, - Visibility::Public, - trait_item.span); - } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | - ast::TraitItemKind::Macro(_) => {} - } - } - - fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { - self.process_macro_use(impl_item.span, impl_item.id); - match impl_item.node { - ast::ImplItemKind::Const(ref ty, ref expr) => { - self.process_const(impl_item.id, - impl_item.ident.name, - impl_item.span, - &ty, - &expr, - From::from(&impl_item.vis)); - } - ast::ImplItemKind::Method(ref sig, ref body) => { - self.process_method(sig, - Some(body), - impl_item.id, - impl_item.ident.name, - From::from(&impl_item.vis), - impl_item.span); - } - ast::ImplItemKind::Type(_) | - ast::ImplItemKind::Macro(_) => {} - } - } - fn visit_ty(&mut self, t: &ast::Ty) { self.process_macro_use(t.span, t.id); match t.node { @@ -1416,6 +1426,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> value: value, type_value: String::new(), scope: 0, + parent: None, visibility: Visibility::Inherited, }.lower(self.tcx)); } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index b7dded7b6247b..4333c6dd18e60 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -169,6 +169,7 @@ pub struct FunctionData { pub scope: DefId, pub value: String, pub visibility: Visibility, + pub parent: Option, } impl Lower for data::FunctionData { @@ -184,6 +185,7 @@ impl Lower for data::FunctionData { scope: make_def_id(self.scope, &tcx.map), value: self.value, visibility: self.visibility, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -328,6 +330,7 @@ pub struct MethodData { pub value: String, pub decl_id: Option, pub visibility: Visibility, + pub parent: Option } impl Lower for data::MethodData { @@ -343,6 +346,7 @@ impl Lower for data::MethodData { value: self.value, decl_id: self.decl_id, visibility: self.visibility, + parent: Some(make_def_id(self.scope, &tcx.map)), } } } @@ -438,7 +442,8 @@ pub struct StructVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: DefId + pub scope: DefId, + pub parent: Option, } impl Lower for data::StructVariantData { @@ -453,6 +458,7 @@ impl Lower for data::StructVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -495,6 +501,7 @@ pub struct TupleVariantData { pub type_value: String, pub value: String, pub scope: DefId, + pub parent: Option, } impl Lower for data::TupleVariantData { @@ -509,6 +516,7 @@ impl Lower for data::TupleVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -522,6 +530,7 @@ pub struct TypeDefData { pub qualname: String, pub value: String, pub visibility: Visibility, + pub parent: Option, } impl Lower for data::TypeDefData { @@ -535,6 +544,7 @@ impl Lower for data::TypeDefData { qualname: self.qualname, value: self.value, visibility: self.visibility, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -620,6 +630,7 @@ pub struct VariableData { pub scope: DefId, pub value: String, pub type_value: String, + pub parent: Option, pub visibility: Visibility, } @@ -636,6 +647,7 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), visibility: self.visibility, } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 9cc1badf7cdd9..874babb907e4c 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -17,6 +17,13 @@ use external_data::*; use data::{VariableKind, Visibility}; use dump::Dump; +// A dumper to dump a restricted set of JSON information, designed for use with +// libraries distributed without their source. Clients are likely to use type +// information here, and (for example) generate Rustdoc URLs, but don't need +// information for navigating the source of the crate. +// Relative to the regular JSON save-analysis info, this form is filtered to +// remove non-visible items, but includes some extra info for items (e.g., the +// parent field for finding the struct to which a field belongs). pub struct JsonApiDumper<'b, W: Write + 'b> { output: &'b mut W, result: Analysis, @@ -217,7 +224,7 @@ impl From for Option { name: data.name, qualname: data.qualname, value: data.value, - parent: None, + parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, }) @@ -232,7 +239,7 @@ impl From for Option { name: data.name, qualname: data.qualname, value: data.value, - parent: None, + parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, }) @@ -285,7 +292,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: None, }), _ => None, @@ -303,7 +310,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: data.decl_id.map(|id| From::from(id)), }), _ => None, @@ -354,7 +361,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: None, }), _ => None, @@ -377,7 +384,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: None, }), _ => None, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 3645eb68394d9..9478e25cff7e0 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -141,6 +141,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: make_signature(decl, generics), visibility: From::from(&item.vis), + parent: None, })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -163,6 +164,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), + parent: None, value: value, type_value: ty_to_string(&typ), visibility: From::from(&item.vis), @@ -179,6 +181,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), + parent: None, value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), visibility: From::from(&item.vis), @@ -284,6 +287,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: scope, + parent: Some(scope), value: "".to_owned(), type_value: typ, visibility: From::from(&field.vis), @@ -366,6 +370,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); + let parent_scope = self.enclosing_scope(id); Some(FunctionData { id: id, name: name.to_string(), @@ -376,6 +381,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME you get better data here by using the visitor. value: String::new(), visibility: vis, + parent: Some(parent_scope), }) } diff --git a/src/test/run-make/save-analysis/Makefile b/src/test/run-make/save-analysis/Makefile index 3c636baaedc5f..3711b6ea8959b 100644 --- a/src/test/run-make/save-analysis/Makefile +++ b/src/test/run-make/save-analysis/Makefile @@ -5,3 +5,4 @@ krate2: krate2.rs code: foo.rs krate2 $(RUSTC) foo.rs -Zsave-analysis-csv $(RUSTC) foo.rs -Zsave-analysis + $(RUSTC) foo.rs -Zsave-analysis-api From 377be7a5014052766784b2dda1d5b5e33e191b6b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 30 Aug 2016 16:40:44 +1200 Subject: [PATCH 436/768] review comments --- src/librustc/session/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8eb80472d6e09..5720978816249 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -848,7 +848,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate"), save_analysis: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in JSON format) information, \ + "write syntax and type analysis (in JSON format) information, in \ addition to normal output"), save_analysis_csv: bool = (false, parse_bool, [UNTRACKED], "write syntax and type analysis (in CSV format) information, in addition to normal output"), From 3d766a077944f167dbd412538af4c6957943374d Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Thu, 1 Sep 2016 10:35:37 +0200 Subject: [PATCH 437/768] the win64 calling convention is also used on x86_64-pc-windows-gnu, so ignore windows entirely instead of just msvc --- src/test/run-pass/abi-sysv64-arg-passing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs index 3f6ae71ffa8e7..989155bdfd98b 100644 --- a/src/test/run-pass/abi-sysv64-arg-passing.rs +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -35,9 +35,9 @@ // ignore-android // ignore-arm // ignore-aarch64 -// ignore-msvc +// ignore-windows -// note: msvc is ignored as rust_test_helpers does not have the sysv64 abi on msvc +// note: windows is ignored as rust_test_helpers does not have the sysv64 abi on windows #![feature(abi_sysv64)] #[allow(dead_code)] From 7b92d05804bea222dc6904274f9fc186a6c5208a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 1 Sep 2016 13:34:56 +0300 Subject: [PATCH 438/768] turn the RFC1592 warnings into hard errors The warnings have already reached stable The test rfc1592_deprecated is covered by `bad_sized` and `unsized6`. Fixes #33242 Fixes #33243 --- src/librustc/lint/builtin.rs | 14 --- src/librustc/middle/free_region.rs | 1 - src/librustc/traits/error_reporting.rs | 122 ++++--------------- src/librustc/traits/fulfill.rs | 38 ------ src/librustc/traits/object_safety.rs | 2 - src/librustc/traits/select.rs | 16 +-- src/librustc/traits/util.rs | 6 - src/librustc/ty/mod.rs | 17 +-- src/librustc/ty/structural_impls.rs | 6 - src/librustc/ty/util.rs | 1 - src/librustc/ty/wf.rs | 32 ++--- src/librustc/util/ppaux.rs | 4 - src/librustc_lint/lib.rs | 8 -- src/librustc_metadata/tyencode.rs | 3 - src/librustc_mir/transform/qualify_consts.rs | 4 - src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/closure.rs | 1 - src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 - src/librustc_typeck/check/method/probe.rs | 1 - src/librustc_typeck/check/mod.rs | 8 -- src/librustc_typeck/collect.rs | 1 - src/librustdoc/clean/mod.rs | 1 - src/test/compile-fail/bad-sized.rs | 2 + src/test/compile-fail/issue-32963.rs | 1 + src/test/compile-fail/rfc1592-deprecated.rs | 32 ----- src/test/compile-fail/unsized6.rs | 4 +- src/test/run-pass/rfc1592-deprecated.rs | 29 ----- 28 files changed, 50 insertions(+), 314 deletions(-) delete mode 100644 src/test/compile-fail/rfc1592-deprecated.rs delete mode 100644 src/test/run-pass/rfc1592-deprecated.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index b2ee38741fcab..ed94e5fe377c4 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -186,18 +186,6 @@ declare_lint! { "detects super or self keywords at the beginning of global path" } -declare_lint! { - pub UNSIZED_IN_TUPLE, - Warn, - "unsized types in the interior of a tuple were erroneously allowed" -} - -declare_lint! { - pub OBJECT_UNSAFE_FRAGMENT, - Warn, - "object-unsafe non-principal fragments in object types were erroneously allowed" -} - declare_lint! { pub LIFETIME_UNDERSCORE, Warn, @@ -239,8 +227,6 @@ impl LintPass for HardwiredLints { OVERLAPPING_INHERENT_IMPLS, RENAMED_AND_REMOVED_LINTS, SUPER_OR_SELF_IN_GLOBAL_PATH, - UNSIZED_IN_TUPLE, - OBJECT_UNSAFE_FRAGMENT, HR_LIFETIME_IN_ASSOC_TYPE, LIFETIME_UNDERSCORE ) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 8193d062631c1..bd35bfc9829a5 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -55,7 +55,6 @@ impl FreeRegionMap { match *predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8318a29de1c54..6d6d7c2b3ba0a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,27 +36,23 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; -use syntax::ast; use syntax_pos::Span; use errors::DiagnosticBuilder; #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { span: Span, - warning_node_id: Option, predicate: ty::Predicate<'tcx> } impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - e: &FulfillmentError<'tcx>, - warning_node_id: Option) -> Self { + e: &FulfillmentError<'tcx>) -> Self { let predicate = infcx.resolve_type_vars_if_possible(&e.obligation.predicate); TraitErrorKey { span: e.obligation.cause.span, - predicate: infcx.tcx.erase_regions(&predicate), - warning_node_id: warning_node_id + predicate: infcx.tcx.erase_regions(&predicate) } } } @@ -64,22 +60,13 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_fulfillment_errors(&self, errors: &Vec>) { for error in errors { - self.report_fulfillment_error(error, None); - } - } - - pub fn report_fulfillment_errors_as_warnings(&self, - errors: &Vec>, - node_id: ast::NodeId) { - for error in errors { - self.report_fulfillment_error(error, Some(node_id)); + self.report_fulfillment_error(error); } } fn report_fulfillment_error(&self, - error: &FulfillmentError<'tcx>, - warning_node_id: Option) { - let error_key = TraitErrorKey::from_error(self, error, warning_node_id); + error: &FulfillmentError<'tcx>) { + let error_key = TraitErrorKey::from_error(self, error); debug!("report_fulfillment_errors({:?}) - key={:?}", error, error_key); if !self.reported_trait_errors.borrow_mut().insert(error_key) { @@ -88,10 +75,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } match error.code { FulfillmentErrorCode::CodeSelectionError(ref e) => { - self.report_selection_error(&error.obligation, e, warning_node_id); + self.report_selection_error(&error.obligation, e); } FulfillmentErrorCode::CodeProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e, warning_node_id); + self.report_projection_error(&error.obligation, e); } FulfillmentErrorCode::CodeAmbiguity => { self.maybe_report_ambiguity(&error.obligation); @@ -101,8 +88,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn report_projection_error(&self, obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - warning_node_id: Option) + error: &MismatchedProjectionTypes<'tcx>) { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); @@ -110,16 +96,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if predicate.references_error() { return } - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("type mismatch resolving `{}`: {}", - predicate, - error.err)); - return - } + self.probe(|_| { let origin = TypeOrigin::Misc(obligation.cause.span); let err_buf; @@ -442,8 +419,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_selection_error(&self, obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - warning_node_id: Option) + error: &SelectionError<'tcx>) { let span = obligation.cause.span; let mut err = match *error { @@ -466,16 +442,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { let trait_ref = trait_predicate.to_poly_trait_ref(); - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("the trait bound `{}` is not satisfied", - trait_ref.to_predicate())); - return; - } - let mut err = struct_span_err!(self.tcx.sess, span, E0277, "the trait bound `{}` is not satisfied", trait_ref.to_predicate()); @@ -541,15 +507,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - let err = self.tcx.report_object_safety_error(span, - trait_def_id, - warning_node_id, - violations); - if let Some(err) = err { - err - } else { - return; - } + self.tcx.report_object_safety_error(span, + trait_def_id, + violations) } ty::Predicate::ClosureKind(closure_def_id, kind) => { @@ -577,13 +537,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } - - ty::Predicate::Rfc1592(ref data) => { - span_bug!( - obligation.cause.span, - "RFC1592 predicate not satisfied for {:?}", - data); - } } } } @@ -605,14 +558,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - let err = self.tcx.report_object_safety_error(span, did, - warning_node_id, - violations); - if let Some(err) = err { - err - } else { - return; - } + self.tcx.report_object_safety_error(span, did, + violations) } }; self.note_obligation_cause(&mut err, obligation); @@ -640,24 +587,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn report_object_safety_error(self, span: Span, trait_def_id: DefId, - warning_node_id: Option, violations: Vec) - -> Option> + -> DiagnosticBuilder<'tcx> { - let mut err = match warning_node_id { - Some(_) => None, - None => { - let trait_str = self.item_path_str(trait_def_id); - let mut db = struct_span_err!( - self.sess, span, E0038, - "the trait `{}` cannot be made into an object", - trait_str); - db.span_label(span, - &format!("the trait `{}` cannot be made \ - into an object", trait_str)); - Some(db) - } - }; + let trait_str = self.item_path_str(trait_def_id); + let mut err = struct_span_err!( + self.sess, span, E0038, + "the trait `{}` cannot be made into an object", + trait_str); + err.span_label(span, &format!( + "the trait `{}` cannot be made into an object", trait_str + )); let mut reported_violations = FnvHashSet(); for violation in violations { @@ -697,19 +637,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { &buf } }; - match (warning_node_id, &mut err) { - (Some(node_id), &mut None) => { - self.sess.add_lint( - ::lint::builtin::OBJECT_UNSAFE_FRAGMENT, - node_id, - span, - note.to_string()); - } - (None, &mut Some(ref mut err)) => { - err.note(note); - } - _ => unreachable!() - } + err.note(note); } err } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 6598aacc1d3d2..65860671c4c63 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -57,9 +57,6 @@ pub struct FulfillmentContext<'tcx> { // fulfillment context. predicates: ObligationForest>, - // A list of new obligations due to RFC1592. - rfc1592_obligations: Vec>, - // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must // outlive the lifetime 'a". These constraints derive from @@ -192,7 +189,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), - rfc1592_obligations: Vec::new(), region_obligations: NodeMap(), deferred_obligations: vec![], } @@ -275,13 +271,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } - pub fn register_rfc1592_obligation(&mut self, - _infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligation: PredicateObligation<'tcx>) - { - self.rfc1592_obligations.push(obligation); - } - pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] @@ -292,21 +281,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } } - pub fn select_rfc1592_obligations(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<(),Vec>> - { - while !self.rfc1592_obligations.is_empty() { - for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) { - self.register_predicate_obligation(infcx, obligation); - } - - self.select_all_or_error(infcx)?; - } - - Ok(()) - } - pub fn select_all_or_error(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec>> @@ -362,7 +336,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { let outcome = self.predicates.process_obligations(&mut FulfillProcessor { selcx: selcx, region_obligations: &mut self.region_obligations, - rfc1592_obligations: &mut self.rfc1592_obligations, deferred_obligations: &mut self.deferred_obligations }); debug!("select: outcome={:?}", outcome); @@ -398,7 +371,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, region_obligations: &'a mut NodeMap>>, - rfc1592_obligations: &'a mut Vec>, deferred_obligations: &'a mut Vec> } @@ -413,7 +385,6 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, process_predicate(self.selcx, obligation, self.region_obligations, - self.rfc1592_obligations, self.deferred_obligations) .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { obligation: o, @@ -455,7 +426,6 @@ fn process_predicate<'a, 'gcx, 'tcx>( selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, region_obligations: &mut NodeMap>>, - rfc1592_obligations: &mut Vec>, deferred_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> @@ -644,14 +614,6 @@ fn process_predicate<'a, 'gcx, 'tcx>( s => Ok(s) } } - - ty::Predicate::Rfc1592(ref inner) => { - rfc1592_obligations.push(PredicateObligation { - predicate: ty::Predicate::clone(inner), - ..obligation.clone() - }); - Ok(Some(vec![])) - } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 219d520046762..5f7b71518291a 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -153,7 +153,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) => { false } @@ -184,7 +183,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index b015de79be5c6..0573f0c5bbaa0 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -513,8 +513,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } match obligation.predicate { - ty::Predicate::Rfc1592(..) => EvaluatedToOk, - ty::Predicate::Trait(ref t) => { assert!(!t.has_escaping_regions()); let obligation = obligation.with(t.clone()); @@ -1779,8 +1777,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, ty::TyTuple(tys) => { - // FIXME(#33242) we only need to constrain the last field - Where(ty::Binder(tys.to_vec())) + Where(ty::Binder(tys.last().into_iter().cloned().collect())) } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2508,12 +2505,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { - let mut object_dids = Some(data.principal.def_id()).into_iter(); - // FIXME(#33243) -// data.builtin_bounds.iter().flat_map(|bound| { -// tcx.lang_items.from_builtin_kind(bound).ok() -// }) -// .chain(Some(data.principal.def_id())); + let mut object_dids = + data.builtin_bounds.iter().flat_map(|bound| { + tcx.lang_items.from_builtin_kind(bound).ok() + }) + .chain(Some(data.principal.def_id())); if let Some(did) = object_dids.find(|did| { !tcx.is_object_safe(*did) }) { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 038de25312d35..2cefc2ad79646 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -23,9 +23,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::Trait(ref data) => ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), - ty::Predicate::Rfc1592(ref data) => - ty::Predicate::Rfc1592(Box::new(anonymize_predicate(tcx, data))), - ty::Predicate::Equate(ref data) => ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), @@ -150,9 +147,6 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { self.stack.extend(predicates); } - ty::Predicate::Rfc1592(..) => { - // Nothing to elaborate. - } ty::Predicate::WellFormed(..) => { // Currently, we do not elaborate WF predicates, // although we easily could. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1ea82a9c639d8..09420077a8abf 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -804,9 +804,6 @@ pub enum Predicate<'tcx> { /// would be the type parameters. Trait(PolyTraitPredicate<'tcx>), - /// A predicate created by RFC1592 - Rfc1592(Box>), - /// where `T1 == T2`. Equate(PolyEquatePredicate<'tcx>), @@ -906,8 +903,6 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { match *self { Predicate::Trait(ty::Binder(ref data)) => Predicate::Trait(ty::Binder(data.subst(tcx, substs))), - Predicate::Rfc1592(ref pi) => - Predicate::Rfc1592(Box::new(pi.subst_supertrait(tcx, trait_ref))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => @@ -1108,9 +1103,6 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Trait(ref data) => { data.skip_binder().input_types().collect() } - ty::Predicate::Rfc1592(ref data) => { - return data.walk_tys() - } ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } @@ -1148,7 +1140,6 @@ impl<'tcx> Predicate<'tcx> { Predicate::Trait(ref t) => { Some(t.to_poly_trait_ref()) } - Predicate::Rfc1592(..) | Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | @@ -1820,10 +1811,10 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } TyTuple(ref tys) => { - // FIXME(#33242) we only need to constrain the last field - tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, stack, ty) - }).collect() + match tys.last() { + None => vec![], + Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty) + } } TyEnum(adt, substs) | TyStruct(adt, substs) => { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 705cca056f24c..ad3769605abd9 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -178,9 +178,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::WellFormed(ty) => { tcx.lift(&ty).map(ty::Predicate::WellFormed) } - ty::Predicate::Rfc1592(box ref a) => { - tcx.lift(a).map(|a| ty::Predicate::Rfc1592(Box::new(a))) - } ty::Predicate::ClosureKind(closure_def_id, kind) => { Some(ty::Predicate::ClosureKind(closure_def_id, kind)) } @@ -790,8 +787,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Rfc1592(ref a) => - ty::Predicate::Rfc1592(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => @@ -812,7 +807,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), - ty::Predicate::Rfc1592(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index dd5c6a9758abf..77d16287fedc6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -318,7 +318,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 1f166cb192fa3..aef646a7aacaf 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,9 +94,6 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } - ty::Predicate::Rfc1592(ref data) => { - bug!("RFC1592 predicate `{:?}` in predicate_obligations", data); - } } wf.normalize() @@ -158,7 +155,6 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( assert!(!obligation.has_escaping_regions()); match obligation.predicate { ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | @@ -282,21 +278,14 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>, - rfc1592: bool) { + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_regions() { let cause = self.cause(cause); match self.infcx.tcx.trait_ref_for_builtin_bound(ty::BoundSized, subty) { Ok(trait_ref) => { - let predicate = trait_ref.to_predicate(); - let predicate = if rfc1592 { - ty::Predicate::Rfc1592(box predicate) - } else { - predicate - }; self.out.push( traits::Obligation::new(cause, - predicate)); + trait_ref.to_predicate())); } Err(ErrorReported) => { } } @@ -326,13 +315,13 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::TySlice(subty) | ty::TyArray(subty, _) => { - self.require_sized(subty, traits::SliceOrArrayElem, false); + self.require_sized(subty, traits::SliceOrArrayElem); } ty::TyTuple(ref tys) => { if let Some((_last, rest)) = tys.split_last() { for elem in rest { - self.require_sized(elem, traits::TupleElem, true); + self.require_sized(elem, traits::TupleElem); } } } @@ -401,22 +390,15 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); - // FIXME(#33243): remove RFC1592 - self.out.push(traits::Obligation::new( - cause.clone(), - ty::Predicate::ObjectSafe(data.principal.def_id()) - )); let component_traits = data.builtin_bounds.iter().flat_map(|bound| { tcx.lang_items.from_builtin_kind(bound).ok() - }); -// .chain(Some(data.principal.def_id())); + }) + .chain(Some(data.principal.def_id())); self.out.extend( component_traits.map(|did| { traits::Obligation::new( cause.clone(), - ty::Predicate::Rfc1592( - box ty::Predicate::ObjectSafe(did) - ) + ty::Predicate::ObjectSafe(did) )}) ); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 24b68c66e4667..7e2cc2938ca9e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -487,9 +487,6 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), - ty::Predicate::Rfc1592(ref a) => { - write!(f, "RFC1592({:?})", a) - } ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), @@ -1083,7 +1080,6 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), - ty::Predicate::Rfc1592(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 1a4330f58c3cd..0f0e9cfb35773 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -191,14 +191,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN), reference: "RFC 1445 ", }, - FutureIncompatibleInfo { - id: LintId::of(UNSIZED_IN_TUPLE), - reference: "issue #33242 ", - }, - FutureIncompatibleInfo { - id: LintId::of(OBJECT_UNSAFE_FRAGMENT), - reference: "issue #33243 ", - }, FutureIncompatibleInfo { id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE), reference: "issue #33685 ", diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 7255eae61d453..954ca878c01ef 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -479,9 +479,6 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, p: &ty::Predicate<'tcx>) { match *p { - ty::Predicate::Rfc1592(..) => { - bug!("RFC1592 predicate in metadata `{:?}`", p); - } ty::Predicate::Trait(ref trait_ref) => { write!(w, "t"); enc_trait_ref(w, cx, trait_ref.0.trait_ref); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9e076851bc37d..2fc90ab27a085 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1019,10 +1019,6 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&err); } - - if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { - infcx.report_fulfillment_errors_as_warnings(&errors, id); - } }); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f24a7cf2121eb..e15b0b4044ee3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1128,8 +1128,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.astconv_object_safety_violations(principal.def_id()); if !object_safety_violations.is_empty() { tcx.report_object_safety_error( - span, principal.def_id(), None, object_safety_violations) - .unwrap().emit(); + span, principal.def_id(), object_safety_violations) + .emit(); return tcx.types.err; } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 46e8c27f6d33b..516dd9c64221c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -165,7 +165,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::Rfc1592(..) => None, // NB: This predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 26a4705528976..365c18d5e6661 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -484,7 +484,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error(&obligation, &err, None); + self.report_selection_error(&obligation, &err); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index cede9d871ff4d..3a6076774330d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -111,10 +111,6 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( return Err(()); } - if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { - infcx.report_fulfillment_errors_as_warnings(errors, drop_impl_node_id); - } - let free_regions = FreeRegionMap::new(); infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); Ok(()) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 29366823fffdc..2e2cb2765d93d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -496,7 +496,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::TypeOutlives(..) => { None } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a7ea8bd7959fe..90a9d9bffe7dc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -505,10 +505,6 @@ pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult { if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&errors); } - - if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { - infcx.report_fulfillment_errors_as_warnings(&errors, item_id); - } }); } }) @@ -2245,10 +2241,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(()) => { } Err(errors) => { self.report_fulfillment_errors(&errors); } } - - if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(self) { - self.report_fulfillment_errors_as_warnings(errors, self.body_id); - } } /// Select as many obligations as we can at present. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 30b9d15587069..f63e7b0994761 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -477,7 +477,6 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { ty::Predicate::TypeOutlives(ref data) => { data.skip_binder().0.is_param(def.index) } - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0af3973f78d21..e4b6a30d5bcb3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -858,7 +858,6 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::WellFormed(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"), - Predicate::Rfc1592(..) => panic!("not user writable"), } } } diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 8aaf752125690..e9d0b986c1176 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,5 +13,7 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR `Trait + Sized: std::marker::Sized` is not satisfied + //~| ERROR the trait `std::marker::Sized` cannot be made into an object //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied + //~| ERROR the trait `std::marker::Sized` cannot be made into an object } diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs index c4e8f76611752..8ba95d14931e0 100644 --- a/src/test/compile-fail/issue-32963.rs +++ b/src/test/compile-fail/issue-32963.rs @@ -17,4 +17,5 @@ fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); //~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied + //~| ERROR the trait `std::marker::Copy` cannot be made into an object } diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs deleted file mode 100644 index e766f977200c3..0000000000000 --- a/src/test/compile-fail/rfc1592-deprecated.rs +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -use std::fmt; - -#[deny(warnings)] trait Foo { fn foo(&self) -> (Self, Self); } -//~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied -//~| WARNING hard error - -impl Foo for T { - fn foo(&self) -> (Self, Self) { - (*self, *self) - } -} - -#[deny(warnings)] -fn main() { - assert_eq!((11).foo(), (11, 11)); - - let junk: Box = Box::new(42); - //~^ ERROR the trait cannot require that `Self : Sized` - //~| WARNING hard error - let f = format!("{:?}", junk); - assert_eq!(f, "42"); -} diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index d40c12f67a08d..462d760a60ceb 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,9 +14,9 @@ trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); + let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied + let y: (isize, (X, usize)); } fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied diff --git a/src/test/run-pass/rfc1592-deprecated.rs b/src/test/run-pass/rfc1592-deprecated.rs deleted file mode 100644 index 81bf02587896f..0000000000000 --- a/src/test/run-pass/rfc1592-deprecated.rs +++ /dev/null @@ -1,29 +0,0 @@ -// 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. - -use std::fmt; - -trait Foo { - fn foo(&self) -> (Self, Self); -} - -impl Foo for T { - fn foo(&self) -> (Self, Self) { - (*self, *self) - } -} - -fn main() { - assert_eq!((11).foo(), (11, 11)); - - let junk: Box = Box::new(42); - let f = format!("{:?}", junk); - assert_eq!(f, "42"); -} From 7d5fa9edc9b9784cbde3550826cc0f37aa6c1501 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Thu, 1 Sep 2016 18:49:35 +0530 Subject: [PATCH 439/768] configure: check if any of the arguments contain --help Currently it checks only the first argument. Fixes #31216 --- configure | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 44fb3d368d2c7..bcc1faea3b5d8 100755 --- a/configure +++ b/configure @@ -360,6 +360,13 @@ abs_path() { (unset CDPATH && cd "$_path" > /dev/null && pwd) } +HELP=0 +for arg; do + case "$arg" in + --help) HELP=1;; + esac +done + msg "looking for configure programs" need_cmd cmp need_cmd mkdir @@ -566,11 +573,8 @@ esac OPTIONS="" -HELP=0 -if [ "$1" = "--help" ] +if [ "$HELP" -eq 1 ] then - HELP=1 - shift echo echo "Usage: $CFG_SELF [options]" echo From dd65cb223a3cd1a0fa8d98e9402f8725d606f6b2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 23 Aug 2016 13:23:58 -0400 Subject: [PATCH 440/768] Add some infrastructure for timing things where time_passes can't be used. --- src/librustc/session/config.rs | 2 + src/librustc/session/mod.rs | 33 +++++++++++++++ src/librustc/util/common.rs | 35 +++++++++++----- src/librustc_driver/driver.rs | 4 ++ src/librustc_trans/back/symbol_names.rs | 53 +++++++++++++------------ 5 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b129..79e14212db426 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -908,6 +908,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump MIR state at various points in translation"), dump_mir_dir: Option = (None, parse_opt_string, [UNTRACKED], "the directory the MIR is dumped into"), + perf_stats: bool = (false, parse_bool, [UNTRACKED], + "print some performance-related statistics"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 338c656379959..cc115cbeb85bc 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -18,6 +18,7 @@ use session::search_paths::PathKind; use session::config::{DebugInfoLevel, PanicStrategy}; use ty::tls; use util::nodemap::{NodeMap, FnvHashMap}; +use util::common::duration_to_secs_str; use mir::transform as mir_pass; use syntax::ast::{NodeId, Name}; @@ -43,6 +44,7 @@ use std::env; use std::ffi::CString; use std::rc::Rc; use std::fmt; +use std::time::Duration; use libc::c_int; pub mod config; @@ -104,9 +106,23 @@ pub struct Session { incr_comp_session: RefCell, + /// Some measurements that are being gathered during compilation. + pub perf_stats: PerfStats, + next_node_id: Cell, } +pub struct PerfStats { + // The accumulated time needed for computing the SVH of the crate + pub svh_time: Cell, + // The accumulated time spent on computing incr. comp. hashes + pub incr_comp_hashes_time: Cell, + // The number of incr. comp. hash computations performed + pub incr_comp_hashes_count: Cell, + // The accumulated time spent on computing symbol hashes + pub symbol_hash_time: Cell, +} + impl Session { pub fn local_crate_disambiguator(&self) -> token::InternedString { self.crate_disambiguator.borrow().clone() @@ -404,6 +420,17 @@ impl Session { None } } + + pub fn print_perf_stats(&self) { + println!("Total time spent computing SVHs: {}", + duration_to_secs_str(self.perf_stats.svh_time.get())); + println!("Total time spent computing incr. comp. hashes: {}", + duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get())); + println!("Total number of incr. comp. hashes computed: {}", + self.perf_stats.incr_comp_hashes_count.get()); + println!("Total time spent computing symbol hashes: {}", + duration_to_secs_str(self.perf_stats.symbol_hash_time.get())); + } } pub fn build_session(sopts: config::Options, @@ -520,6 +547,12 @@ pub fn build_session_(sopts: config::Options, available_macros: RefCell::new(HashSet::new()), imported_macro_spans: RefCell::new(HashMap::new()), incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), + perf_stats: PerfStats { + svh_time: Cell::new(Duration::from_secs(0)), + incr_comp_hashes_time: Cell::new(Duration::from_secs(0)), + incr_comp_hashes_count: Cell::new(0), + symbol_hash_time: Cell::new(Duration::from_secs(0)), + } }; init_llvm(&sess); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index bdfb97549d5d5..78f20b77f3185 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -17,7 +17,7 @@ use std::fmt::Debug; use std::hash::{Hash, BuildHasher}; use std::iter::repeat; use std::path::Path; -use std::time::Instant; +use std::time::{Duration, Instant}; use hir; use hir::intravisit; @@ -47,12 +47,6 @@ pub fn time(do_it: bool, what: &str, f: F) -> T where let rv = f(); let dur = start.elapsed(); - // Hack up our own formatting for the duration to make it easier for scripts - // to parse (always use the same number of decimal places and the same unit). - const NANOS_PER_SEC: f64 = 1_000_000_000.0; - let secs = dur.as_secs() as f64; - let secs = secs + dur.subsec_nanos() as f64 / NANOS_PER_SEC; - let mem_string = match get_resident() { Some(n) => { let mb = n as f64 / 1_000_000.0; @@ -60,14 +54,37 @@ pub fn time(do_it: bool, what: &str, f: F) -> T where } None => "".to_owned(), }; - println!("{}time: {:.3}{}\t{}", repeat(" ").take(old).collect::(), - secs, mem_string, what); + println!("{}time: {}{}\t{}", + repeat(" ").take(old).collect::(), + duration_to_secs_str(dur), + mem_string, + what); DEPTH.with(|slot| slot.set(old)); rv } +// Hack up our own formatting for the duration to make it easier for scripts +// to parse (always use the same number of decimal places and the same unit). +pub fn duration_to_secs_str(dur: Duration) -> String { + const NANOS_PER_SEC: f64 = 1_000_000_000.0; + let secs = dur.as_secs() as f64 + + dur.subsec_nanos() as f64 / NANOS_PER_SEC; + + format!("{:.3}", secs) +} + +pub fn record_time(accu: &Cell, f: F) -> T where + F: FnOnce() -> T, +{ + let start = Instant::now(); + let rv = f(); + let duration = start.elapsed(); + accu.set(duration + accu.get()); + rv +} + // Like std::macros::try!, but for Option<>. macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b5..e8137430a0646 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -233,6 +233,10 @@ pub fn compile_input(sess: &Session, // any more, we can finalize it (which involves renaming it) rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash); + if sess.opts.debugging_opts.perf_stats { + sess.print_perf_stats(); + } + controller_entry_point!(compilation_done, sess, CompileState::state_when_compilation_done(input, sess, outdir, output), diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 9b02cbe6721f3..00f29b7412ed2 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -108,6 +108,7 @@ use rustc::ty::{Ty, TyCtxt, TypeFoldable}; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; use rustc::hir::map::definitions::{DefPath, DefPathData}; +use rustc::util::common::record_time; use syntax::attr; use syntax::parse::token::{self, InternedString}; @@ -138,33 +139,35 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let tcx = scx.tcx(); - let mut hash_state = scx.symbol_hasher().borrow_mut(); - - hash_state.reset(); - - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - hash_state.input_str(&def_path.to_string(tcx)); - - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); - hash_state.input(&encoded_item_type[..]); - - // also include any type parameters (for generic items) - if let Some(substs) = substs { - for t in substs.types() { - assert!(!t.has_erasable_regions()); - assert!(!t.needs_subst()); - let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); - hash_state.input(&encoded_type[..]); + return record_time(&tcx.sess.perf_stats.symbol_hash_time, || { + let mut hash_state = scx.symbol_hasher().borrow_mut(); + + hash_state.reset(); + + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + hash_state.input_str(&def_path.to_string(tcx)); + + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); + hash_state.input(&encoded_item_type[..]); + + // also include any type parameters (for generic items) + if let Some(substs) = substs { + for t in substs.types() { + assert!(!t.has_erasable_regions()); + assert!(!t.needs_subst()); + let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); + hash_state.input(&encoded_type[..]); + } } - } - return format!("h{}", truncated_hash_result(&mut *hash_state)); + format!("h{}", truncated_hash_result(&mut *hash_state)) + }); fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { let output = symbol_hasher.result_bytes(); From 8e4f4810dcc7cc21aec13d421d211a94f29e413f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 23 Aug 2016 13:54:02 -0400 Subject: [PATCH 441/768] Fill some holes in SVH/ICH computation, making it more strict. --- src/librustc_incremental/calculate_svh/mod.rs | 34 +- .../calculate_svh/svh_visitor.rs | 321 +++++++++++++++--- src/librustc_incremental/lib.rs | 1 + 3 files changed, 291 insertions(+), 65 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index b14c20ae8d46e..6ad93d8f4733c 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,6 +35,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; +use rustc::util::common::record_time; +use rustc::session::config::DebugInfoLevel::NoDebugInfo; use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; @@ -48,12 +50,19 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IncrementalHashesMap { let _ignore = tcx.dep_graph.in_ignore(); let krate = tcx.map.krate(); - let mut visitor = HashItemsVisitor { tcx: tcx, - hashes: FnvHashMap(), - def_path_hashes: DefPathHashes::new(tcx) }; - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); - krate.visit_all_items(&mut visitor); - visitor.compute_crate_hash(); + let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo; + let mut visitor = HashItemsVisitor { + tcx: tcx, + hashes: FnvHashMap(), + def_path_hashes: DefPathHashes::new(tcx), + hash_spans: hash_spans + }; + record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { + visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), + |v| visit::walk_crate(v, krate)); + krate.visit_all_items(&mut visitor); + }); + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); visitor.hashes } @@ -61,6 +70,7 @@ struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path_hashes: DefPathHashes<'a, 'tcx>, hashes: IncrementalHashesMap, + hash_spans: bool, } impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { @@ -81,7 +91,8 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { let mut state = SipHasher::new(); walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx, - &mut self.def_path_hashes)); + &mut self.def_path_hashes, + self.hash_spans)); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash); @@ -117,9 +128,12 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { item_hashes.hash(&mut crate_state); } - for attr in &krate.attrs { - debug!("krate attr {:?}", attr); - attr.meta().hash(&mut crate_state); + { + let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, + self.tcx, + &mut self.def_path_hashes, + self.hash_spans); + visitor.hash_attributes(&krate.attrs); } let crate_hash = crate_state.finish(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c1158dc2d5fe9..de286d68fe980 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -13,10 +13,9 @@ // hash computation, but for many kinds of items the order of // declaration should be irrelevant to the ABI. -pub use self::SawExprComponent::*; -pub use self::SawStmtComponent::*; +use self::SawExprComponent::*; use self::SawAbiComponent::*; -use syntax::ast::{self, Name, NodeId}; +use syntax::ast::{self, Name, NodeId, Attribute}; use syntax::parse::token; use syntax_pos::Span; use rustc::hir; @@ -24,7 +23,6 @@ use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; -use rustc::hir::intravisit::{Visitor, FnKind}; use rustc::ty::TyCtxt; use std::hash::{Hash, SipHasher}; @@ -34,22 +32,41 @@ use super::def_path_hash::DefPathHashes; pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, pub st: &'a mut SipHasher, - // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, + hash_spans: bool, } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { pub fn new(st: &'a mut SipHasher, tcx: TyCtxt<'hash, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>) + def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, + hash_spans: bool) -> Self { - StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes } + StrictVersionHashVisitor { + st: st, + tcx: tcx, + def_path_hashes: def_path_hashes, + hash_spans: hash_spans, + } } fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { self.def_path_hashes.hash(def_id) } + + #[inline] + fn hash_span(&mut self, span: Span) { + if self.hash_spans { + let _ = span; + } + } + + fn hash_discriminant(&mut self, v: &T) { + unsafe { + ::std::intrinsics::discriminant_value(&v).hash(self.st); + } + } } // To off-load the bulk of the hash-computation on #[derive(Hash)], @@ -80,26 +97,35 @@ enum SawAbiComponent<'a> { SawIdent(token::InternedString), SawStructDef(token::InternedString), - SawLifetime(token::InternedString), - SawLifetimeDef(token::InternedString), + SawLifetime, + SawLifetimeDef(usize), SawMod, SawForeignItem, SawItem, SawTy, SawGenerics, - SawFn, SawTraitItem, SawImplItem, SawStructField, SawVariant, - SawPath, + SawPath(bool), + SawPathSegment, + SawPathParameters, + SawPathListItem, SawBlock, SawPat, SawLocal, SawArm, SawExpr(SawExprComponent<'a>), - SawStmt(SawStmtComponent), + SawStmt, + SawVis, + SawWherePredicate, + SawTyParamBound, + SawPolyTraitRef, + SawAssocTypeBinding, + SawAttribute(ast::AttrStyle, bool), + SawMacroDef, } /// SawExprComponent carries all of the information that we want @@ -117,7 +143,7 @@ enum SawAbiComponent<'a> { /// guarantee of collision-freedom, hash collisions are just /// (hopefully) unlikely.) #[derive(Hash)] -pub enum SawExprComponent<'a> { +enum SawExprComponent<'a> { SawExprLoop(Option), SawExprField(token::InternedString), @@ -185,31 +211,39 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { } } -/// SawStmtComponent is analogous to SawExprComponent, but for statements. -#[derive(Hash)] -pub enum SawStmtComponent { - SawStmtExpr, - SawStmtSemi, +macro_rules! hash_attrs { + ($visitor:expr, $attrs:expr) => ({ + let attrs = $attrs; + if attrs.len() > 0 { + $visitor.hash_attributes(attrs); + } + }) } -impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { +impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn visit_nested_item(&mut self, _: ItemId) { // Each item is hashed independently; ignore nested items. } - fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, - g: &'tcx Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, + s: &'tcx VariantData, + name: Name, + _: &'tcx Generics, + _: NodeId, + span: Span) { debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); - visit::walk_generics(self, g); - visit::walk_struct_def(self, s) + self.hash_span(span); + visit::walk_struct_def(self, s); } - fn visit_variant(&mut self, v: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) { + fn visit_variant(&mut self, + v: &'tcx Variant, + g: &'tcx Generics, + item_id: NodeId) { debug!("visit_variant: st={:?}", self.st); SawVariant.hash(self.st); - // walk_variant does not call walk_generics, so do it here. - visit::walk_generics(self, g); + hash_attrs!(self, &v.node.attrs); visit::walk_variant(self, v, g, item_id) } @@ -227,19 +261,22 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // (If you edit a method such that it deviates from the // pattern, please move that method up above this comment.) - fn visit_name(&mut self, _: Span, name: Name) { + fn visit_name(&mut self, span: Span, name: Name) { debug!("visit_name: st={:?}", self.st); SawIdent(name.as_str()).hash(self.st); + self.hash_span(span); } fn visit_lifetime(&mut self, l: &'tcx Lifetime) { debug!("visit_lifetime: st={:?}", self.st); - SawLifetime(l.name.as_str()).hash(self.st); + SawLifetime.hash(self.st); + visit::walk_lifetime(self, l); } fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { debug!("visit_lifetime_def: st={:?}", self.st); - SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); + SawLifetimeDef(l.bounds.len()).hash(self.st); + visit::walk_lifetime_def(self, l); } // We do recursively walk the bodies of functions/methods @@ -249,7 +286,12 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // crates to be recompiled. fn visit_expr(&mut self, ex: &'tcx Expr) { debug!("visit_expr: st={:?}", self.st); - SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) + SawExpr(saw_expr(&ex.node)).hash(self.st); + // No need to explicitly hash the discriminant here, since we are + // implicitly hashing the discriminant of SawExprComponent. + self.hash_span(ex.span); + hash_attrs!(self, &ex.attrs); + visit::walk_expr(self, ex) } fn visit_stmt(&mut self, s: &'tcx Stmt) { @@ -263,8 +305,16 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // rules). match s.node { StmtDecl(..) => (), - StmtExpr(..) => SawStmt(SawStmtExpr).hash(self.st), - StmtSemi(..) => SawStmt(SawStmtSemi).hash(self.st), + StmtExpr(..) => { + SawStmt.hash(self.st); + self.hash_discriminant(&s.node); + self.hash_span(s.span); + } + StmtSemi(..) => { + SawStmt.hash(self.st); + self.hash_discriminant(&s.node); + self.hash_span(s.span); + } } visit::walk_stmt(self, s) @@ -277,17 +327,21 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // perhaps reachability) somewhere here, so foreign items // that do not leak into downstream crates would not be // part of the ABI. - SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i) + SawForeignItem.hash(self.st); + self.hash_span(i.span); + hash_attrs!(self, &i.attrs); + visit::walk_foreign_item(self, i) } fn visit_item(&mut self, i: &'tcx Item) { debug!("visit_item: {:?} st={:?}", i, self.st); - // FIXME (#14132) ideally would incorporate reachability - // analysis somewhere here, so items that never leak into - // downstream crates (e.g. via monomorphisation or - // inlining) would not be part of the ABI. - SawItem.hash(self.st); visit::walk_item(self, i) + SawItem.hash(self.st); + // Hash the value of the discriminant of the Item variant. + self.hash_discriminant(&i.node); + self.hash_span(i.span); + hash_attrs!(self, &i.attrs); + visit::walk_item(self, i) } fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) { @@ -297,63 +351,159 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx fn visit_ty(&mut self, t: &'tcx Ty) { debug!("visit_ty: st={:?}", self.st); - SawTy.hash(self.st); visit::walk_ty(self, t) + SawTy.hash(self.st); + self.hash_span(t.span); + visit::walk_ty(self, t) } fn visit_generics(&mut self, g: &'tcx Generics) { debug!("visit_generics: st={:?}", self.st); - SawGenerics.hash(self.st); visit::walk_generics(self, g) - } - - fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl, - b: &'tcx Block, s: Span, n: NodeId) { - debug!("visit_fn: st={:?}", self.st); - SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n) + SawGenerics.hash(self.st); + // FIXME: nested stuff + visit::walk_generics(self, g) } fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { debug!("visit_trait_item: st={:?}", self.st); - SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) + SawTraitItem.hash(self.st); + self.hash_discriminant(&ti.node); + self.hash_span(ti.span); + hash_attrs!(self, &ti.attrs); + visit::walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { debug!("visit_impl_item: st={:?}", self.st); - SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) + SawImplItem.hash(self.st); + self.hash_discriminant(&ii.node); + self.hash_span(ii.span); + hash_attrs!(self, &ii.attrs); + visit::walk_impl_item(self, ii) } fn visit_struct_field(&mut self, s: &'tcx StructField) { debug!("visit_struct_field: st={:?}", self.st); - SawStructField.hash(self.st); visit::walk_struct_field(self, s) + SawStructField.hash(self.st); + self.hash_span(s.span); + hash_attrs!(self, &s.attrs); + visit::walk_struct_field(self, s) } fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); - SawPath.hash(self.st); visit::walk_path(self, path) + SawPath(path.global).hash(self.st); + self.hash_span(path.span); + visit::walk_path(self, path) } fn visit_block(&mut self, b: &'tcx Block) { debug!("visit_block: st={:?}", self.st); - SawBlock.hash(self.st); visit::walk_block(self, b) + SawBlock.hash(self.st); + self.hash_span(b.span); + visit::walk_block(self, b) } fn visit_pat(&mut self, p: &'tcx Pat) { debug!("visit_pat: st={:?}", self.st); - SawPat.hash(self.st); visit::walk_pat(self, p) + SawPat.hash(self.st); + self.hash_discriminant(&p.node); + self.hash_span(p.span); + visit::walk_pat(self, p) } fn visit_local(&mut self, l: &'tcx Local) { debug!("visit_local: st={:?}", self.st); - SawLocal.hash(self.st); visit::walk_local(self, l) + SawLocal.hash(self.st); + hash_attrs!(self, &l.attrs); + visit::walk_local(self, l) + // No need to hash span, we are hashing all component spans } fn visit_arm(&mut self, a: &'tcx Arm) { debug!("visit_arm: st={:?}", self.st); - SawArm.hash(self.st); visit::walk_arm(self, a) + SawArm.hash(self.st); + hash_attrs!(self, &a.attrs); + visit::walk_arm(self, a) } fn visit_id(&mut self, id: NodeId) { debug!("visit_id: id={} st={:?}", id, self.st); - self.hash_resolve(id); + self.hash_resolve(id) + } + + fn visit_vis(&mut self, v: &'tcx Visibility) { + debug!("visit_vis: st={:?}", self.st); + SawVis.hash(self.st); + self.hash_discriminant(&v); + visit::walk_vis(self, v) + } + + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { + debug!("visit_where_predicate: st={:?}", self.st); + SawWherePredicate.hash(self.st); + self.hash_discriminant(predicate); + // Ignoring span. Any important nested components should be visited. + visit::walk_where_predicate(self, predicate) + } + + fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) { + debug!("visit_ty_param_bound: st={:?}", self.st); + SawTyParamBound.hash(self.st); + self.hash_discriminant(bounds); + // The TraitBoundModifier in TraitTyParamBound will be hash in + // visit_poly_trait_ref() + visit::walk_ty_param_bound(self, bounds) + } + + fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) { + debug!("visit_poly_trait_ref: st={:?}", self.st); + SawPolyTraitRef.hash(self.st); + m.hash(self.st); + visit::walk_poly_trait_ref(self, t, m) + } + + fn visit_path_list_item(&mut self, prefix: &'tcx Path, item: &'tcx PathListItem) { + debug!("visit_path_list_item: st={:?}", self.st); + SawPathListItem.hash(self.st); + self.hash_discriminant(&item.node); + self.hash_span(item.span); + visit::walk_path_list_item(self, prefix, item) + } + + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { + debug!("visit_path_segment: st={:?}", self.st); + SawPathSegment.hash(self.st); + visit::walk_path_segment(self, path_span, path_segment) + } + + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) { + debug!("visit_path_parameters: st={:?}", self.st); + SawPathParameters.hash(self.st); + self.hash_discriminant(path_parameters); + visit::walk_path_parameters(self, path_span, path_parameters) + } + + fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { + debug!("visit_assoc_type_binding: st={:?}", self.st); + SawAssocTypeBinding.hash(self.st); + self.hash_span(type_binding.span); + visit::walk_assoc_type_binding(self, type_binding) + } + + fn visit_attribute(&mut self, _: &Attribute) { + // We explicitly do not use this method, since doing that would + // implicitly impose an order on the attributes being hashed, while we + // explicitly don't want their order to matter + } + + fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { + debug!("visit_macro_def: st={:?}", self.st); + if macro_def.export { + SawMacroDef.hash(self.st); + hash_attrs!(self, ¯o_def.attrs); + visit::walk_macro_def(self, macro_def) + // FIXME: We should hash the body of the macro too. + } } } @@ -450,4 +600,65 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } } } + + fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) { + // ignoring span information, it doesn't matter here + match meta_item.node { + ast::MetaItemKind::Word(ref s) => { + "Word".hash(self.st); + s.len().hash(self.st); + s.hash(self.st); + } + ast::MetaItemKind::NameValue(ref s, ref lit) => { + "NameValue".hash(self.st); + s.len().hash(self.st); + s.hash(self.st); + lit.node.hash(self.st); + } + ast::MetaItemKind::List(ref s, ref items) => { + "List".hash(self.st); + s.len().hash(self.st); + s.hash(self.st); + // Sort subitems so the hash does not depend on their order + let indices = self.indices_sorted_by(&items, |p| { + meta_item_sort_key(&*p) + }); + items.len().hash(self.st); + for (index, &item_index) in indices.iter().enumerate() { + index.hash(self.st); + self.hash_meta_item(&items[item_index]); + } + } + } + } + + pub fn hash_attributes(&mut self, attributes: &[Attribute]) { + let indices = self.indices_sorted_by(attributes, |attr| { + meta_item_sort_key(&attr.node.value) + }); + + for i in indices { + let attr = &attributes[i].node; + SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); + self.hash_meta_item(&*attr.value); + } + } + + fn indices_sorted_by(&mut self, items: &[T], get_key: F) -> Vec + where K: Ord, + F: Fn(&T) -> K + { + let mut indices = Vec::with_capacity(items.len()); + indices.extend(0 .. items.len()); + indices.sort_by_key(|index| get_key(&items[*index])); + indices + } +} + +fn meta_item_sort_key(item: &ast::MetaItem) -> token::InternedString { + match item.node { + ast::MetaItemKind::Word(ref s) | + ast::MetaItemKind::NameValue(ref s, _) | + ast::MetaItemKind::List(ref s, _) => s.clone() + } } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 511ba8ec19cc7..feacfdc96731f 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -23,6 +23,7 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] +#![feature(core_intrinsics)] extern crate graphviz; extern crate rbml; From e355ec1c6a24f8a597a08809b9dad394498dc3dd Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 24 Aug 2016 17:06:31 -0400 Subject: [PATCH 442/768] incr.comp.: Add stable hashing of HIR spans to ICH. --- .../calculate_svh/svh_visitor.rs | 207 +++++++++++++----- src/libsyntax/codemap.rs | 24 +- src/libsyntax_pos/lib.rs | 64 ++++++ 3 files changed, 226 insertions(+), 69 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index de286d68fe980..554a0e0a97cd3 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,24 +17,99 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; use syntax::ast::{self, Name, NodeId, Attribute}; use syntax::parse::token; -use syntax_pos::Span; +use syntax::codemap::CodeMap; +use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, FileMap}; use rustc::hir; use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; - +use std::rc::Rc; use std::hash::{Hash, SipHasher}; use super::def_path_hash::DefPathHashes; +const IGNORED_ATTRIBUTES: &'static [&'static str] = &["cfg", + "rustc_clean", + "rustc_dirty"]; + pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, pub st: &'a mut SipHasher, // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, + codemap: CachedCodemapView<'tcx>, +} + +struct CachedCodemapView<'tcx> { + codemap: &'tcx CodeMap, + // Format: (line number, line-start, line_end, file) + line_cache: [(usize, BytePos, BytePos, Rc); 4], + eviction_index: usize, +} + +impl<'tcx> CachedCodemapView<'tcx> { + fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachedCodemapView<'tcx> { + let codemap = tcx.sess.codemap(); + let first_file = codemap.files.borrow()[0].clone(); + + CachedCodemapView { + codemap: codemap, + line_cache: [(0, BytePos(0), BytePos(0), first_file.clone()), + (0, BytePos(0), BytePos(0), first_file.clone()), + (0, BytePos(0), BytePos(0), first_file.clone()), + (0, BytePos(0), BytePos(0), first_file.clone())], + eviction_index: 0, + } + } + + fn byte_pos_to_line_and_col(&mut self, + pos: BytePos) + -> (Rc, usize, BytePos) { + // Check if the position is in one of the cached lines + for &(line, start, end, ref file) in self.line_cache.iter() { + if pos >= start && pos < end { + return (file.clone(), line, pos - start); + } + } + + // Check whether we have a cached line in the correct file, so we can + // overwrite it without having to look up the file again. + for &mut (ref mut line, + ref mut start, + ref mut end, + ref file) in self.line_cache.iter_mut() { + if pos >= file.start_pos && pos < file.end_pos { + let line_index = file.lookup_line(pos).unwrap(); + let (line_start, line_end) = file.line_bounds(line_index); + + // Update the cache entry in place + *line = line_index + 1; + *start = line_start; + *end = line_end; + + return (file.clone(), line_index + 1, pos - line_start); + } + } + + // No cache hit ... + let file_index = self.codemap.lookup_filemap_idx(pos); + let file = self.codemap.files.borrow()[file_index].clone(); + let line_index = file.lookup_line(pos).unwrap(); + let (line_start, line_end) = file.line_bounds(line_index); + + // Just overwrite some cache entry. If we got this for, all of them + // point to the wrong file. + self.line_cache[self.eviction_index] = (line_index + 1, + line_start, + line_end, + file.clone()); + self.eviction_index = (self.eviction_index + 1) % self.line_cache.len(); + + return (file, line_index + 1, pos - line_start); + } } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { @@ -48,6 +123,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, + codemap: CachedCodemapView::new(tcx), } } @@ -55,10 +131,46 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { self.def_path_hashes.hash(def_id) } - #[inline] + // Hash a span in a stable way. If we would just hash the spans BytePos + // fields that would be similar hashing pointers since those or just offsets + // into the CodeMap. Instead, we hash the (file name, line, column) triple, + // which stays the same even if the containing FileMap has moved within the + // CodeMap. + // Also note that we are hashing byte offsets for the column, not unicode + // codepoint offsets. For the purpose of the hash that's sufficient. fn hash_span(&mut self, span: Span) { - if self.hash_spans { - let _ = span; + debug_assert!(self.hash_spans); + debug!("hash_span: st={:?}", self.st); + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if span.hi > span.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + span.hi - BytePos(1) + } else { + span.hi + }; + + let (file1, line1, col1) = self.codemap.byte_pos_to_line_and_col(span.lo); + let (file2, line2, col2) = self.codemap.byte_pos_to_line_and_col(span_hi); + + let expansion_kind = match span.expn_id { + NO_EXPANSION => SawSpanExpnKind::NoExpansion, + COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, + _ => SawSpanExpnKind::SomeExpansion, + }; + + expansion_kind.hash(self.st); + + SawSpan(&file1.name[..], line1, col1, + &file2.name[..], line2, col2, + expansion_kind).hash(self.st); + + if expansion_kind == SawSpanExpnKind::SomeExpansion { + self.hash_span(self.codemap.codemap.source_callsite(span)); } } @@ -126,6 +238,7 @@ enum SawAbiComponent<'a> { SawAssocTypeBinding, SawAttribute(ast::AttrStyle, bool), SawMacroDef, + SawSpan(&'a str, usize, BytePos, &'a str, usize, BytePos, SawSpanExpnKind), } /// SawExprComponent carries all of the information that we want @@ -211,6 +324,13 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { } } +#[derive(Clone, Copy, Hash, Eq, PartialEq)] +enum SawSpanExpnKind { + NoExpansion, + CommandLine, + SomeExpansion, +} + macro_rules! hash_attrs { ($visitor:expr, $attrs:expr) => ({ let attrs = $attrs; @@ -220,6 +340,14 @@ macro_rules! hash_attrs { }) } +macro_rules! hash_span { + ($visitor:expr, $span:expr) => ({ + if $visitor.hash_spans { + $visitor.hash_span($span); + } + }) +} + impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn visit_nested_item(&mut self, _: ItemId) { // Each item is hashed independently; ignore nested items. @@ -233,7 +361,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has span: Span) { debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); - self.hash_span(span); + hash_span!(self, span); visit::walk_struct_def(self, s); } @@ -247,24 +375,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_variant(self, v, g, item_id) } - // All of the remaining methods just record (in the hash - // SipHasher) that the visitor saw that particular variant - // (with its payload), and continue walking as the default - // visitor would. - // - // Some of the implementations have some notes as to how one - // might try to make their SVH computation less discerning - // (e.g. by incorporating reachability analysis). But - // currently all of their implementations are uniform and - // uninteresting. - // - // (If you edit a method such that it deviates from the - // pattern, please move that method up above this comment.) - fn visit_name(&mut self, span: Span, name: Name) { debug!("visit_name: st={:?}", self.st); SawIdent(name.as_str()).hash(self.st); - self.hash_span(span); + hash_span!(self, span); } fn visit_lifetime(&mut self, l: &'tcx Lifetime) { @@ -279,17 +393,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_lifetime_def(self, l); } - // We do recursively walk the bodies of functions/methods - // (rather than omitting their bodies from the hash) since - // monomorphization and cross-crate inlining generally implies - // that a change to a crate body will require downstream - // crates to be recompiled. fn visit_expr(&mut self, ex: &'tcx Expr) { debug!("visit_expr: st={:?}", self.st); SawExpr(saw_expr(&ex.node)).hash(self.st); // No need to explicitly hash the discriminant here, since we are // implicitly hashing the discriminant of SawExprComponent. - self.hash_span(ex.span); + hash_span!(self, ex.span); hash_attrs!(self, &ex.attrs); visit::walk_expr(self, ex) } @@ -308,12 +417,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has StmtExpr(..) => { SawStmt.hash(self.st); self.hash_discriminant(&s.node); - self.hash_span(s.span); + hash_span!(self, s.span); } StmtSemi(..) => { SawStmt.hash(self.st); self.hash_discriminant(&s.node); - self.hash_span(s.span); + hash_span!(self, s.span); } } @@ -323,12 +432,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { debug!("visit_foreign_item: st={:?}", self.st); - // FIXME (#14132) ideally we would incorporate privacy (or - // perhaps reachability) somewhere here, so foreign items - // that do not leak into downstream crates would not be - // part of the ABI. SawForeignItem.hash(self.st); - self.hash_span(i.span); + hash_span!(self, i.span); hash_attrs!(self, &i.attrs); visit::walk_foreign_item(self, i) } @@ -339,7 +444,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has SawItem.hash(self.st); // Hash the value of the discriminant of the Item variant. self.hash_discriminant(&i.node); - self.hash_span(i.span); + hash_span!(self, i.span); hash_attrs!(self, &i.attrs); visit::walk_item(self, i) } @@ -352,7 +457,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_ty(&mut self, t: &'tcx Ty) { debug!("visit_ty: st={:?}", self.st); SawTy.hash(self.st); - self.hash_span(t.span); + hash_span!(self, t.span); visit::walk_ty(self, t) } @@ -367,7 +472,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_trait_item: st={:?}", self.st); SawTraitItem.hash(self.st); self.hash_discriminant(&ti.node); - self.hash_span(ti.span); + hash_span!(self, ti.span); hash_attrs!(self, &ti.attrs); visit::walk_trait_item(self, ti) } @@ -376,7 +481,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_impl_item: st={:?}", self.st); SawImplItem.hash(self.st); self.hash_discriminant(&ii.node); - self.hash_span(ii.span); + hash_span!(self, ii.span); hash_attrs!(self, &ii.attrs); visit::walk_impl_item(self, ii) } @@ -384,7 +489,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_struct_field(&mut self, s: &'tcx StructField) { debug!("visit_struct_field: st={:?}", self.st); SawStructField.hash(self.st); - self.hash_span(s.span); + hash_span!(self, s.span); hash_attrs!(self, &s.attrs); visit::walk_struct_field(self, s) } @@ -392,14 +497,14 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); SawPath(path.global).hash(self.st); - self.hash_span(path.span); + hash_span!(self, path.span); visit::walk_path(self, path) } fn visit_block(&mut self, b: &'tcx Block) { debug!("visit_block: st={:?}", self.st); SawBlock.hash(self.st); - self.hash_span(b.span); + hash_span!(self, b.span); visit::walk_block(self, b) } @@ -407,7 +512,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_pat: st={:?}", self.st); SawPat.hash(self.st); self.hash_discriminant(&p.node); - self.hash_span(p.span); + hash_span!(self, p.span); visit::walk_pat(self, p) } @@ -466,7 +571,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_path_list_item: st={:?}", self.st); SawPathListItem.hash(self.st); self.hash_discriminant(&item.node); - self.hash_span(item.span); + hash_span!(self, item.span); visit::walk_path_list_item(self, prefix, item) } @@ -486,7 +591,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { debug!("visit_assoc_type_binding: st={:?}", self.st); SawAssocTypeBinding.hash(self.st); - self.hash_span(type_binding.span); + hash_span!(self, type_binding.span); visit::walk_assoc_type_binding(self, type_binding) } @@ -602,21 +707,21 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) { + debug!("hash_meta_item: st={:?}", self.st); + // ignoring span information, it doesn't matter here + self.hash_discriminant(&meta_item.node); match meta_item.node { ast::MetaItemKind::Word(ref s) => { - "Word".hash(self.st); s.len().hash(self.st); s.hash(self.st); } ast::MetaItemKind::NameValue(ref s, ref lit) => { - "NameValue".hash(self.st); s.len().hash(self.st); s.hash(self.st); lit.node.hash(self.st); } ast::MetaItemKind::List(ref s, ref items) => { - "List".hash(self.st); s.len().hash(self.st); s.hash(self.st); // Sort subitems so the hash does not depend on their order @@ -633,14 +738,18 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } pub fn hash_attributes(&mut self, attributes: &[Attribute]) { + debug!("hash_attributes: st={:?}", self.st); let indices = self.indices_sorted_by(attributes, |attr| { meta_item_sort_key(&attr.node.value) }); for i in indices { let attr = &attributes[i].node; - SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); - self.hash_meta_item(&*attr.value); + + if !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { + SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); + self.hash_meta_item(&*attr.value); + } } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index b176b8fefc612..cd6f2874954b8 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -348,26 +348,10 @@ impl CodeMap { let files = self.files.borrow(); let f = (*files)[idx].clone(); - let len = f.lines.borrow().len(); - if len == 0 { - return Err(f); + match f.lookup_line(pos) { + Some(line) => Ok(FileMapAndLine { fm: f, line: line }), + None => 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; - } - } - assert!(a <= lines.len()); - } - Ok(FileMapAndLine { fm: f, line: a }) } pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { @@ -691,7 +675,7 @@ impl CodeMap { } // Return the index of the filemap (in self.files) which contains pos. - fn lookup_filemap_idx(&self, pos: BytePos) -> usize { + pub fn lookup_filemap_idx(&self, pos: BytePos) -> usize { let files = self.files.borrow(); let files = &*files; let count = files.len(); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index b11bbea84abce..d835f8058fa0e 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -507,6 +507,39 @@ impl FileMap { pub fn count_lines(&self) -> usize { self.lines.borrow().len() } + + /// Find the line containing the given position. The return value is the + /// index into the `lines` array of this FileMap, not the 1-based line + /// number. If the filemap is empty or the position is located before the + /// first line, None is returned. + pub fn lookup_line(&self, pos: BytePos) -> Option { + let lines = self.lines.borrow(); + if lines.len() == 0 { + return None; + } + + let line_index = lookup_line(&lines[..], pos); + assert!(line_index < lines.len() as isize); + if line_index >= 0 { + Some(line_index as usize) + } else { + None + } + } + + pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) { + if self.start_pos == self.end_pos { + return (self.start_pos, self.end_pos); + } + + let lines = self.lines.borrow(); + assert!(line_index < lines.len()); + if line_index == (lines.len() - 1) { + (lines[line_index], self.end_pos) + } else { + (lines[line_index], lines[line_index + 1]) + } + } } // _____________________________________________________________________________ @@ -688,3 +721,34 @@ pub struct MalformedCodemapPositions { pub end_pos: BytePos } +// Given a slice of line start positions and a position, returns the index of +// the line the position is on. Returns -1 if the position is located before +// the first line. +fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize { + match lines.binary_search(&pos) { + Ok(line) => line as isize, + Err(line) => line as isize - 1 + } +} + +#[cfg(test)] +mod tests { + use super::{lookup_line, BytePos}; + + #[test] + fn test_lookup_line() { + + let lines = &[BytePos(3), BytePos(17), BytePos(28)]; + + assert_eq!(lookup_line(lines, BytePos(0)), -1); + assert_eq!(lookup_line(lines, BytePos(3)), 0); + assert_eq!(lookup_line(lines, BytePos(4)), 0); + + assert_eq!(lookup_line(lines, BytePos(16)), 0); + assert_eq!(lookup_line(lines, BytePos(17)), 1); + assert_eq!(lookup_line(lines, BytePos(18)), 1); + + assert_eq!(lookup_line(lines, BytePos(28)), 2); + assert_eq!(lookup_line(lines, BytePos(29)), 2); + } +} From 8b67ad69a7fb943d79d74b588057b5071c406060 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Aug 2016 16:31:02 -0400 Subject: [PATCH 443/768] incr.comp. Add tests for stable span hashing. --- src/test/incremental/source_loc_macros.rs | 63 +++++++++++++++++++ .../span_hash_stable/auxiliary/mod.rs | 17 +++++ .../span_hash_stable/auxiliary/sub1.rs | 15 +++++ .../span_hash_stable/auxiliary/sub2.rs | 15 +++++ src/test/incremental/span_hash_stable/main.rs | 34 ++++++++++ .../spans_insignificant_w_o_debuginfo.rs | 25 ++++++++ .../spans_significant_w_debuginfo.rs | 25 ++++++++ 7 files changed, 194 insertions(+) create mode 100644 src/test/incremental/source_loc_macros.rs create mode 100644 src/test/incremental/span_hash_stable/auxiliary/mod.rs create mode 100644 src/test/incremental/span_hash_stable/auxiliary/sub1.rs create mode 100644 src/test/incremental/span_hash_stable/auxiliary/sub2.rs create mode 100644 src/test/incremental/span_hash_stable/main.rs create mode 100644 src/test/incremental/spans_insignificant_w_o_debuginfo.rs create mode 100644 src/test/incremental/spans_significant_w_debuginfo.rs diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs new file mode 100644 index 0000000000000..f922ac0da41b1 --- /dev/null +++ b/src/test/incremental/source_loc_macros.rs @@ -0,0 +1,63 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that different expansions of the file!(), line!(), +// column!() macros get picked up by the incr. comp. hash. + +// revisions:rpass1 rpass2 + +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] + +#[rustc_clean(label="Hir", cfg="rpass2")] +fn line_same() { + let _ = line!(); +} + +#[rustc_clean(label="Hir", cfg="rpass2")] +fn col_same() { + let _ = column!(); +} + +#[rustc_clean(label="Hir", cfg="rpass2")] +fn file_same() { + let _ = file!(); +} + +#[cfg(rpass1)] +fn line_different() { + let _ = line!(); +} + +#[cfg(rpass2)] +#[rustc_dirty(label="Hir", cfg="rpass2")] +fn line_different() { + let _ = line!(); +} + +#[cfg(rpass1)] +fn col_different() { + let _ = column!(); +} + +#[cfg(rpass2)] +#[rustc_dirty(label="Hir", cfg="rpass2")] +fn col_different() { + let _ = column!(); +} + +fn main() { + line_same(); + line_different(); + col_same(); + col_different(); + file_same(); +} diff --git a/src/test/incremental/span_hash_stable/auxiliary/mod.rs b/src/test/incremental/span_hash_stable/auxiliary/mod.rs new file mode 100644 index 0000000000000..dfd2a6610f259 --- /dev/null +++ b/src/test/incremental/span_hash_stable/auxiliary/mod.rs @@ -0,0 +1,17 @@ +// 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. + +#[cfg(rpass1)] +pub mod sub2; + +pub mod sub1; + +#[cfg(rpass2)] +pub mod sub2; diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs new file mode 100644 index 0000000000000..2d042c316833e --- /dev/null +++ b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs @@ -0,0 +1,15 @@ +// 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. + +#[rustc_clean(label="Hir", cfg="rpass2")] +pub struct SomeType { + pub x: u32, + pub y: i64, +} diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs new file mode 100644 index 0000000000000..df7d2f0267d02 --- /dev/null +++ b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs @@ -0,0 +1,15 @@ +// 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. + +#[rustc_clean(label="Hir", cfg="rpass2")] +pub struct SomeOtherType { + pub a: i32, + pub b: u64, +} diff --git a/src/test/incremental/span_hash_stable/main.rs b/src/test/incremental/span_hash_stable/main.rs new file mode 100644 index 0000000000000..1512c5dc53788 --- /dev/null +++ b/src/test/incremental/span_hash_stable/main.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that it doesn't make a difference in which order we are +// adding source files to the codemap. The order affects the BytePos values of +// the spans and this test makes sure that we handle them correctly by hashing +// file:line:column instead of raw byte offset. + +// revisions:rpass1 rpass2 +// compile-flags: -g -Z query-dep-graph + +#![feature(rustc_attrs)] + +mod auxiliary; + +fn main() { + let _ = auxiliary::sub1::SomeType { + x: 0, + y: 1, + }; + + let _ = auxiliary::sub2::SomeOtherType { + a: 2, + b: 3, + }; +} + diff --git a/src/test/incremental/spans_insignificant_w_o_debuginfo.rs b/src/test/incremental/spans_insignificant_w_o_debuginfo.rs new file mode 100644 index 0000000000000..9c8b8552498c4 --- /dev/null +++ b/src/test/incremental/spans_insignificant_w_o_debuginfo.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that just changing a definition's location in the +// source file does *not* change its incr. comp. hash, if debuginfo is disabled. + +// revisions:rpass1 rpass2 + +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] + +#[cfg(rpass1)] +pub fn main() {} + +#[cfg(rpass2)] +#[rustc_clean(label="Hir", cfg="rpass2")] +pub fn main() {} diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs new file mode 100644 index 0000000000000..b0920aa1fa510 --- /dev/null +++ b/src/test/incremental/spans_significant_w_debuginfo.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that just changing a definition's location in the +// source file also changes its incr. comp. hash, if debuginfo is enabled. + +// revisions:rpass1 rpass2 + +// compile-flags: -g -Z query-dep-graph + +#![feature(rustc_attrs)] + +#[cfg(rpass1)] +pub fn main() {} + +#[cfg(rpass2)] +#[rustc_dirty(label="Hir", cfg="rpass2")] +pub fn main() {} From 1cfd7c36542bfbd68a9808a6fc295e1ffe98a749 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Aug 2016 18:29:13 -0400 Subject: [PATCH 444/768] incr.comp.: Ignore doc-comments when computing the ICH. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 554a0e0a97cd3..7bc4d0ac46337 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -236,7 +236,7 @@ enum SawAbiComponent<'a> { SawTyParamBound, SawPolyTraitRef, SawAssocTypeBinding, - SawAttribute(ast::AttrStyle, bool), + SawAttribute(ast::AttrStyle), SawMacroDef, SawSpan(&'a str, usize, BytePos, &'a str, usize, BytePos, SawSpanExpnKind), } @@ -746,8 +746,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { for i in indices { let attr = &attributes[i].node; - if !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { - SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); + if !attr.is_sugared_doc && + !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { + SawAttribute(attr.style).hash(self.st); self.hash_meta_item(&*attr.value); } } From 5dd36bd48630e925ec617e40db8d23b593814cef Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 15:28:53 -0400 Subject: [PATCH 445/768] Rename CacheCodemapView to CachingCodemapView. --- .../calculate_svh/svh_visitor.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 7bc4d0ac46337..84f4ac4b74570 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -40,22 +40,22 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, - codemap: CachedCodemapView<'tcx>, + codemap: CachingCodemapView<'tcx>, } -struct CachedCodemapView<'tcx> { +struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, // Format: (line number, line-start, line_end, file) line_cache: [(usize, BytePos, BytePos, Rc); 4], eviction_index: usize, } -impl<'tcx> CachedCodemapView<'tcx> { - fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachedCodemapView<'tcx> { +impl<'tcx> CachingCodemapView<'tcx> { + fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { let codemap = tcx.sess.codemap(); let first_file = codemap.files.borrow()[0].clone(); - CachedCodemapView { + CachingCodemapView { codemap: codemap, line_cache: [(0, BytePos(0), BytePos(0), first_file.clone()), (0, BytePos(0), BytePos(0), first_file.clone()), @@ -123,7 +123,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, - codemap: CachedCodemapView::new(tcx), + codemap: CachingCodemapView::new(tcx), } } From 6785256557d6a4c21d53806637042871babc7302 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 15:29:50 -0400 Subject: [PATCH 446/768] ICH: Don't hash span expansion kind twice. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 84f4ac4b74570..db062d6dca96d 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -163,8 +163,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { _ => SawSpanExpnKind::SomeExpansion, }; - expansion_kind.hash(self.st); - SawSpan(&file1.name[..], line1, col1, &file2.name[..], line2, col2, expansion_kind).hash(self.st); From 500ab357c263eaa8ae55ed1323daa946def5b7b6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 15:47:44 -0400 Subject: [PATCH 447/768] ICH: Cleanup some comments. --- .../calculate_svh/svh_visitor.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index db062d6dca96d..702eed9d96fc5 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -45,7 +45,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, - // Format: (line number, line-start, line_end, file) + // Format: (line number, line-start, line-end, file) line_cache: [(usize, BytePos, BytePos, Rc); 4], eviction_index: usize, } @@ -100,7 +100,7 @@ impl<'tcx> CachingCodemapView<'tcx> { let line_index = file.lookup_line(pos).unwrap(); let (line_start, line_end) = file.line_bounds(line_index); - // Just overwrite some cache entry. If we got this for, all of them + // Just overwrite some cache entry. If we got this far, all of them // point to the wrong file. self.line_cache[self.eviction_index] = (line_index + 1, line_start, @@ -131,11 +131,11 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { self.def_path_hashes.hash(def_id) } - // Hash a span in a stable way. If we would just hash the spans BytePos - // fields that would be similar hashing pointers since those or just offsets - // into the CodeMap. Instead, we hash the (file name, line, column) triple, - // which stays the same even if the containing FileMap has moved within the - // CodeMap. + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // within the CodeMap. // Also note that we are hashing byte offsets for the column, not unicode // codepoint offsets. For the purpose of the hash that's sufficient. fn hash_span(&mut self, span: Span) { @@ -462,7 +462,6 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_generics(&mut self, g: &'tcx Generics) { debug!("visit_generics: st={:?}", self.st); SawGenerics.hash(self.st); - // FIXME: nested stuff visit::walk_generics(self, g) } @@ -605,7 +604,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has SawMacroDef.hash(self.st); hash_attrs!(self, ¯o_def.attrs); visit::walk_macro_def(self, macro_def) - // FIXME: We should hash the body of the macro too. + // FIXME(mw): We should hash the body of the macro too but we don't + // have a stable way of doing so yet. } } } From 0310e3444b6b24da1b542b7c6b2999a1220259c0 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 16:45:34 -0400 Subject: [PATCH 448/768] ICH: Take CaptureClause of closure expressions into account. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 702eed9d96fc5..23fb211d7c7e4 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -275,7 +275,7 @@ enum SawExprComponent<'a> { SawExprIf, SawExprWhile, SawExprMatch, - SawExprClosure, + SawExprClosure(CaptureClause), SawExprBlock, SawExprAssign, SawExprAssignOp(hir::BinOp_), @@ -304,7 +304,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { ExprWhile(..) => SawExprWhile, ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())), ExprMatch(..) => SawExprMatch, - ExprClosure(..) => SawExprClosure, + ExprClosure(cc, _, _, _) => SawExprClosure(cc), ExprBlock(..) => SawExprBlock, ExprAssign(..) => SawExprAssign, ExprAssignOp(op, _, _) => SawExprAssignOp(op.node), From a142d2ff025466a69662854255c959f60a31fd8c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 30 Aug 2016 12:11:43 -0400 Subject: [PATCH 449/768] ICH: Fix bug in hash_discriminant() and visit_vis(). --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 23fb211d7c7e4..edfde33b3a15a 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -174,7 +174,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn hash_discriminant(&mut self, v: &T) { unsafe { - ::std::intrinsics::discriminant_value(&v).hash(self.st); + let disr = ::std::intrinsics::discriminant_value(v); + debug!("hash_discriminant: disr={}, st={:?}", disr, self.st); + disr.hash(self.st); } } } @@ -536,7 +538,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_vis(&mut self, v: &'tcx Visibility) { debug!("visit_vis: st={:?}", self.st); SawVis.hash(self.st); - self.hash_discriminant(&v); + self.hash_discriminant(v); visit::walk_vis(self, v) } From 2faca22bd31b0deeb38f35dc8d0916fb6ace95c2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 31 Aug 2016 16:29:04 -0400 Subject: [PATCH 450/768] ICH: Fix codemap lookup caching. --- .../calculate_svh/svh_visitor.rs | 94 ++++++++++--------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index edfde33b3a15a..e871dd5bcbffe 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -43,72 +43,82 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { codemap: CachingCodemapView<'tcx>, } +#[derive(Clone)] +struct CacheEntry { + time_stamp: usize, + line_number: usize, + line_start: BytePos, + line_end: BytePos, + file: Rc, +} + struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, - // Format: (line number, line-start, line-end, file) - line_cache: [(usize, BytePos, BytePos, Rc); 4], - eviction_index: usize, + line_cache: [CacheEntry; 3], + time_stamp: usize, } impl<'tcx> CachingCodemapView<'tcx> { fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { let codemap = tcx.sess.codemap(); let first_file = codemap.files.borrow()[0].clone(); + let entry = CacheEntry { + time_stamp: 0, + line_number: 0, + line_start: BytePos(0), + line_end: BytePos(0), + file: first_file, + }; CachingCodemapView { codemap: codemap, - line_cache: [(0, BytePos(0), BytePos(0), first_file.clone()), - (0, BytePos(0), BytePos(0), first_file.clone()), - (0, BytePos(0), BytePos(0), first_file.clone()), - (0, BytePos(0), BytePos(0), first_file.clone())], - eviction_index: 0, + line_cache: [entry.clone(), entry.clone(), entry.clone()], + time_stamp: 0, } } fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> (Rc, usize, BytePos) { + self.time_stamp += 1; + // Check if the position is in one of the cached lines - for &(line, start, end, ref file) in self.line_cache.iter() { - if pos >= start && pos < end { - return (file.clone(), line, pos - start); + for cache_entry in self.line_cache.iter_mut() { + if pos >= cache_entry.line_start && pos < cache_entry.line_end { + cache_entry.time_stamp = self.time_stamp; + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); } } - // Check whether we have a cached line in the correct file, so we can - // overwrite it without having to look up the file again. - for &mut (ref mut line, - ref mut start, - ref mut end, - ref file) in self.line_cache.iter_mut() { - if pos >= file.start_pos && pos < file.end_pos { - let line_index = file.lookup_line(pos).unwrap(); - let (line_start, line_end) = file.line_bounds(line_index); - - // Update the cache entry in place - *line = line_index + 1; - *start = line_start; - *end = line_end; - - return (file.clone(), line_index + 1, pos - line_start); + // No cache hit ... + let mut oldest = 0; + for index in 1 .. self.line_cache.len() { + if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { + oldest = index; } } - // No cache hit ... - let file_index = self.codemap.lookup_filemap_idx(pos); - let file = self.codemap.files.borrow()[file_index].clone(); - let line_index = file.lookup_line(pos).unwrap(); - let (line_start, line_end) = file.line_bounds(line_index); - - // Just overwrite some cache entry. If we got this far, all of them - // point to the wrong file. - self.line_cache[self.eviction_index] = (line_index + 1, - line_start, - line_end, - file.clone()); - self.eviction_index = (self.eviction_index + 1) % self.line_cache.len(); - - return (file, line_index + 1, pos - line_start); + let cache_entry = &mut self.line_cache[oldest]; + + // If the entry doesn't point to the correct file, fix it up + if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { + let file_index = self.codemap.lookup_filemap_idx(pos); + cache_entry.file = self.codemap.files.borrow()[file_index].clone(); + } + + let line_index = cache_entry.file.lookup_line(pos).unwrap(); + let line_bounds = cache_entry.file.line_bounds(line_index); + + cache_entry.line_number = line_index + 1; + cache_entry.line_start = line_bounds.0; + cache_entry.line_end = line_bounds.1; + cache_entry.time_stamp = self.time_stamp; + + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); } } From 8cbd6fe33155fde25146d2cf03aa26e450086106 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 31 Aug 2016 16:51:24 -0400 Subject: [PATCH 451/768] ICH: Share codemap cache between subsequent runs of the ICH visitor. --- .../calculate_svh/caching_codemap_view.rs | 97 +++++++++++++++++++ src/librustc_incremental/calculate_svh/mod.rs | 8 +- .../calculate_svh/svh_visitor.rs | 92 ++---------------- 3 files changed, 111 insertions(+), 86 deletions(-) create mode 100644 src/librustc_incremental/calculate_svh/caching_codemap_view.rs diff --git a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs new file mode 100644 index 0000000000000..32aa5a4272871 --- /dev/null +++ b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs @@ -0,0 +1,97 @@ +// 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. + +use rustc::ty::TyCtxt; +use std::rc::Rc; +use syntax::codemap::CodeMap; +use syntax_pos::{BytePos, FileMap}; + +#[derive(Clone)] +struct CacheEntry { + time_stamp: usize, + line_number: usize, + line_start: BytePos, + line_end: BytePos, + file: Rc, +} + +pub struct CachingCodemapView<'tcx> { + codemap: &'tcx CodeMap, + line_cache: [CacheEntry; 3], + time_stamp: usize, +} + +impl<'tcx> CachingCodemapView<'tcx> { + pub fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { + let codemap = tcx.sess.codemap(); + let first_file = codemap.files.borrow()[0].clone(); + let entry = CacheEntry { + time_stamp: 0, + line_number: 0, + line_start: BytePos(0), + line_end: BytePos(0), + file: first_file, + }; + + CachingCodemapView { + codemap: codemap, + line_cache: [entry.clone(), entry.clone(), entry.clone()], + time_stamp: 0, + } + } + + pub fn codemap(&self) -> &'tcx CodeMap { + self.codemap + } + + pub fn byte_pos_to_line_and_col(&mut self, + pos: BytePos) + -> (Rc, usize, BytePos) { + self.time_stamp += 1; + + // Check if the position is in one of the cached lines + for cache_entry in self.line_cache.iter_mut() { + if pos >= cache_entry.line_start && pos < cache_entry.line_end { + cache_entry.time_stamp = self.time_stamp; + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); + } + } + + // No cache hit ... + let mut oldest = 0; + for index in 1 .. self.line_cache.len() { + if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { + oldest = index; + } + } + + let cache_entry = &mut self.line_cache[oldest]; + + // If the entry doesn't point to the correct file, fix it up + if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { + let file_index = self.codemap.lookup_filemap_idx(pos); + cache_entry.file = self.codemap.files.borrow()[file_index].clone(); + } + + let line_index = cache_entry.file.lookup_line(pos).unwrap(); + let line_bounds = cache_entry.file.line_bounds(line_index); + + cache_entry.line_number = line_index + 1; + cache_entry.line_start = line_bounds.0; + cache_entry.line_end = line_bounds.1; + cache_entry.time_stamp = self.time_stamp; + + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 6ad93d8f4733c..c54fe2114517e 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -40,9 +40,11 @@ use rustc::session::config::DebugInfoLevel::NoDebugInfo; use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; +use self::caching_codemap_view::CachingCodemapView; mod def_path_hash; mod svh_visitor; +mod caching_codemap_view; pub type IncrementalHashesMap = FnvHashMap, u64>; @@ -55,7 +57,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) tcx: tcx, hashes: FnvHashMap(), def_path_hashes: DefPathHashes::new(tcx), - hash_spans: hash_spans + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans, }; record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), @@ -69,6 +72,7 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path_hashes: DefPathHashes<'a, 'tcx>, + codemap: CachingCodemapView<'tcx>, hashes: IncrementalHashesMap, hash_spans: bool, } @@ -92,6 +96,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx, &mut self.def_path_hashes, + &mut self.codemap, self.hash_spans)); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); @@ -132,6 +137,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, self.tcx, &mut self.def_path_hashes, + &mut self.codemap, self.hash_spans); visitor.hash_attributes(&krate.attrs); } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index e871dd5bcbffe..417f09c1c9d55 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,18 +17,17 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; use syntax::ast::{self, Name, NodeId, Attribute}; use syntax::parse::token; -use syntax::codemap::CodeMap; -use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, FileMap}; +use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use rustc::hir; use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; -use std::rc::Rc; use std::hash::{Hash, SipHasher}; use super::def_path_hash::DefPathHashes; +use super::caching_codemap_view::CachingCodemapView; const IGNORED_ATTRIBUTES: &'static [&'static str] = &["cfg", "rustc_clean", @@ -40,92 +39,14 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, - codemap: CachingCodemapView<'tcx>, -} - -#[derive(Clone)] -struct CacheEntry { - time_stamp: usize, - line_number: usize, - line_start: BytePos, - line_end: BytePos, - file: Rc, -} - -struct CachingCodemapView<'tcx> { - codemap: &'tcx CodeMap, - line_cache: [CacheEntry; 3], - time_stamp: usize, -} - -impl<'tcx> CachingCodemapView<'tcx> { - fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { - let codemap = tcx.sess.codemap(); - let first_file = codemap.files.borrow()[0].clone(); - let entry = CacheEntry { - time_stamp: 0, - line_number: 0, - line_start: BytePos(0), - line_end: BytePos(0), - file: first_file, - }; - - CachingCodemapView { - codemap: codemap, - line_cache: [entry.clone(), entry.clone(), entry.clone()], - time_stamp: 0, - } - } - - fn byte_pos_to_line_and_col(&mut self, - pos: BytePos) - -> (Rc, usize, BytePos) { - self.time_stamp += 1; - - // Check if the position is in one of the cached lines - for cache_entry in self.line_cache.iter_mut() { - if pos >= cache_entry.line_start && pos < cache_entry.line_end { - cache_entry.time_stamp = self.time_stamp; - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); - } - } - - // No cache hit ... - let mut oldest = 0; - for index in 1 .. self.line_cache.len() { - if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { - oldest = index; - } - } - - let cache_entry = &mut self.line_cache[oldest]; - - // If the entry doesn't point to the correct file, fix it up - if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { - let file_index = self.codemap.lookup_filemap_idx(pos); - cache_entry.file = self.codemap.files.borrow()[file_index].clone(); - } - - let line_index = cache_entry.file.lookup_line(pos).unwrap(); - let line_bounds = cache_entry.file.line_bounds(line_index); - - cache_entry.line_number = line_index + 1; - cache_entry.line_start = line_bounds.0; - cache_entry.line_end = line_bounds.1; - cache_entry.time_stamp = self.time_stamp; - - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); - } + codemap: &'a mut CachingCodemapView<'tcx>, } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { pub fn new(st: &'a mut SipHasher, tcx: TyCtxt<'hash, 'tcx, 'tcx>, def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, + codemap: &'a mut CachingCodemapView<'tcx>, hash_spans: bool) -> Self { StrictVersionHashVisitor { @@ -133,7 +54,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, - codemap: CachingCodemapView::new(tcx), + codemap: codemap, } } @@ -178,7 +99,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { expansion_kind).hash(self.st); if expansion_kind == SawSpanExpnKind::SomeExpansion { - self.hash_span(self.codemap.codemap.source_callsite(span)); + let call_site = self.codemap.codemap().source_callsite(span); + self.hash_span(call_site); } } From 0f8eb81011dcc2f235e74a4f0b7c2d80c1b0b4ab Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 29 Aug 2016 20:05:47 +0200 Subject: [PATCH 452/768] Document try!'s error conversion behaviour --- src/libcore/macros.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c916ad930ff10..f29a49dd5fe1a 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -189,10 +189,19 @@ macro_rules! debug_assert_eq { ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); }) } -/// Helper macro for unwrapping `Result` values while returning early with an -/// error if the value of the expression is `Err`. Can only be used in -/// functions that return `Result` because of the early return of `Err` that -/// it provides. +/// Helper macro for reducing boilerplate code for matching `Result` together +/// with converting downstream errors. +/// +/// `try!` matches the given `Result`. In case of the `Ok` variant, the +/// expression has the value of the wrapped value. +/// +/// In case of the `Err` variant, it retrieves the inner error. `try!` then +/// performs conversion using `From`. This provides automatic conversion +/// between specialized errors and more general ones. The resulting +/// error is then immediately returned. +/// +/// Because of the early return, `try!` can only be used in functions that +/// return `Result`. /// /// # Examples /// @@ -201,18 +210,28 @@ macro_rules! debug_assert_eq { /// use std::fs::File; /// use std::io::prelude::*; /// -/// fn write_to_file_using_try() -> Result<(), io::Error> { +/// enum MyError { +/// FileWriteError +/// } +/// +/// impl From for MyError { +/// fn from(e: io::Error) -> MyError { +/// MyError::FileWriteError +/// } +/// } +/// +/// fn write_to_file_using_try() -> Result<(), MyError> { /// let mut file = try!(File::create("my_best_friends.txt")); /// try!(file.write_all(b"This is a list of my best friends.")); /// println!("I wrote to the file"); /// Ok(()) /// } /// // This is equivalent to: -/// fn write_to_file_using_match() -> Result<(), io::Error> { +/// fn write_to_file_using_match() -> Result<(), MyError> { /// let mut file = try!(File::create("my_best_friends.txt")); /// match file.write_all(b"This is a list of my best friends.") { /// Ok(v) => v, -/// Err(e) => return Err(e), +/// Err(e) => return Err(From::from(e)), /// } /// println!("I wrote to the file"); /// Ok(()) From 7310a8ffea95400c2c61d4fb27c224eb0e64e244 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Sep 2016 14:39:31 -0400 Subject: [PATCH 453/768] ICH: Adapt to changes in the MetaItem AST representation. --- src/librustc_data_structures/fnv.rs | 6 ++++ .../calculate_svh/svh_visitor.rs | 35 +++++++++---------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index 0000c283a7a00..47f623266f3b7 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -57,3 +57,9 @@ impl Hasher for FnvHasher { self.0 } } + +pub fn hash(v: &T) -> u64 { + let mut state = FnvHasher::default(); + v.hash(&mut state); + state.finish() +} diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 417f09c1c9d55..05a2f751d2921 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -15,7 +15,7 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; -use syntax::ast::{self, Name, NodeId, Attribute}; +use syntax::ast::{self, Name, NodeId}; use syntax::parse::token; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use rustc::hir; @@ -24,6 +24,7 @@ use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; +use rustc_data_structures::fnv; use std::hash::{Hash, SipHasher}; use super::def_path_hash::DefPathHashes; @@ -526,7 +527,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _: &Attribute) { + fn visit_attribute(&mut self, _: &ast::Attribute) { // We explicitly do not use this method, since doing that would // implicitly impose an order on the attributes being hashed, while we // explicitly don't want their order to matter @@ -658,28 +659,34 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { s.hash(self.st); // Sort subitems so the hash does not depend on their order let indices = self.indices_sorted_by(&items, |p| { - meta_item_sort_key(&*p) + (p.name(), fnv::hash(&p.literal().map(|i| &i.node))) }); items.len().hash(self.st); for (index, &item_index) in indices.iter().enumerate() { index.hash(self.st); - self.hash_meta_item(&items[item_index]); + let nested_meta_item: &ast::NestedMetaItemKind = &items[item_index].node; + self.hash_discriminant(nested_meta_item); + match *nested_meta_item { + ast::NestedMetaItemKind::MetaItem(ref meta_item) => { + self.hash_meta_item(meta_item); + } + ast::NestedMetaItemKind::Literal(ref lit) => { + lit.node.hash(self.st); + } + } } } } } - pub fn hash_attributes(&mut self, attributes: &[Attribute]) { + pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { debug!("hash_attributes: st={:?}", self.st); - let indices = self.indices_sorted_by(attributes, |attr| { - meta_item_sort_key(&attr.node.value) - }); + let indices = self.indices_sorted_by(attributes, |attr| attr.name()); for i in indices { let attr = &attributes[i].node; - if !attr.is_sugared_doc && - !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { + !IGNORED_ATTRIBUTES.contains(&&*attr.value.name()) { SawAttribute(attr.style).hash(self.st); self.hash_meta_item(&*attr.value); } @@ -696,11 +703,3 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { indices } } - -fn meta_item_sort_key(item: &ast::MetaItem) -> token::InternedString { - match item.node { - ast::MetaItemKind::Word(ref s) | - ast::MetaItemKind::NameValue(ref s, _) | - ast::MetaItemKind::List(ref s, _) => s.clone() - } -} From 66ae481055d5379656c420a30534887a31f81404 Mon Sep 17 00:00:00 2001 From: c4rlo Date: Thu, 1 Sep 2016 22:42:51 +0100 Subject: [PATCH 454/768] README.md: fix a "\" in table heading to be "/" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dbe48a50cfa70..f2385f315186f 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ fetch snapshots, and an OS that can execute the available snapshot binaries. Snapshot binaries are currently built and tested on several platforms: -| Platform \ Architecture | x86 | x86_64 | +| Platform / Architecture | x86 | x86_64 | |--------------------------------|-----|--------| | Windows (7, 8, Server 2008 R2) | ✓ | ✓ | | Linux (2.6.18 or later) | ✓ | ✓ | From 48a435a90fb227f0da20b610438618dfc2c49a4e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 19:20:08 +0000 Subject: [PATCH 455/768] Fix test `compile-fail/task-rng-isnt-sendable.rs`. --- src/test/compile-fail/task-rng-isnt-sendable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index 9c0a2267d7cf8..c987d9f2f4e1b 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -10,10 +10,10 @@ // ensure that the ThreadRng isn't/doesn't become accidentally sendable. -use std::rand; //~ ERROR: module `rand` is private +use std::__rand::ThreadRng; fn test_send() {} pub fn main() { - test_send::(); + test_send::(); //~ ERROR std::marker::Send` is not satisfied } From 5dc1196191c2f1edba8baaf841fdc07f9f8eea0b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 19 Aug 2016 21:46:28 +0000 Subject: [PATCH 456/768] Refactor away `binding.is_pseudo_public()`. --- src/librustc_resolve/lib.rs | 4 ---- src/librustc_resolve/resolve_imports.rs | 11 +++++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 54efc4ae30a60..e27936b912960 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -885,10 +885,6 @@ impl<'a> NameBinding<'a> { } } - fn is_pseudo_public(&self) -> bool { - self.pseudo_vis() == ty::Visibility::Public - } - // We sometimes need to treat variants as `pub` for backwards compatibility fn pseudo_vis(&self) -> ty::Visibility { if self.is_variant() { ty::Visibility::Public } else { self.vis } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8c6d89c29bde1..eedbccbb039ba 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -168,7 +168,7 @@ impl<'a> Resolver<'a> { }; let is_disallowed_private_import = |binding: &NameBinding| { - !allow_private_imports && !binding.is_pseudo_public() && binding.is_import() + !allow_private_imports && binding.vis != ty::Visibility::Public && binding.is_import() }; if let Some(span) = record_used { @@ -338,7 +338,7 @@ impl<'a> Resolver<'a> { }; // Define `new_binding` in `module`s glob importers. - if new_binding.is_importable() && new_binding.is_pseudo_public() { + if new_binding.vis == ty::Visibility::Public { for directive in module.glob_importers.borrow_mut().iter() { let imported_binding = self.import(new_binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); @@ -656,9 +656,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let Some(Def::Trait(_)) = module.def { self.session.span_err(directive.span, "items in traits are not importable."); - } - - if module.def_id() == directive.parent.def_id() { + return; + } else if module.def_id() == directive.parent.def_id() { return; } else if let GlobImport { is_prelude: true } = directive.subclass { self.prelude = Some(module); @@ -674,7 +673,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { resolution.borrow().binding().map(|binding| (*name, binding)) }).collect::>(); for ((name, ns), binding) in bindings { - if binding.is_importable() && binding.is_pseudo_public() { + if binding.pseudo_vis() == ty::Visibility::Public { let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } From 691d10c3c947761ea00df87bd1b1fd532da248e0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 07:22:32 +0000 Subject: [PATCH 457/768] Rename `new_binding` -> `binding`. --- src/librustc_resolve/resolve_imports.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index eedbccbb039ba..81f99e2240b6f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -324,7 +324,7 @@ impl<'a> Resolver<'a> { { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. - let (new_binding, t) = { + let (binding, t) = { let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut(); let was_known = resolution.binding().is_some(); @@ -337,10 +337,10 @@ impl<'a> Resolver<'a> { } }; - // Define `new_binding` in `module`s glob importers. - if new_binding.vis == ty::Visibility::Public { + // Define `binding` in `module`s glob importers. + if binding.vis == ty::Visibility::Public { for directive in module.glob_importers.borrow_mut().iter() { - let imported_binding = self.import(new_binding, directive); + let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } } From 87ae68c1d6e55a62e1faf4ceccb5e884aa6a95d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 07:26:26 +0000 Subject: [PATCH 458/768] Refactor `binding.def()` to return a `Def` instead of an `Option`. --- src/librustc_resolve/lib.rs | 34 ++++++++++++------------- src/librustc_resolve/resolve_imports.rs | 8 +++--- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e27936b912960..8a7a22988cb5f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -459,7 +459,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => { - let shadows_what = PathResolution::new(binding.def().unwrap()).kind_name(); + let shadows_what = PathResolution::new(binding.def()).kind_name(); let mut err = struct_span_err!(resolver.session, span, E0530, @@ -739,7 +739,7 @@ impl<'a> LexicalScopeBinding<'a> { fn local_def(self) -> LocalDef { match self { LexicalScopeBinding::LocalDef(local_def) => local_def, - LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def().unwrap()), + LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def()), } } @@ -877,10 +877,10 @@ impl<'a> NameBinding<'a> { } } - fn def(&self) -> Option { + fn def(&self) -> Def { match self.kind { - NameBindingKind::Def(def) => Some(def), - NameBindingKind::Module(module) => module.def, + NameBindingKind::Def(def) => def, + NameBindingKind::Module(module) => module.def.unwrap(), NameBindingKind::Import { binding, .. } => binding.def(), } } @@ -916,7 +916,7 @@ impl<'a> NameBinding<'a> { } fn is_importable(&self) -> bool { - match self.def().unwrap() { + match self.def() { Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false, _ => true, } @@ -1097,7 +1097,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def { let namespace = if is_value { ValueNS } else { TypeNS }; match self.resolve_crate_relative_path(path.span, &path.segments, namespace) { - Ok(binding) => binding.def().unwrap(), + Ok(binding) => binding.def(), Err(true) => Def::Err, Err(false) => { let path_name = &format!("{}", path); @@ -1693,7 +1693,7 @@ impl<'a> Resolver<'a> { &prefix.segments, TypeNS) { Ok(binding) => { - let def = binding.def().unwrap(); + let def = binding.def(); self.record_def(item.id, PathResolution::new(def)); } Err(true) => self.record_def(item.id, err_path_resolution()), @@ -2309,7 +2309,7 @@ impl<'a> Resolver<'a> { // entity, then fall back to a fresh binding. let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None) .and_then(LexicalScopeBinding::item); - let resolution = binding.and_then(NameBinding::def).and_then(|def| { + let resolution = binding.map(NameBinding::def).and_then(|def| { let always_binding = !pat_src.is_refutable() || opt_pat.is_some() || bmode != BindingMode::ByValue(Mutability::Immutable); match def { @@ -2443,7 +2443,7 @@ impl<'a> Resolver<'a> { if path.global { let binding = self.resolve_crate_relative_path(span, segments, namespace); - return binding.map(|binding| mk_res(binding.def().unwrap())); + return binding.map(|binding| mk_res(binding.def())); } // Try to find a path to an item in a module. @@ -2481,7 +2481,7 @@ impl<'a> Resolver<'a> { let unqualified_def = resolve_identifier_with_fallback(self, None); let qualified_binding = self.resolve_module_relative_path(span, segments, namespace); match (qualified_binding, unqualified_def) { - (Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => { + (Ok(binding), Some(ref ud)) if binding.def() == ud.def => { self.session .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, id, @@ -2491,7 +2491,7 @@ impl<'a> Resolver<'a> { _ => {} } - qualified_binding.map(|binding| mk_res(binding.def().unwrap())) + qualified_binding.map(|binding| mk_res(binding.def())) } // Resolve a single identifier @@ -3114,7 +3114,7 @@ impl<'a> Resolver<'a> { let mut collected_traits = Vec::new(); module.for_each_child(|name, ns, binding| { if ns != TypeNS { return } - if let Some(Def::Trait(_)) = binding.def() { + if let Def::Trait(_) = binding.def() { collected_traits.push((name, binding)); } }); @@ -3122,7 +3122,7 @@ impl<'a> Resolver<'a> { } for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - let trait_def_id = binding.def().unwrap().def_id(); + let trait_def_id = binding.def().def_id(); if this.trait_item_map.contains_key(&(name, trait_def_id)) { let mut import_id = None; if let NameBindingKind::Import { directive, .. } = binding.kind { @@ -3181,8 +3181,8 @@ impl<'a> Resolver<'a> { if name_binding.is_import() { return; } // collect results based on the filter function - if let Some(def) = name_binding.def() { - if name == lookup_name && ns == namespace && filter_fn(def) { + if name == lookup_name && ns == namespace { + if filter_fn(name_binding.def()) { // create the path let ident = ast::Ident::with_empty_ctxt(name); let params = PathParameters::none(); @@ -3302,7 +3302,7 @@ impl<'a> Resolver<'a> { let msg = format!("extern crate `{}` is private", name); self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg); } else { - let def = binding.def().unwrap(); + let def = binding.def(); self.session.span_err(span, &format!("{} `{}` is private", def.kind_name(), name)); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 81f99e2240b6f..e00c736138d3b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -639,9 +639,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - let def = match type_result.ok().and_then(NameBinding::def) { + let def = match type_result.ok().map(NameBinding::def) { Some(def) => def, - None => value_result.ok().and_then(NameBinding::def).unwrap(), + None => value_result.ok().map(NameBinding::def).unwrap(), }; let path_resolution = PathResolution::new(def); self.def_map.insert(directive.id, path_resolution); @@ -714,9 +714,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if binding.vis == ty::Visibility::Public && (binding.is_import() || binding.is_extern_crate()) { - if let Some(def) = binding.def() { - reexports.push(Export { name: name, def_id: def.def_id() }); - } + reexports.push(Export { name: name, def_id: binding.def().def_id() }); } if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { From 1e4c8173e182d6254c7faafb3d1e1020eac194c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 07:59:47 +0000 Subject: [PATCH 459/768] Improve diagnostics and remove dead code. --- src/librustc_resolve/lib.rs | 46 +++++++++++------------------ src/test/compile-fail/bad-module.rs | 8 +++-- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8a7a22988cb5f..6cf53f877fb60 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1287,7 +1287,7 @@ impl<'a> Resolver<'a> { while index < module_path_len { let name = module_path[index]; match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { - Failed(None) => { + Failed(_) => { let segment_name = name.as_str(); let module_name = module_to_string(search_module); let msg = if "???" == &module_name { @@ -1314,7 +1314,6 @@ impl<'a> Resolver<'a> { return Failed(span.map(|span| (span, msg))); } - Failed(err) => return Failed(err), Indeterminate => { debug!("(resolving module path for import) module resolution is \ indeterminate: {}", @@ -1383,7 +1382,11 @@ impl<'a> Resolver<'a> { let ident = ast::Ident::with_empty_ctxt(module_path[0]); match self.resolve_ident_in_lexical_scope(ident, TypeNS, span) .and_then(LexicalScopeBinding::module) { - None => return Failed(None), + None => { + let msg = + format!("Use of undeclared type or module `{}`", ident.name); + return Failed(span.map(|span| (span, msg))); + } Some(containing_module) => { search_module = containing_module; start_index = 1; @@ -2614,16 +2617,9 @@ impl<'a> Resolver<'a> { let containing_module; match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { Failed(err) => { - let (span, msg) = match err { - Some((span, msg)) => (span, msg), - None => { - let msg = format!("Use of undeclared type or module `{}`", - names_to_string(&module_path)); - (span, msg) - } - }; - - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + if let Some((span, msg)) = err { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + } return Err(true); } Indeterminate => return Err(false), @@ -2651,16 +2647,9 @@ impl<'a> Resolver<'a> { let containing_module; match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) { Failed(err) => { - let (span, msg) = match err { - Some((span, msg)) => (span, msg), - None => { - let msg = format!("Use of undeclared module `::{}`", - names_to_string(&module_path)); - (span, msg) - } - }; - - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + if let Some((span, msg)) = err { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + } return Err(true); } @@ -3270,12 +3259,11 @@ impl<'a> Resolver<'a> { path_resolution = PathResolution::new(def); ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap()) } - Failed(Some((span, msg))) => { - self.session.span_err(span, &format!("failed to resolve module path. {}", msg)); - ty::Visibility::Public - } - _ => { - self.session.span_err(path.span, "unresolved module path"); + Indeterminate => unreachable!(), + Failed(err) => { + if let Some((span, msg)) = err { + self.session.span_err(span, &format!("failed to resolve module path. {}", msg)); + } ty::Visibility::Public } }; diff --git a/src/test/compile-fail/bad-module.rs b/src/test/compile-fail/bad-module.rs index 0cd3a8853185f..6987d06ef12c3 100644 --- a/src/test/compile-fail/bad-module.rs +++ b/src/test/compile-fail/bad-module.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: failed to resolve. Use of undeclared type or module `thing` +fn main() { + let foo = thing::len(Vec::new()); + //~^ ERROR failed to resolve. Use of undeclared type or module `thing` -fn main() { let foo = thing::len(Vec::new()); } + let foo = foo::bar::baz(); + //~^ ERROR failed to resolve. Use of undeclared type or module `foo` +} From 95528d1a9839066a29cc1cb50b097d5f84633148 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 00:24:11 +0000 Subject: [PATCH 460/768] Refactor away `resolver.current_vis` and add `module.normal_ancestor_id`. --- src/librustc_resolve/build_reduced_graph.rs | 18 ++-- src/librustc_resolve/lib.rs | 106 +++++++------------- src/librustc_resolve/resolve_imports.rs | 12 +-- 3 files changed, 47 insertions(+), 89 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 71b00218e7cc1..83d35095f351b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -30,7 +30,7 @@ use syntax::ast::Name; use syntax::attr; use syntax::parse::token; -use syntax::ast::{Block, Crate}; +use syntax::ast::{Block, Crate, DUMMY_NODE_ID}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; @@ -81,7 +81,6 @@ impl<'b> Resolver<'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item) { let parent = self.current_module; - let parent_vis = self.current_vis; let name = item.ident.name; let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -204,7 +203,7 @@ impl<'b> Resolver<'b> { ItemKind::Mod(..) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), false); + let module = self.new_module(parent_link, Some(def), item.id); module.no_implicit_prelude.set({ parent.no_implicit_prelude.get() || attr::contains_name(&item.attrs, "no_implicit_prelude") @@ -214,7 +213,6 @@ impl<'b> Resolver<'b> { // Descend into the module. self.current_module = module; - self.current_vis = ty::Visibility::Restricted(item.id); } ItemKind::ForeignMod(..) => {} @@ -243,7 +241,7 @@ impl<'b> Resolver<'b> { ItemKind::Enum(ref enum_definition, _) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Enum(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), false); + let module = self.new_module(parent_link, Some(def), parent.normal_ancestor_id); self.define(parent, name, TypeNS, (module, sp, vis)); for variant in &(*enum_definition).variants { @@ -285,7 +283,8 @@ impl<'b> Resolver<'b> { // Add all the items within to a new module. let parent_link = ModuleParentLink(parent, name); let def = Def::Trait(def_id); - let module_parent = self.new_module(parent_link, Some(def), false); + let module_parent = + self.new_module(parent_link, Some(def), parent.normal_ancestor_id); self.define(parent, name, TypeNS, (module_parent, sp, vis)); // Add the names of all the items to the trait info. @@ -312,7 +311,6 @@ impl<'b> Resolver<'b> { visit::walk_item(&mut BuildReducedGraphVisitor { resolver: self }, item); self.current_module = parent; - self.current_vis = parent_vis; } // Constructs the reduced graph for one variant. Variants exist in the @@ -363,7 +361,7 @@ impl<'b> Resolver<'b> { block_id); let parent_link = BlockParentLink(parent, block_id); - let new_module = self.new_module(parent_link, None, false); + let new_module = self.new_module(parent_link, None, parent.normal_ancestor_id); self.module_map.insert(block_id, new_module); self.current_module = new_module; // Descend into the block. } @@ -395,7 +393,7 @@ impl<'b> Resolver<'b> { debug!("(building reduced graph for external crate) building module {} {:?}", name, vis); let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), true); + let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::Variant(_, variant_id) => { @@ -437,7 +435,7 @@ impl<'b> Resolver<'b> { } let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), true); + let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::TyAlias(..) | Def::AssociatedTy(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6cf53f877fb60..b17687e17575c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,7 +54,7 @@ use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; -use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; +use syntax::ast::{CRATE_NODE_ID, DUMMY_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -768,6 +768,9 @@ pub struct ModuleS<'a> { parent_link: ParentLink<'a>, def: Option, + // The node id of the closest normal module (`mod`) ancestor (including this module). + normal_ancestor_id: NodeId, + // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). extern_crate_id: Option, @@ -791,17 +794,18 @@ pub struct ModuleS<'a> { pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { - fn new(parent_link: ParentLink<'a>, def: Option, external: bool) -> Self { + fn new(parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) -> Self { ModuleS { parent_link: parent_link, def: def, + normal_ancestor_id: normal_ancestor_id, extern_crate_id: None, resolutions: RefCell::new(FnvHashMap()), no_implicit_prelude: Cell::new(false), glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), traits: RefCell::new(None), - populated: Cell::new(!external), + populated: Cell::new(normal_ancestor_id != DUMMY_NODE_ID), } } @@ -829,6 +833,13 @@ impl<'a> ModuleS<'a> { _ => false, } } + + fn parent(&self) -> Option<&'a Self> { + match self.parent_link { + ModuleParentLink(parent, _) | BlockParentLink(parent, _) => Some(parent), + NoParentLink => None, + } + } } impl<'a> fmt::Debug for ModuleS<'a> { @@ -983,10 +994,6 @@ pub struct Resolver<'a> { // The module that represents the current item scope. current_module: Module<'a>, - // The visibility of `pub(self)` items in the current scope. - // Equivalently, the visibility required for an item to be accessible from the current scope. - current_vis: ty::Visibility, - // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. value_ribs: Vec>, @@ -1079,15 +1086,12 @@ impl<'a> ResolverArenas<'a> { } impl<'a> ty::NodeIdTree for Resolver<'a> { - fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool { - let ancestor = self.definitions.local_def_id(ancestor); - let mut module = *self.module_map.get(&node).unwrap(); - while module.def_id() != Some(ancestor) { - let module_parent = match self.get_nearest_normal_module_parent(module) { - Some(parent) => parent, + fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool { + while node != ancestor { + node = match self.module_map[&node].parent() { + Some(parent) => parent.normal_ancestor_id, None => return false, - }; - module = module_parent; + } } true } @@ -1149,8 +1153,7 @@ impl<'a> Resolver<'a> { pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); - let graph_root = - ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false); + let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), CRATE_NODE_ID); let graph_root = arenas.alloc_module(graph_root); let mut module_map = NodeMap(); module_map.insert(CRATE_NODE_ID, graph_root); @@ -1173,7 +1176,6 @@ impl<'a> Resolver<'a> { indeterminate_imports: Vec::new(), current_module: graph_root, - current_vis: ty::Visibility::Restricted(ast::CRATE_NODE_ID), value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], type_ribs: vec![Rib::new(ModuleRibKind(graph_root))], label_ribs: Vec::new(), @@ -1217,21 +1219,20 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { self.current_module = self.graph_root; - self.current_vis = ty::Visibility::Restricted(ast::CRATE_NODE_ID); visit::walk_crate(self, krate); check_unused::check_crate(self, krate); self.report_privacy_errors(); } - fn new_module(&self, parent_link: ParentLink<'a>, def: Option, external: bool) + fn new_module(&self, parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) -> Module<'a> { - self.arenas.alloc_module(ModuleS::new(parent_link, def, external)) + self.arenas.alloc_module(ModuleS::new(parent_link, def, normal_ancestor_id)) } fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), false); + let mut module = ModuleS::new(parent_link, Some(def), local_node_id); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } @@ -1473,35 +1474,6 @@ impl<'a> Resolver<'a> { None } - /// Returns the nearest normal module parent of the given module. - fn get_nearest_normal_module_parent(&self, mut module: Module<'a>) -> Option> { - loop { - match module.parent_link { - NoParentLink => return None, - ModuleParentLink(new_module, _) | - BlockParentLink(new_module, _) => { - let new_module = new_module; - if new_module.is_normal() { - return Some(new_module); - } - module = new_module; - } - } - } - } - - /// Returns the nearest normal module parent of the given module, or the - /// module itself if it is a normal module. - fn get_nearest_normal_module_parent_or_self(&self, module: Module<'a>) -> Module<'a> { - if module.is_normal() { - return module; - } - match self.get_nearest_normal_module_parent(module) { - None => module, - Some(new_module) => new_module, - } - } - /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`; /// (b) some chain of `super::`. /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * @@ -1514,22 +1486,19 @@ impl<'a> Resolver<'a> { "super" => 0, _ => return Success(NoPrefixFound), }; - let mut containing_module = - self.get_nearest_normal_module_parent_or_self(self.current_module); + + let mut containing_module = self.module_map[&self.current_module.normal_ancestor_id]; // Now loop through all the `super`s we find. while i < module_path.len() && "super" == module_path[i].as_str() { debug!("(resolving module prefix) resolving `super` at {}", module_to_string(&containing_module)); - match self.get_nearest_normal_module_parent(containing_module) { - None => { - let msg = "There are too many initial `super`s.".into(); - return Failed(span.map(|span| (span, msg))); - } - Some(new_module) => { - containing_module = new_module; - i += 1; - } + if let Some(parent) = containing_module.parent() { + containing_module = self.module_map[&parent.normal_ancestor_id]; + i += 1; + } else { + let msg = "There are too many initial `super`s.".into(); + return Failed(span.map(|span| (span, msg))); } } @@ -1564,14 +1533,12 @@ impl<'a> Resolver<'a> { if let Some(module) = module { // Move down in the graph. let orig_module = replace(&mut self.current_module, module); - let orig_vis = replace(&mut self.current_vis, ty::Visibility::Restricted(id)); self.value_ribs.push(Rib::new(ModuleRibKind(module))); self.type_ribs.push(Rib::new(ModuleRibKind(module))); f(self); self.current_module = orig_module; - self.current_vis = orig_vis; self.value_ribs.pop(); self.type_ribs.pop(); } else { @@ -3248,16 +3215,17 @@ impl<'a> Resolver<'a> { ast::Visibility::Public => return ty::Visibility::Public, ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID), ast::Visibility::Restricted { ref path, id } => (path, id), - ast::Visibility::Inherited => return self.current_vis, + ast::Visibility::Inherited => { + return ty::Visibility::Restricted(self.current_module.normal_ancestor_id); + } }; let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect(); let mut path_resolution = err_path_resolution(); let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { Success(module) => { - let def = module.def.unwrap(); - path_resolution = PathResolution::new(def); - ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap()) + path_resolution = PathResolution::new(module.def.unwrap()); + ty::Visibility::Restricted(module.normal_ancestor_id) } Indeterminate => unreachable!(), Failed(err) => { @@ -3276,7 +3244,7 @@ impl<'a> Resolver<'a> { } fn is_accessible(&self, vis: ty::Visibility) -> bool { - vis.is_at_least(self.current_vis, self) + vis.is_accessible_from(self.current_module.normal_ancestor_id, self) } fn report_privacy_errors(&self) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e00c736138d3b..a0aab53c58f09 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -381,14 +381,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // remain or unsuccessfully when no forward progress in resolving imports // is made. - fn set_current_module(&mut self, module: Module<'b>) { - self.current_module = module; - self.current_vis = ty::Visibility::Restricted({ - let normal_module = self.get_nearest_normal_module_parent_or_self(module); - self.definitions.as_local_node_id(normal_module.def_id().unwrap()).unwrap() - }); - } - /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. fn resolve_imports(&mut self) { @@ -472,7 +464,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { names_to_string(&directive.module_path), module_to_string(self.current_module)); - self.set_current_module(directive.parent); + self.current_module = directive.parent; let module = if let Some(module) = directive.imported_module.get() { module @@ -548,7 +540,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> { - self.set_current_module(directive.parent); + self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span)); From 513e955a1891d12819ba642331eb436d00861f3d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 04:05:49 +0000 Subject: [PATCH 461/768] Add field `dummy_binding` to `Resolver`. --- src/librustc_resolve/lib.rs | 8 +++++++- src/librustc_resolve/resolve_imports.rs | 9 ++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b17687e17575c..124a748be326f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -65,7 +65,7 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind}; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use errors::DiagnosticBuilder; use std::cell::{Cell, RefCell}; @@ -1052,6 +1052,7 @@ pub struct Resolver<'a> { privacy_errors: Vec>, arenas: &'a ResolverArenas<'a>, + dummy_binding: &'a NameBinding<'a>, } pub struct ResolverArenas<'a> { @@ -1203,6 +1204,11 @@ impl<'a> Resolver<'a> { privacy_errors: Vec::new(), arenas: arenas, + dummy_binding: arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Def(Def::Err), + span: DUMMY_SP, + vis: ty::Visibility::Public, + }), } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a0aab53c58f09..f02e9b048dea7 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -27,7 +27,7 @@ use rustc::hir::def::*; use syntax::ast::{NodeId, Name}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use std::cell::{Cell, RefCell}; @@ -442,13 +442,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // failed resolution fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) { if let SingleImport { target, .. } = directive.subclass { - let dummy_binding = self.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(Def::Err), - span: DUMMY_SP, - vis: ty::Visibility::Public, - }); + let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, directive); - let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone()); let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding); } From 5ba22c0ed68ed4b46c9db2ceac2e5cc96728411a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 16 Aug 2016 06:03:36 +0000 Subject: [PATCH 462/768] Add `item_like_imports` feature. --- src/librustc_resolve/lib.rs | 2 ++ src/libsyntax/feature_gate.rs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 124a748be326f..8428507e686df 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1053,6 +1053,7 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, + new_import_semantics: bool, // true if `#![feature(item_like_imports)]` } pub struct ResolverArenas<'a> { @@ -1209,6 +1210,7 @@ impl<'a> Resolver<'a> { span: DUMMY_SP, vis: ty::Visibility::Public, }), + new_import_semantics: session.features.borrow().item_like_imports, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e224e30b1a2a4..02c44c3a56d7e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -285,7 +285,10 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI - (active, abi_sysv64, "1.13.0", Some(36167)) + (active, abi_sysv64, "1.13.0", Some(36167)), + + // Use the import semantics from RFC 1560. + (active, item_like_imports, "1.13.0", Some(35120)) ); declare_features! ( From efc0bea687a6c412b7d11acab12ada8e33050089 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 00:57:19 +0000 Subject: [PATCH 463/768] item_like_imports: Treat private imports like private items. --- src/librustc_resolve/resolve_imports.rs | 4 +++- src/test/run-pass/imports.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/imports.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f02e9b048dea7..d6aae23947f2e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -167,8 +167,10 @@ impl<'a> Resolver<'a> { _ => return Failed(None), // This happens when there is a cycle of imports }; + let new_import_semantics = self.new_import_semantics; let is_disallowed_private_import = |binding: &NameBinding| { - !allow_private_imports && binding.vis != ty::Visibility::Public && binding.is_import() + !new_import_semantics && !allow_private_imports && // disallowed + binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import }; if let Some(span) = record_used { diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs new file mode 100644 index 0000000000000..900e0b69ebba5 --- /dev/null +++ b/src/test/run-pass/imports.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(item_like_imports)] +#![allow(unused)] + +// Like other items, private imports can be imported and used non-lexically in paths. +mod a { + use a as foo; + use self::foo::foo as bar; + + mod b { + use super::bar; + } +} + +fn main() {} From aad1f3cbf3340afd0685b79981a59f0ba3e83116 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 20:33:24 +0000 Subject: [PATCH 464/768] item_like_imports: Allow glob imports to be shadowed by items and single imports. --- src/librustc_resolve/resolve_imports.rs | 20 +++++++----- src/test/run-pass/imports.rs | 42 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index d6aae23947f2e..c7cb3a351784d 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -690,15 +690,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; // Report conflicts - for duplicate_glob in resolution.duplicate_globs.iter() { - // FIXME #31337: We currently allow items to shadow glob-imported re-exports. - if !binding.is_import() { - if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind { - if binding.is_import() { continue } + if !self.new_import_semantics { + for duplicate_glob in resolution.duplicate_globs.iter() { + // FIXME #31337: We currently allow items to shadow glob-imported re-exports. + if !binding.is_import() { + if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind { + if binding.is_import() { continue } + } } - } - self.report_conflict(module, name, ns, duplicate_glob, binding); + self.report_conflict(module, name, ns, duplicate_glob, binding); + } + } else if binding.is_glob_import() { + for duplicate_glob in resolution.duplicate_globs.iter() { + self.report_conflict(module, name, ns, duplicate_glob, binding); + } } if binding.vis == ty::Visibility::Public && diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index 900e0b69ebba5..df4961c074ae1 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -21,4 +21,46 @@ mod a { } } +mod foo { pub fn f() {} } +mod bar { pub fn f() {} } + +pub fn f() -> bool { true } + +// Items and explicit imports shadow globs. +fn g() { + use foo::*; + use bar::*; + fn f() -> bool { true } + let _: bool = f(); +} + +fn h() { + use foo::*; + use bar::*; + use f; + let _: bool = f(); +} + +// Here, there appears to be shadowing but isn't because of namespaces. +mod b { + use foo::*; // This imports `f` in the value namespace. + use super::b as f; // This imports `f` only in the type namespace, + fn test() { self::f(); } // so the glob isn't shadowed. +} + +// Here, there is shadowing in one namespace, but not the other. +mod c { + mod test { + pub fn f() {} + pub mod f {} + } + use self::test::*; // This glob-imports `f` in both namespaces. + mod f { pub fn f() {} } // This shadows the glob only in the value namespace. + + fn test() { + self::f(); // Check that the glob-imported value isn't shadowed. + self::f::f(); // Check that the glob-imported module is shadowed. + } +} + fn main() {} From c56a5afd4d1c4717770efa693e69eead13abee34 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 19 Aug 2016 22:52:26 +0000 Subject: [PATCH 465/768] item_like_imports: Allow single imports with a given visibility to reexport some (but not all) namespaces with less visibility. --- src/librustc_resolve/resolve_imports.rs | 51 +++++++++++++++++----- src/test/compile-fail/imports/reexports.rs | 37 ++++++++++++++++ 2 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/imports/reexports.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c7cb3a351784d..7084aa685aec5 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -285,13 +285,20 @@ impl<'a> Resolver<'a> { // return the corresponding binding defined by the import directive. fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) -> NameBinding<'a> { + let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || + !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC` + directive.vis.get() + } else { + binding.pseudo_vis() + }; + NameBinding { kind: NameBindingKind::Import { binding: binding, directive: directive, }, span: directive.span, - vis: directive.vis.get(), + vis: vis, } } @@ -597,22 +604,44 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } + let session = self.session; + let reexport_error = || { + let msg = format!("`{}` is private, and cannot be reexported", name); + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", name); + struct_span_err!(session, directive.span, E0364, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); + }; + + let extern_crate_lint = || { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", + name); + session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + }; + match (value_result, type_result) { + // With `#![feature(item_like_imports)]`, all namespaces + // must be re-exported with extra visibility for an error to occur. + (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => { + let vis = directive.vis.get(); + if !value_binding.pseudo_vis().is_at_least(vis, self) && + !type_binding.pseudo_vis().is_at_least(vis, self) { + reexport_error(); + } else if type_binding.is_extern_crate() && + !type_binding.vis.is_at_least(vis, self) { + extern_crate_lint(); + } + } + (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - let msg = format!("`{}` is private, and cannot be reexported", name); - let note_msg = - format!("consider marking `{}` as `pub` in the imported module", name); - struct_span_err!(self.session, directive.span, E0364, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); + reexport_error(); } (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { if binding.is_extern_crate() { - let msg = format!("extern crate `{}` is private, and cannot be reexported \ - (error E0364), consider declaring with `pub`", - name); - self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + extern_crate_lint(); } else { struct_span_err!(self.session, directive.span, E0365, "`{}` is private, and cannot be reexported", name) diff --git a/src/test/compile-fail/imports/reexports.rs b/src/test/compile-fail/imports/reexports.rs new file mode 100644 index 0000000000000..f8dbb4d444886 --- /dev/null +++ b/src/test/compile-fail/imports/reexports.rs @@ -0,0 +1,37 @@ +// 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. + +#![feature(item_like_imports)] + +mod a { + fn foo() {} + mod foo {} + + mod a { + pub use super::foo; //~ ERROR cannot be reexported + } +} + +mod b { + pub fn foo() {} + mod foo { pub struct S; } + + pub mod a { + pub use super::foo; // This is OK since the value `foo` is visible enough. + fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported). + } +} + +mod c { + // Test that `foo` is not reexported. + use b::a::foo::S; //~ ERROR `foo` +} + +fn main() {} From 097b6d62fc7431b322b46b3a0e9f36134c13dd82 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 00:23:32 +0000 Subject: [PATCH 466/768] item_like_imports: Allow glob imports with a given visibility to reexport some (but not all) names with less visibility. --- src/librustc_resolve/build_reduced_graph.rs | 7 +++++- src/librustc_resolve/resolve_imports.rs | 25 +++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 83d35095f351b..0c7c970371877 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -26,6 +26,8 @@ use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::ty::{self, VariantKind}; +use std::cell::Cell; + use syntax::ast::Name; use syntax::attr; use syntax::parse::token; @@ -176,7 +178,10 @@ impl<'b> Resolver<'b> { } } ViewPathGlob(_) => { - let subclass = GlobImport { is_prelude: is_prelude }; + let subclass = GlobImport { + is_prelude: is_prelude, + max_vis: Cell::new(ty::Visibility::PrivateExternal), + }; let span = view_path.span; self.add_import_directive(module_path, subclass, span, item.id, vis); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 7084aa685aec5..189253348b0aa 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -52,7 +52,10 @@ pub enum ImportDirectiveSubclass<'a> { value_result: Cell, Determinacy>>, type_result: Cell, Determinacy>>, }, - GlobImport { is_prelude: bool }, + GlobImport { + is_prelude: bool, + max_vis: Cell, // The visibility of the greatest reexport. + }, } impl<'a> ImportDirectiveSubclass<'a> { @@ -276,7 +279,7 @@ impl<'a> Resolver<'a> { } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. - GlobImport { is_prelude: true } => {} + GlobImport { is_prelude: true, .. } => {} GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive), } } @@ -292,6 +295,12 @@ impl<'a> Resolver<'a> { binding.pseudo_vis() }; + if let GlobImport { ref max_vis, .. } = directive.subclass { + if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) { + max_vis.set(vis) + } + } + NameBinding { kind: NameBindingKind::Import { binding: binding, @@ -562,7 +571,15 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let msg = "Cannot glob-import a module into itself.".into(); return Failed(Some((directive.span, msg))); } - GlobImport { .. } => return Success(()), + GlobImport { is_prelude, ref max_vis } => { + if !is_prelude && + max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs. + !max_vis.get().is_at_least(directive.vis.get(), self) { + let msg = "A non-empty glob must import something with the glob's visibility"; + self.session.span_err(directive.span, msg); + } + return Success(()); + } }; for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { @@ -677,7 +694,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { return; } else if module.def_id() == directive.parent.def_id() { return; - } else if let GlobImport { is_prelude: true } = directive.subclass { + } else if let GlobImport { is_prelude: true, .. } = directive.subclass { self.prelude = Some(module); return; } From 245a0c5530f8d4d251bcef2d7b8de2fa19f442bf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 00:33:06 +0000 Subject: [PATCH 467/768] item_like_imports: Make all visible items glob importable. --- src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/resolve_imports.rs | 10 +++++++--- src/test/compile-fail/imports/reexports.rs | 7 +++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8428507e686df..12b708fa1a163 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3255,6 +3255,10 @@ impl<'a> Resolver<'a> { vis.is_accessible_from(self.current_module.normal_ancestor_id, self) } + fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { + vis.is_accessible_from(module.normal_ancestor_id, self) + } + fn report_privacy_errors(&self) { if self.privacy_errors.len() == 0 { return } let mut reported_spans = FnvHashSet(); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 189253348b0aa..4ab4ec4789d01 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -356,8 +356,11 @@ impl<'a> Resolver<'a> { }; // Define `binding` in `module`s glob importers. - if binding.vis == ty::Visibility::Public { - for directive in module.glob_importers.borrow_mut().iter() { + for directive in module.glob_importers.borrow_mut().iter() { + if match self.new_import_semantics { + true => self.is_accessible_from(binding.vis, directive.parent), + false => binding.vis == ty::Visibility::Public, + } { let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } @@ -708,7 +711,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { resolution.borrow().binding().map(|binding| (*name, binding)) }).collect::>(); for ((name, ns), binding) in bindings { - if binding.pseudo_vis() == ty::Visibility::Public { + if binding.pseudo_vis() == ty::Visibility::Public || + self.new_import_semantics && self.is_accessible(binding.vis) { let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } diff --git a/src/test/compile-fail/imports/reexports.rs b/src/test/compile-fail/imports/reexports.rs index f8dbb4d444886..fc46b23351adf 100644 --- a/src/test/compile-fail/imports/reexports.rs +++ b/src/test/compile-fail/imports/reexports.rs @@ -16,6 +16,7 @@ mod a { mod a { pub use super::foo; //~ ERROR cannot be reexported + pub use super::*; //~ ERROR must import something with the glob's visibility } } @@ -27,11 +28,17 @@ mod b { pub use super::foo; // This is OK since the value `foo` is visible enough. fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported). } + + pub mod b { + pub use super::*; // This is also OK since the value `foo` is visible enough. + fn f(_: foo::S) {} // Again, the module `foo` is imported (but not `pub` reexported). + } } mod c { // Test that `foo` is not reexported. use b::a::foo::S; //~ ERROR `foo` + use b::b::foo::S as T; //~ ERROR `foo` } fn main() {} From f582fa327e210ea5bf91d6b8f174f35fc9006054 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 03:28:35 +0000 Subject: [PATCH 468/768] item_like_imports: Allow multiple glob imports of the same item. --- src/librustc_resolve/resolve_imports.rs | 20 +++++++++--- src/test/compile-fail/imports/duplicate.rs | 38 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/imports/duplicate.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4ab4ec4789d01..495bdcb7dfd2a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -317,10 +317,17 @@ impl<'a> Resolver<'a> { where T: ToNameBinding<'a> { let binding = self.arenas.alloc_name_binding(binding.to_name_binding()); - self.update_resolution(module, name, ns, |_, resolution| { + self.update_resolution(module, name, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { - resolution.duplicate_globs.push(binding); + if !this.new_import_semantics || !old_binding.is_glob_import() { + resolution.duplicate_globs.push(binding); + } else if binding.def() != old_binding.def() { + resolution.duplicate_globs.push(binding); + } else if !old_binding.vis.is_at_least(binding.vis, this) { + // We are glob-importing the same item but with greater visibility. + resolution.binding = Some(binding); + } } else if old_binding.is_glob_import() { resolution.duplicate_globs.push(old_binding); resolution.binding = Some(binding); @@ -344,14 +351,17 @@ impl<'a> Resolver<'a> { // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t) = { let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut(); - let was_known = resolution.binding().is_some(); + let old_binding = resolution.binding(); let t = f(self, resolution); - if was_known { return t; } match resolution.binding() { - Some(binding) => (binding, t), + _ if !self.new_import_semantics && old_binding.is_some() => return t, None => return t, + Some(binding) => match old_binding { + Some(old_binding) if old_binding as *const _ == binding as *const _ => return t, + _ => (binding, t), + } } }; diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs new file mode 100644 index 0000000000000..0b5963dd89315 --- /dev/null +++ b/src/test/compile-fail/imports/duplicate.rs @@ -0,0 +1,38 @@ +// 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. + +#![feature(item_like_imports)] + +mod a { + pub fn foo() {} +} + +mod b { + pub fn foo() {} +} + +mod c { + pub use a::foo; +} + +mod d { + use a::foo; //~ NOTE previous import + use a::foo; //~ ERROR `foo` has already been imported + //~| NOTE already imported +} + +mod e { + pub use a::*; + pub use c::*; // ok +} + +fn main() { + e::foo(); +} From 681a14f29b5e8d8745bda4fc7ba4d4ccb634ddb9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 05:23:19 +0000 Subject: [PATCH 469/768] item_like_imports: Allow unused ambiguous glob imports. --- src/librustc_resolve/lib.rs | 34 ++++++++++++++++++++-- src/librustc_resolve/resolve_imports.rs | 31 +++++++++++++++----- src/test/compile-fail/imports/duplicate.rs | 14 +++++++++ src/test/run-pass/imports.rs | 10 +++++++ 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 12b708fa1a163..d77258f44eb9a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -874,6 +874,10 @@ enum NameBindingKind<'a> { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, }, + Ambiguity { + b1: &'a NameBinding<'a>, + b2: &'a NameBinding<'a>, + } } #[derive(Clone, Debug)] @@ -885,6 +889,7 @@ impl<'a> NameBinding<'a> { NameBindingKind::Module(module) => Some(module), NameBindingKind::Def(_) => None, NameBindingKind::Import { binding, .. } => binding.module(), + NameBindingKind::Ambiguity { .. } => None, } } @@ -893,6 +898,7 @@ impl<'a> NameBinding<'a> { NameBindingKind::Def(def) => def, NameBindingKind::Module(module) => module.def.unwrap(), NameBindingKind::Import { binding, .. } => binding.def(), + NameBindingKind::Ambiguity { .. } => Def::Err, } } @@ -922,6 +928,7 @@ impl<'a> NameBinding<'a> { fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { directive, .. } => directive.is_glob(), + NameBindingKind::Ambiguity { .. } => true, _ => false, } } @@ -932,6 +939,14 @@ impl<'a> NameBinding<'a> { _ => true, } } + + fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> { + match self.kind { + NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)), + NameBindingKind::Import { binding, .. } => binding.ambiguity(), + _ => None, + } + } } /// Interns the names of the primitive types. @@ -1249,7 +1264,8 @@ impl<'a> Resolver<'a> { match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs } } - fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { + fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) + -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) { self.used_crates.insert(krate); @@ -1259,6 +1275,19 @@ impl<'a> Resolver<'a> { self.used_imports.insert((directive.id, ns)); self.add_to_glob_map(directive.id, name); } + + if let Some((b1, b2)) = binding.ambiguity() { + let msg1 = format!("`{}` could resolve to the name imported here", name); + let msg2 = format!("`{}` could also resolve to the name imported here", name); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + .span_note(b1.span, &msg1) + .span_note(b2.span, &msg2) + .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) + .emit(); + return true; + } + + false } fn add_to_glob_map(&mut self, id: NodeId, name: Name) { @@ -2294,7 +2323,8 @@ impl<'a> Resolver<'a> { Def::Struct(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) if !always_binding => { // A constant, unit variant, etc pattern. - self.record_use(ident.node.name, ValueNS, binding.unwrap()); + let name = ident.node.name; + self.record_use(name, ValueNS, binding.unwrap(), ident.span); Some(PathResolution::new(def)) } Def::Struct(..) | Def::Variant(..) | diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 495bdcb7dfd2a..cb89231fc0551 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -181,7 +181,9 @@ impl<'a> Resolver<'a> { if is_disallowed_private_import(binding) { return Failed(None); } - self.record_use(name, ns, binding); + if self.record_use(name, ns, binding, span) { + return Success(self.dummy_binding); + } if !self.is_accessible(binding.vis) { self.privacy_errors.push(PrivacyError(span, name, binding)); } @@ -323,7 +325,18 @@ impl<'a> Resolver<'a> { if !this.new_import_semantics || !old_binding.is_glob_import() { resolution.duplicate_globs.push(binding); } else if binding.def() != old_binding.def() { - resolution.duplicate_globs.push(binding); + resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Ambiguity { + b1: old_binding, + b2: binding, + }, + vis: if old_binding.vis.is_at_least(binding.vis, this) { + old_binding.vis + } else { + binding.vis + }, + span: old_binding.span, + })); } else if !old_binding.vis.is_at_least(binding.vis, this) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); @@ -597,7 +610,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { if let Ok(binding) = result { - self.record_use(name, ns, binding); + if self.record_use(name, ns, binding, directive.span) { + self.resolution(module, name, ns).borrow_mut().binding = + Some(self.dummy_binding); + } } } @@ -759,17 +775,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - self.report_conflict(module, name, ns, duplicate_glob, binding); - } - } else if binding.is_glob_import() { - for duplicate_glob in resolution.duplicate_globs.iter() { self.report_conflict(module, name, ns, duplicate_glob, binding); } } if binding.vis == ty::Visibility::Public && (binding.is_import() || binding.is_extern_crate()) { - reexports.push(Export { name: name, def_id: binding.def().def_id() }); + let def = binding.def(); + if def != Def::Err { + reexports.push(Export { name: name, def_id: def.def_id() }); + } } if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index 0b5963dd89315..05c0d9cd38e83 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -33,6 +33,20 @@ mod e { pub use c::*; // ok } +mod f { + pub use a::*; //~ NOTE `foo` could resolve to the name imported here + pub use b::*; //~ NOTE `foo` could also resolve to the name imported here +} + +mod g { + pub use a::*; //~ NOTE `foo` could resolve to the name imported here + pub use f::*; //~ NOTE `foo` could also resolve to the name imported here +} + fn main() { e::foo(); + f::foo(); //~ ERROR `foo` is ambiguous + //~| NOTE Consider adding an explicit import of `foo` to disambiguate + g::foo(); //~ ERROR `foo` is ambiguous + //~| NOTE Consider adding an explicit import of `foo` to disambiguate } diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index df4961c074ae1..195b99c9788e8 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -63,4 +63,14 @@ mod c { } } +// Unused names can be ambiguous. +mod d { + pub use foo::*; // This imports `f` in the value namespace. + pub use bar::*; // This also imports `f` in the value namespace. +} + +mod e { + pub use d::*; // n.b. Since `e::f` is not used, this is not considered to be a use of `d::f`. +} + fn main() {} From 32a0cfeb485f2c1bbfe52eaa9e119e974e38f21f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 08:30:07 +0000 Subject: [PATCH 470/768] Avoid reporting multiple ambiguity errors for a single use of a name. --- src/librustc_resolve/lib.rs | 30 ++++++++++++++-------- src/test/compile-fail/imports/duplicate.rs | 13 ++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d77258f44eb9a..a881feaa4d353 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1065,6 +1065,7 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, + ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>)>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1218,6 +1219,7 @@ impl<'a> Resolver<'a> { maybe_unused_trait_imports: NodeSet(), privacy_errors: Vec::new(), + ambiguity_errors: Vec::new(), arenas: arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { @@ -1245,7 +1247,7 @@ impl<'a> Resolver<'a> { visit::walk_crate(self, krate); check_unused::check_crate(self, krate); - self.report_privacy_errors(); + self.report_errors(); } fn new_module(&self, parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) @@ -1276,14 +1278,8 @@ impl<'a> Resolver<'a> { self.add_to_glob_map(directive.id, name); } - if let Some((b1, b2)) = binding.ambiguity() { - let msg1 = format!("`{}` could resolve to the name imported here", name); - let msg2 = format!("`{}` could also resolve to the name imported here", name); - self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) - .span_note(b1.span, &msg1) - .span_note(b2.span, &msg2) - .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) - .emit(); + if binding.ambiguity().is_some() { + self.ambiguity_errors.push((span, name, binding)); return true; } @@ -3289,9 +3285,21 @@ impl<'a> Resolver<'a> { vis.is_accessible_from(module.normal_ancestor_id, self) } - fn report_privacy_errors(&self) { - if self.privacy_errors.len() == 0 { return } + fn report_errors(&self) { let mut reported_spans = FnvHashSet(); + + for &(span, name, binding) in &self.ambiguity_errors { + if !reported_spans.insert(span) { continue } + let (b1, b2) = binding.ambiguity().unwrap(); + let msg1 = format!("`{}` could resolve to the name imported here", name); + let msg2 = format!("`{}` could also resolve to the name imported here", name); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + .span_note(b1.span, &msg1) + .span_note(b2.span, &msg2) + .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) + .emit(); + } + for &PrivacyError(span, name, binding) in &self.privacy_errors { if !reported_spans.insert(span) { continue } if binding.is_extern_crate() { diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index 05c0d9cd38e83..70936b2544646 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -50,3 +50,16 @@ fn main() { g::foo(); //~ ERROR `foo` is ambiguous //~| NOTE Consider adding an explicit import of `foo` to disambiguate } + +mod ambiguous_module_errors { + pub mod m1 { pub use super::m1 as foo; } + pub mod m2 { pub use super::m2 as foo; } + + use self::m1::*; //~ NOTE + use self::m2::*; //~ NOTE + + fn f() { + foo::bar(); //~ ERROR `foo` is ambiguous + //~| NOTE + } +} From 4f5616e3c43f866f4758a21f67d98da52b89ee20 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 07:12:13 +0000 Subject: [PATCH 471/768] Avoid cascading name resolution errors caused by an ambiguous module. --- src/librustc_resolve/lib.rs | 68 +++++++++++++--------- src/librustc_resolve/resolve_imports.rs | 2 +- src/test/compile-fail/imports/duplicate.rs | 5 ++ 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a881feaa4d353..0fe7f9ed21547 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -749,10 +749,6 @@ impl<'a> LexicalScopeBinding<'a> { _ => None, } } - - fn module(self) -> Option> { - self.item().and_then(NameBinding::module) - } } /// The link from a module up to its nearest parent node. @@ -884,12 +880,13 @@ enum NameBindingKind<'a> { struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); impl<'a> NameBinding<'a> { - fn module(&self) -> Option> { + fn module(&self) -> Result, bool /* true if an error has already been reported */> { match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Def(_) => None, + NameBindingKind::Module(module) => Ok(module), NameBindingKind::Import { binding, .. } => binding.module(), - NameBindingKind::Ambiguity { .. } => None, + NameBindingKind::Def(Def::Err) => Err(true), + NameBindingKind::Def(_) => Err(false), + NameBindingKind::Ambiguity { .. } => Err(false), } } @@ -915,7 +912,7 @@ impl<'a> NameBinding<'a> { } fn is_extern_crate(&self) -> bool { - self.module().and_then(|module| module.extern_crate_id).is_some() + self.module().ok().and_then(|module| module.extern_crate_id).is_some() } fn is_import(&self) -> bool { @@ -1269,7 +1266,7 @@ impl<'a> Resolver<'a> { fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint - if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) { + if let Some(DefId { krate, .. }) = binding.module().ok().and_then(ModuleS::def_id) { self.used_crates.insert(krate); } @@ -1292,6 +1289,18 @@ impl<'a> Resolver<'a> { } } + fn expect_module(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Option) + -> ResolveResult> { + match binding.module() { + Ok(module) => Success(module), + Err(true) => Failed(None), + Err(false) => { + let msg = format!("Not a module `{}`", name); + Failed(span.map(|span| (span, msg))) + } + } + } + /// Resolves the given module path from the given root `search_module`. fn resolve_module_path_from_root(&mut self, mut search_module: Module<'a>, @@ -1357,11 +1366,9 @@ impl<'a> Resolver<'a> { Success(binding) => { // Check to see whether there are type bindings, and, if // so, whether there is a module within. - if let Some(module_def) = binding.module() { - search_module = module_def; - } else { - let msg = format!("Not a module `{}`", name); - return Failed(span.map(|span| (span, msg))); + match self.expect_module(name, binding, span) { + Success(module) => search_module = module, + result @ _ => return result, } } } @@ -1414,17 +1421,20 @@ impl<'a> Resolver<'a> { // first component of the path in the current lexical // scope and then proceed to resolve below that. let ident = ast::Ident::with_empty_ctxt(module_path[0]); - match self.resolve_ident_in_lexical_scope(ident, TypeNS, span) - .and_then(LexicalScopeBinding::module) { - None => { - let msg = - format!("Use of undeclared type or module `{}`", ident.name); - return Failed(span.map(|span| (span, msg))); - } - Some(containing_module) => { - search_module = containing_module; - start_index = 1; + let lexical_binding = + self.resolve_ident_in_lexical_scope(ident, TypeNS, span); + if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) { + match self.expect_module(ident.name, binding, span) { + Success(containing_module) => { + search_module = containing_module; + start_index = 1; + } + result @ _ => return result, } + } else { + let msg = + format!("Use of undeclared type or module `{}`", ident.name); + return Failed(span.map(|span| (span, msg))); } } } @@ -3202,7 +3212,7 @@ impl<'a> Resolver<'a> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Ok(module) = name_binding.module() { // form the path let path_segments = match module.parent_link { NoParentLink => path_segments.clone(), @@ -3341,9 +3351,9 @@ impl<'a> Resolver<'a> { let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", - (TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate", - (TypeNS, Some(module)) if module.is_normal() => "a module", - (TypeNS, Some(module)) if module.is_trait() => "a trait", + (TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate", + (TypeNS, Ok(module)) if module.is_normal() => "a module", + (TypeNS, Ok(module)) if module.is_trait() => "a trait", (TypeNS, _) => "a type", }; format!("{} named `{}` has already been {} in this {}", diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index cb89231fc0551..c8982d95d4e00 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -460,7 +460,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { errors = true; let (span, help) = match err { Some((span, msg)) => (span, msg), - None => (import.span, String::new()), + None => continue, }; // If the error is a single failed import then create a "fake" import diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index 70936b2544646..fb61bb8e489be 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -56,7 +56,12 @@ mod ambiguous_module_errors { pub mod m2 { pub use super::m2 as foo; } use self::m1::*; //~ NOTE + //~| NOTE use self::m2::*; //~ NOTE + //~| NOTE + + use self::foo::bar; //~ ERROR `foo` is ambiguous + //~| NOTE fn f() { foo::bar(); //~ ERROR `foo` is ambiguous From 7cd4e7ff0b2e0872ed5dac00f3b680e7dbc3d24b Mon Sep 17 00:00:00 2001 From: Eugene R Gonzalez Date: Thu, 1 Sep 2016 18:46:30 -0400 Subject: [PATCH 472/768] Fixed E0528 label and unit test --- src/librustc_typeck/check/_match.rs | 9 ++++++--- src/test/compile-fail/E0528.rs | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 225468cb9f40c..e1ce89f0ab5dc 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -248,9 +248,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else if let Some(rest) = size.checked_sub(min_len) { (inner_ty, tcx.mk_array(inner_ty, rest)) } else { - span_err!(tcx.sess, pat.span, E0528, - "pattern requires at least {} elements but array has {}", - min_len, size); + struct_span_err!(tcx.sess, pat.span, E0528, + "pattern requires at least {} elements but array has {}", + min_len, size) + .span_label(pat.span, + &format!("pattern cannot match array of {} elements", size)) + .emit(); (inner_ty, tcx.types.err) } } diff --git a/src/test/compile-fail/E0528.rs b/src/test/compile-fail/E0528.rs index 27187bb5aba08..e912650f11292 100644 --- a/src/test/compile-fail/E0528.rs +++ b/src/test/compile-fail/E0528.rs @@ -13,7 +13,9 @@ fn main() { let r = &[1, 2]; match r { - &[a, b, c, rest..] => { //~ ERROR E0528 + &[a, b, c, rest..] => { + //~^ ERROR E0528 + //~| NOTE pattern cannot match array of 2 elements } } } From 96283fc08367ae8c3d344f2342c4ebe11d799092 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 1 Sep 2016 10:52:44 -0700 Subject: [PATCH 473/768] test: Add a min-llvm-version directive We've got tests which require a particular version of LLVM to run as they're testing bug fixes. Our build system, however, supports multiple LLVM versions, so we can't run these tests on all LLVM versions. This adds a new `min-llvm-version` directive for tests so they can opt out of being run on older versions of LLVM. This then namely applies that logic to the `issue-36023.rs` test case and... Closes #36138 --- mk/main.mk | 1 + mk/tests.mk | 1 + src/bootstrap/check.rs | 4 +++- src/test/run-pass/issue-36023.rs | 2 ++ src/tools/compiletest/src/common.rs | 3 +++ src/tools/compiletest/src/header.rs | 22 +++++++++++++++++++++- src/tools/compiletest/src/main.rs | 2 ++ 7 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mk/main.mk b/mk/main.mk index 5a849af9856f1..6130b58138751 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -348,6 +348,7 @@ LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1)) LLC_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llc$$(X_$(1)) LLVM_ALL_COMPONENTS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --components) +LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version) endef diff --git a/mk/tests.mk b/mk/tests.mk index 201e4cae51d6d..c135aa9b8fb95 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -649,6 +649,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \ --lldb-python $$(CFG_LLDB_PYTHON) \ --gdb-version="$(CFG_GDB_VERSION)" \ --lldb-version="$(CFG_LLDB_VERSION)" \ + --llvm-version="$$(LLVM_VERSION_$(3))" \ --android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \ --adb-path=$(CFG_ADB) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \ diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 3d8b1438125e6..2b9d717cbd48d 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -148,6 +148,9 @@ pub fn compiletest(build: &Build, if let Some(ref dir) = build.lldb_python_dir { cmd.arg("--lldb-python-dir").arg(dir); } + let llvm_config = build.llvm_config(target); + let llvm_version = output(Command::new(&llvm_config).arg("--version")); + cmd.arg("--llvm-version").arg(llvm_version); cmd.args(&build.flags.args); @@ -158,7 +161,6 @@ pub fn compiletest(build: &Build, // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. if suite == "run-make" { - let llvm_config = build.llvm_config(target); let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); cmd.arg("--cc").arg(build.cc(target)) diff --git a/src/test/run-pass/issue-36023.rs b/src/test/run-pass/issue-36023.rs index f6c03b384f23d..53a8a403b6410 100644 --- a/src/test/run-pass/issue-36023.rs +++ b/src/test/run-pass/issue-36023.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// min-llvm-version 3.9 + use std::ops::Deref; fn main() { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6090cb4f52725..5d522736089ea 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -152,6 +152,9 @@ pub struct Config { // Version of LLDB pub lldb_version: Option, + // Version of LLVM + pub llvm_version: Option, + // Path to the android tools pub android_cross_path: PathBuf, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index af33d76be1b0d..899a366a4bb74 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -44,7 +44,9 @@ impl EarlyProps { (config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) || (config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) || - ignore_gdb(config, ln) || ignore_lldb(config, ln); + ignore_gdb(config, ln) || + ignore_lldb(config, ln) || + ignore_llvm(config, ln); props.should_fail = props.should_fail || parse_name_directive(ln, "should-fail"); }); @@ -115,6 +117,24 @@ impl EarlyProps { false } } + + fn ignore_llvm(config: &Config, line: &str) -> bool { + if let Some(ref actual_version) = config.llvm_version { + if line.contains("min-llvm-version") { + let min_version = line.trim() + .split(' ') + .last() + .expect("Malformed llvm version directive"); + // Ignore if actual version is smaller the minimum required + // version + &actual_version[..] < min_version + } else { + false + } + } else { + false + } + } } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 90641b5c476d7..4afeb3613319b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -99,6 +99,7 @@ pub fn parse_config(args: Vec ) -> Config { optopt("", "host", "the host to build for", "HOST"), optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"), optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), + optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"), optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), optopt("", "adb-path", "path to the android debugger", "PATH"), optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"), @@ -170,6 +171,7 @@ pub fn parse_config(args: Vec ) -> Config { host: opt_str2(matches.opt_str("host")), gdb_version: extract_gdb_version(matches.opt_str("gdb-version")), lldb_version: extract_lldb_version(matches.opt_str("lldb-version")), + llvm_version: matches.opt_str("llvm-version"), android_cross_path: opt_path(matches, "android-cross-path"), adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: format!("{}/{}", From 90ce504c1c3dc014ca8e0aa91e21c46569a9d4ab Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 29 Aug 2016 05:29:01 +0000 Subject: [PATCH 474/768] Address comments. --- src/librustc_resolve/build_reduced_graph.rs | 8 ++--- src/librustc_resolve/lib.rs | 34 ++++++++++++--------- src/librustc_resolve/resolve_imports.rs | 1 + src/test/run-pass/imports.rs | 2 ++ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0c7c970371877..3e9b37f0a95a7 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -32,7 +32,7 @@ use syntax::ast::Name; use syntax::attr; use syntax::parse::token; -use syntax::ast::{Block, Crate, DUMMY_NODE_ID}; +use syntax::ast::{Block, Crate}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; @@ -208,7 +208,7 @@ impl<'b> Resolver<'b> { ItemKind::Mod(..) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), item.id); + let module = self.new_module(parent_link, Some(def), Some(item.id)); module.no_implicit_prelude.set({ parent.no_implicit_prelude.get() || attr::contains_name(&item.attrs, "no_implicit_prelude") @@ -398,7 +398,7 @@ impl<'b> Resolver<'b> { debug!("(building reduced graph for external crate) building module {} {:?}", name, vis); let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); + let module = self.new_module(parent_link, Some(def), None); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::Variant(_, variant_id) => { @@ -440,7 +440,7 @@ impl<'b> Resolver<'b> { } let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); + let module = self.new_module(parent_link, Some(def), None); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::TyAlias(..) | Def::AssociatedTy(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0fe7f9ed21547..1224c694a4e6e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,7 +54,7 @@ use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; -use syntax::ast::{CRATE_NODE_ID, DUMMY_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; +use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -765,7 +765,7 @@ pub struct ModuleS<'a> { def: Option, // The node id of the closest normal module (`mod`) ancestor (including this module). - normal_ancestor_id: NodeId, + normal_ancestor_id: Option, // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). @@ -790,7 +790,8 @@ pub struct ModuleS<'a> { pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { - fn new(parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) -> Self { + fn new(parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: Option) + -> Self { ModuleS { parent_link: parent_link, def: def, @@ -801,7 +802,7 @@ impl<'a> ModuleS<'a> { glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), traits: RefCell::new(None), - populated: Cell::new(normal_ancestor_id != DUMMY_NODE_ID), + populated: Cell::new(normal_ancestor_id.is_some()), } } @@ -1104,7 +1105,7 @@ impl<'a> ty::NodeIdTree for Resolver<'a> { fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool { while node != ancestor { node = match self.module_map[&node].parent() { - Some(parent) => parent.normal_ancestor_id, + Some(parent) => parent.normal_ancestor_id.unwrap(), None => return false, } } @@ -1168,7 +1169,8 @@ impl<'a> Resolver<'a> { pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); - let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), CRATE_NODE_ID); + let graph_root = + ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), Some(CRATE_NODE_ID)); let graph_root = arenas.alloc_module(graph_root); let mut module_map = NodeMap(); module_map.insert(CRATE_NODE_ID, graph_root); @@ -1247,14 +1249,17 @@ impl<'a> Resolver<'a> { self.report_errors(); } - fn new_module(&self, parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) + fn new_module(&self, + parent_link: ParentLink<'a>, + def: Option, + normal_ancestor_id: Option) -> Module<'a> { self.arenas.alloc_module(ModuleS::new(parent_link, def, normal_ancestor_id)) } fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), local_node_id); + let mut module = ModuleS::new(parent_link, Some(def), Some(local_node_id)); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } @@ -1530,14 +1535,15 @@ impl<'a> Resolver<'a> { _ => return Success(NoPrefixFound), }; - let mut containing_module = self.module_map[&self.current_module.normal_ancestor_id]; + let mut containing_module = + self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; // Now loop through all the `super`s we find. while i < module_path.len() && "super" == module_path[i].as_str() { debug!("(resolving module prefix) resolving `super` at {}", module_to_string(&containing_module)); if let Some(parent) = containing_module.parent() { - containing_module = self.module_map[&parent.normal_ancestor_id]; + containing_module = self.module_map[&parent.normal_ancestor_id.unwrap()]; i += 1; } else { let msg = "There are too many initial `super`s.".into(); @@ -3260,7 +3266,7 @@ impl<'a> Resolver<'a> { ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID), ast::Visibility::Restricted { ref path, id } => (path, id), ast::Visibility::Inherited => { - return ty::Visibility::Restricted(self.current_module.normal_ancestor_id); + return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap()); } }; @@ -3269,7 +3275,7 @@ impl<'a> Resolver<'a> { let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { Success(module) => { path_resolution = PathResolution::new(module.def.unwrap()); - ty::Visibility::Restricted(module.normal_ancestor_id) + ty::Visibility::Restricted(module.normal_ancestor_id.unwrap()) } Indeterminate => unreachable!(), Failed(err) => { @@ -3288,11 +3294,11 @@ impl<'a> Resolver<'a> { } fn is_accessible(&self, vis: ty::Visibility) -> bool { - vis.is_accessible_from(self.current_module.normal_ancestor_id, self) + vis.is_accessible_from(self.current_module.normal_ancestor_id.unwrap(), self) } fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { - vis.is_accessible_from(module.normal_ancestor_id, self) + vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self) } fn report_errors(&self) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c8982d95d4e00..875d6745f6b2e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -55,6 +55,7 @@ pub enum ImportDirectiveSubclass<'a> { GlobImport { is_prelude: bool, max_vis: Cell, // The visibility of the greatest reexport. + // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors. }, } diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index 195b99c9788e8..9851dfe0262f8 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-pretty : (#23623) problems when ending with // comments + #![feature(item_like_imports)] #![allow(unused)] From 7f95bb0dbd70e838d7cc12520135b08853c8b192 Mon Sep 17 00:00:00 2001 From: Eugene R Gonzalez Date: Thu, 1 Sep 2016 22:35:25 -0400 Subject: [PATCH 475/768] Fixed E0529's label and unit test --- src/librustc_typeck/check/_match.rs | 5 ++++- src/test/compile-fail/E0529.rs | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 225468cb9f40c..1027a3207f0af 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -270,7 +270,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } } - err.emit(); + + err.span_label( pat.span, + &format!("pattern cannot match with input type `{}`", expected_ty) + ).emit(); } (tcx.types.err, tcx.types.err) } diff --git a/src/test/compile-fail/E0529.rs b/src/test/compile-fail/E0529.rs index 488fe7c7763ae..18d3e68816aad 100644 --- a/src/test/compile-fail/E0529.rs +++ b/src/test/compile-fail/E0529.rs @@ -13,7 +13,9 @@ fn main() { let r: f32 = 1.0; match r { - [a, b] => { //~ ERROR E0529 + [a, b] => { + //~^ ERROR E0529 + //~| NOTE pattern cannot match with input type `f32` } } } From cd8f0aa7f228fa37084817baba8aba1d96387d89 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 01:52:32 -0700 Subject: [PATCH 476/768] Remove --{enable|disable}-orbit from configure. Fixes #35956. --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 44fb3d368d2c7..c6b6e4da5291d 100755 --- a/configure +++ b/configure @@ -609,7 +609,6 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt rustbuild 0 "use the rust and cargo based build system" -opt orbit 1 "get MIR where it belongs - everywhere; most importantly, in orbit" opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" From ed5e5df596aff90b4147869e3464330f7833f81e Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Fri, 2 Sep 2016 11:44:46 +0200 Subject: [PATCH 477/768] E0493: showing a label where the destructor is defined. --- src/librustc_mir/transform/qualify_consts.rs | 29 ++++++++++++++++++++ src/test/compile-fail/E0493.rs | 9 ++++++ 2 files changed, 38 insertions(+) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a6f6faf246969..14a432cbb895b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -18,6 +18,7 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::dep_graph::DepNode; use rustc::hir; +use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; @@ -258,12 +259,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { "in Nightly builds, add `#![feature(drop_types_in_const)]` \ to the crate attributes to enable"); } else { + self.find_drop_implementation_method_span() + .map(|span| err.span_label(span, &format!("destructor defined here"))); + err.span_label(self.span, &format!("constants cannot have destructors")); } err.emit(); } + fn find_drop_implementation_method_span(&self) -> Option { + self.tcx.lang_items + .drop_trait() + .and_then(|drop_trait_id| { + let mut span = None; + + self.tcx + .lookup_trait_def(drop_trait_id) + .for_each_relevant_impl(self.tcx, self.mir.return_ty, |impl_did| { + self.tcx.map + .as_local_node_id(impl_did) + .and_then(|impl_node_id| self.tcx.map.find(impl_node_id)) + .map(|node| { + if let hir_map::NodeItem(item) = node { + if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node { + span = methods.first().map(|method| method.span); + } + } + }); + }); + + span + }) + } + /// Check if an Lvalue with the current qualifications could /// be consumed, by either an operand or a Deref projection. fn try_consume(&mut self) -> bool { diff --git a/src/test/compile-fail/E0493.rs b/src/test/compile-fail/E0493.rs index d5b29a628f0bd..e06da5ca7c55c 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/compile-fail/E0493.rs @@ -14,6 +14,15 @@ struct Foo { impl Drop for Foo { fn drop(&mut self) {} + //~^ NOTE destructor defined here +} + +struct Bar { + a: u32 +} + +impl Drop for Bar { + fn drop(&mut self) {} } const F : Foo = Foo { a : 0 }; From 3a96fe32753f0308002e18d165f52d54e5ac64cb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 31 Aug 2016 19:10:24 -0400 Subject: [PATCH 478/768] Transition Travis CI to use rustbuild. --- .travis.yml | 4 ++-- src/bootstrap/compile.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0abd858d8228b..c5d8a94f39b05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,9 +15,9 @@ before_install: script: - docker run -v `pwd`:/build rust sh -c " - ./configure --llvm-root=/usr/lib/llvm-3.7 && + ./configure --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 && make tidy && - make check-notidy -j4 + make check -j4 " # Real testing happens on http://buildbot.rust-lang.org/ diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 155848901cdb4..302ac68460c69 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -203,6 +203,10 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("LLVM_RUSTLLVM", "1"); } cargo.env("LLVM_CONFIG", build.llvm_config(target)); + let target_config = build.config.target_config.get(target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } if build.config.llvm_static_stdcpp { cargo.env("LLVM_STATIC_STDCPP", compiler_file(build.cxx(target), "libstdc++.a")); From b778f7fa0192ac6863f3ce0ab49d9c4001bf5503 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Wed, 31 Aug 2016 16:02:55 -0700 Subject: [PATCH 479/768] core: add likely and unlikely intrinsics --- src/libcore/intrinsics.rs | 14 +++++++++ src/librustc_trans/intrinsic.rs | 8 +++++ src/librustc_typeck/check/intrinsic.rs | 2 ++ src/test/codegen/likely.rs | 41 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 src/test/codegen/likely.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8271b85b01a3b..619656f4d713c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -194,6 +194,20 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. pub fn assume(b: bool); + #[cfg(not(stage0))] + /// Hints to the compiler that branch condition is likely to be true. + /// Returns the value passed to it. + /// + /// Any use other than with `if` statements will probably not have an effect. + pub fn likely(b: bool) -> bool; + + #[cfg(not(stage0))] + /// Hints to the compiler that branch condition is likely to be false. + /// Returns the value passed to it. + /// + /// Any use other than with `if` statements will probably not have an effect. + pub fn unlikely(b: bool) -> bool; + /// Executes a breakpoint trap, for inspection by a debugger. pub fn breakpoint(); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 8bef7584db9e2..1ee5db7eafc59 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -136,6 +136,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (Some(llfn), _) => { Call(bcx, llfn, &llargs, call_debug_location) } + (_, "likely") => { + let expect = ccx.get_intrinsic(&("llvm.expect.i1")); + Call(bcx, expect, &[llargs[0], C_bool(ccx, true)], call_debug_location) + } + (_, "unlikely") => { + let expect = ccx.get_intrinsic(&("llvm.expect.i1")); + Call(bcx, expect, &[llargs[0], C_bool(ccx, false)], call_debug_location) + } (_, "try") => { bcx = try_intrinsic(bcx, llargs[0], llargs[1], llargs[2], llresult, call_debug_location); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index bde7f20f5e6e6..ea4b3e924b3b3 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -285,6 +285,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), + "likely" => (0, vec![tcx.types.bool], tcx.types.bool), + "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool), "discriminant_value" => (1, vec![ tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), diff --git a/src/test/codegen/likely.rs b/src/test/codegen/likely.rs new file mode 100644 index 0000000000000..acaec0350bfbd --- /dev/null +++ b/src/test/codegen/likely.rs @@ -0,0 +1,41 @@ +// 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. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::{likely,unlikely}; + +#[no_mangle] +pub fn check_likely(x: i32, y: i32) -> Option { + unsafe { + // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true) + if likely(x == y) { + None + } else { + Some(x + y) + } + } +} + +#[no_mangle] +pub fn check_unlikely(x: i32, y: i32) -> Option { + unsafe { + // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false) + if unlikely(x == y) { + None + } else { + Some(x + y) + } + } +} + From 059094f3f264a683e624ae57b475264b5ce8511c Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Fri, 2 Sep 2016 19:55:14 +0200 Subject: [PATCH 480/768] Moved test on E0493 from compile-fail to ui. --- src/test/{compile-fail => ui/span}/E0493.rs | 3 --- src/test/ui/span/E0493.stderr | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) rename src/test/{compile-fail => ui/span}/E0493.rs (81%) create mode 100644 src/test/ui/span/E0493.stderr diff --git a/src/test/compile-fail/E0493.rs b/src/test/ui/span/E0493.rs similarity index 81% rename from src/test/compile-fail/E0493.rs rename to src/test/ui/span/E0493.rs index e06da5ca7c55c..ea4526b70f6a8 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/ui/span/E0493.rs @@ -14,7 +14,6 @@ struct Foo { impl Drop for Foo { fn drop(&mut self) {} - //~^ NOTE destructor defined here } struct Bar { @@ -26,8 +25,6 @@ impl Drop for Bar { } const F : Foo = Foo { a : 0 }; -//~^ ERROR constants are not allowed to have destructors [E0493] -//~| NOTE constants cannot have destructors fn main() { } diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr new file mode 100644 index 0000000000000..afcc9a240eb4e --- /dev/null +++ b/src/test/ui/span/E0493.stderr @@ -0,0 +1,11 @@ +error[E0493]: constants are not allowed to have destructors + --> $DIR/E0493.rs:27:17 + | +16 | fn drop(&mut self) {} + | --------------------- destructor defined here +... +27 | const F : Foo = Foo { a : 0 }; + | ^^^^^^^^^^^^^ constants cannot have destructors + +error: aborting due to previous error + From f18c99072e6b9ec0075d913ea6454f0c5e75881c Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 16 Aug 2016 18:41:27 -0700 Subject: [PATCH 481/768] Add tests for #29859 --- src/test/compile-fail/issue-29859-2.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/issue-29859.rs | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/compile-fail/issue-29859-2.rs create mode 100644 src/test/compile-fail/issue-29859.rs diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/issue-29859-2.rs new file mode 100644 index 0000000000000..c0e50185f939d --- /dev/null +++ b/src/test/compile-fail/issue-29859-2.rs @@ -0,0 +1,25 @@ +// 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. + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); //~ ERROR E0277 + println!("{:?} {:?}", a, b); +} diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/issue-29859.rs new file mode 100644 index 0000000000000..c0e50185f939d --- /dev/null +++ b/src/test/compile-fail/issue-29859.rs @@ -0,0 +1,25 @@ +// 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. + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); //~ ERROR E0277 + println!("{:?} {:?}", a, b); +} From 352fac95ad5305bf8b0e482b8255b2b0057adf09 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 16 Aug 2016 22:48:09 -0700 Subject: [PATCH 482/768] Reject certain auto trait declarations Fixes #29859 --- src/librustc/ty/mod.rs | 10 +++++ src/librustc_typeck/check/wfcheck.rs | 53 ++++++++++++++++++++++++++ src/librustc_typeck/diagnostics.rs | 2 + src/test/compile-fail/issue-29859-2.rs | 15 +------- src/test/compile-fail/issue-29859.rs | 6 +-- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e9c01f5bad66e..414e7b71f7cf2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -762,6 +762,16 @@ pub struct GenericPredicates<'tcx> { } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { + pub fn empty() -> GenericPredicates<'tcx> { + GenericPredicates { + predicates: VecPerParamSpace::empty(), + } + } + + pub fn is_empty(&self) -> bool { + self.predicates.is_empty() + } + pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { let mut instantiated = InstantiatedPredicates::empty(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 435442bd30a65..0117dfa673007 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -251,6 +251,36 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } + fn check_auto_trait(&mut self, + trait_def_id: DefId, + span: Span) + { + let predicates = self.tcx().lookup_predicates(trait_def_id); + + // If we must exclude the Self : Trait predicate contained by all + // traits. + let no_refl_predicates : Vec<_> = + predicates.predicates.iter().filter(|predicate| { + match *predicate { + &ty::Predicate::Trait(ref poly_trait_ref) => + poly_trait_ref.def_id() != trait_def_id, + _ => true, + } + }).collect(); + + let trait_def = self.tcx().lookup_trait_def(trait_def_id); + + // We use an if-else here, since the generics will also trigger + // an extraneous error message when we find predicates like + // `T : Sized` for a trait like: `trait Magic`. + if !trait_def.generics.types.get_slice(ParamSpace::TypeSpace).is_empty() { + error_566(self.ccx, span); + } else if !no_refl_predicates.is_empty() { + error_565(self.ccx, span); + } + + } + fn check_trait(&mut self, item: &hir::Item, items: &[hir::TraitItem]) @@ -258,9 +288,18 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let trait_def_id = self.tcx().map.local_def_id(item.id); if self.tcx().trait_has_default_impl(trait_def_id) { + // We want to both ensure: + // 1) that there are no items contained within + // the trait defintion + // + // 2) that the definition doesn't violate the no-super trait rule + // for auto traits. + if !items.is_empty() { error_380(self.ccx, item.span); } + + self.check_auto_trait(trait_def_id, item.span); } self.for_item(item).with_fcx(|fcx, this| { @@ -272,6 +311,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } + + fn check_item_fn(&mut self, item: &hir::Item, body: &hir::Block) @@ -637,6 +678,18 @@ fn error_380(ccx: &CrateCtxt, span: Span) { Trait for ..`) must have no methods or associated items") } +fn error_565(ccx: &CrateCtxt, span: Span) { + span_err!(ccx.tcx.sess, span, E0565, + "traits with default impls (`e.g. unsafe impl \ + Trait for ..`) can not have predicates") +} + +fn error_566(ccx: &CrateCtxt, span: Span) { + span_err!(ccx.tcx.sess, span, E0566, + "traits with default impls (`e.g. unsafe impl \ + Trait for ..`) can not have type parameters") +} + fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!(ccx.tcx.sess, span, E0392, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 3f1374db36936..7b7b4d2aa00fa 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4072,4 +4072,6 @@ register_diagnostics! { E0563, // cannot determine a type for this `impl Trait`: {} E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` + E0565, // auto-traits can not have predicates, + E0566, // auto traits can not have type parameters } diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/issue-29859-2.rs index c0e50185f939d..258aafb15baf4 100644 --- a/src/test/compile-fail/issue-29859-2.rs +++ b/src/test/compile-fail/issue-29859-2.rs @@ -10,16 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} -impl Magic for .. {} -impl Magic for T {} - -fn copy(x: T) -> (T, T) { (x, x) } - -#[derive(Debug)] -struct NoClone; - -fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 - println!("{:?} {:?}", a, b); -} +trait Magic {} //~ E0566 +impl Magic for .. {} diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/issue-29859.rs index c0e50185f939d..3419e66af1393 100644 --- a/src/test/compile-fail/issue-29859.rs +++ b/src/test/compile-fail/issue-29859.rs @@ -10,8 +10,8 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} -impl Magic for .. {} +trait Magic: Copy {} //~ ERROR E0565 +impl Magic for .. {} impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } @@ -20,6 +20,6 @@ fn copy(x: T) -> (T, T) { (x, x) } struct NoClone; fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 + let (a, b) = copy(NoClone); println!("{:?} {:?}", a, b); } From 90d1a535510dfa098c908a76234d7b0db72eadf8 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 18 Aug 2016 11:29:35 -0700 Subject: [PATCH 483/768] Address feedback, and remove invalid tests --- src/librustc/ty/mod.rs | 10 -- src/librustc_typeck/check/wfcheck.rs | 95 +++++++++++-------- ...its-inductive-overflow-auto-normal-auto.rs | 32 ------- ...its-inductive-overflow-supertrait-oibit.rs | 4 +- ... => typeck-auto-trait-no-supertraits-2.rs} | 2 +- .../typeck-auto-trait-no-supertraits.rs | 49 ++++++++++ ....rs => typeck-auto-trait-no-typeparams.rs} | 2 +- .../typeck-default-trait-impl-superregion.rs | 27 ------ .../typeck-default-trait-impl-supertrait.rs | 29 ------ ...default-trait-impl-trait-where-clause-2.rs | 36 ------- ...k-default-trait-impl-trait-where-clause.rs | 36 ------- 11 files changed, 108 insertions(+), 214 deletions(-) delete mode 100644 src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs rename src/test/compile-fail/{issue-29859.rs => typeck-auto-trait-no-supertraits-2.rs} (91%) create mode 100644 src/test/compile-fail/typeck-auto-trait-no-supertraits.rs rename src/test/compile-fail/{issue-29859-2.rs => typeck-auto-trait-no-typeparams.rs} (93%) delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-superregion.rs delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-supertrait.rs delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 414e7b71f7cf2..e9c01f5bad66e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -762,16 +762,6 @@ pub struct GenericPredicates<'tcx> { } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { - pub fn empty() -> GenericPredicates<'tcx> { - GenericPredicates { - predicates: VecPerParamSpace::empty(), - } - } - - pub fn is_empty(&self) -> bool { - self.predicates.is_empty() - } - pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { let mut instantiated = InstantiatedPredicates::empty(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 0117dfa673007..4576fc9ffdc79 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -252,33 +252,71 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } fn check_auto_trait(&mut self, - trait_def_id: DefId, - span: Span) + trait_def_id: DefId, + items: &[hir::TraitItem], + span: Span) { + // We want to ensure: + // + // 1) that there are no items contained within + // the trait defintion + // + // 2) that the definition doesn't violate the no-super trait rule + // for auto traits. + // + // 3) that the trait definition does not have any type parameters + let predicates = self.tcx().lookup_predicates(trait_def_id); - // If we must exclude the Self : Trait predicate contained by all + // We must exclude the Self : Trait predicate contained by all // traits. - let no_refl_predicates : Vec<_> = - predicates.predicates.iter().filter(|predicate| { - match *predicate { - &ty::Predicate::Trait(ref poly_trait_ref) => - poly_trait_ref.def_id() != trait_def_id, + let has_predicates = + predicates.predicates.iter().any(|predicate| { + match predicate { + &ty::Predicate::Trait(ref poly_trait_ref) => { + let self_ty = poly_trait_ref.0.self_ty(); + !(self_ty.is_self() && poly_trait_ref.def_id() == trait_def_id) + }, _ => true, - } - }).collect(); + } + }); let trait_def = self.tcx().lookup_trait_def(trait_def_id); + let has_ty_params = + trait_def.generics + .types + .len() > 1; + // We use an if-else here, since the generics will also trigger // an extraneous error message when we find predicates like // `T : Sized` for a trait like: `trait Magic`. - if !trait_def.generics.types.get_slice(ParamSpace::TypeSpace).is_empty() { - error_566(self.ccx, span); - } else if !no_refl_predicates.is_empty() { - error_565(self.ccx, span); + // + // We also put the check on the number of items here, + // as it seems confusing to report an error about + // extraneous predicates created by things like + // an associated type inside the trait. + + if !items.is_empty() { + error_380(self.ccx, span); + } else if has_ty_params { + span_err!(self.tcx().sess, span, E0566, + "traits with auto impls (`e.g. unsafe impl \ + Trait for ..`) can not have type parameters") + } else if has_predicates { + span_err!(self.tcx().sess, span, E0565, + "traits with auto impls (`e.g. unsafe impl \ + Trait for ..`) can not have predicates") } + // Finally if either of the above conditions apply we should add a note + // indicating that this error is the result of a recent soundness fix. + if has_ty_params || has_predicates { + self.tcx().sess.span_note_without_error( + span, + "the new auto trait rules are the result of a \ + recent soundness fix; see #29859 for more details") + } } fn check_trait(&mut self, @@ -287,19 +325,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { let trait_def_id = self.tcx().map.local_def_id(item.id); + // TODO: in a second pass, globally rename to auto_trait, + // from default_impl. if self.tcx().trait_has_default_impl(trait_def_id) { - // We want to both ensure: - // 1) that there are no items contained within - // the trait defintion - // - // 2) that the definition doesn't violate the no-super trait rule - // for auto traits. - - if !items.is_empty() { - error_380(self.ccx, item.span); - } - - self.check_auto_trait(trait_def_id, item.span); + self.check_auto_trait(trait_def_id, items, item.span); } self.for_item(item).with_fcx(|fcx, this| { @@ -311,8 +340,6 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } - - fn check_item_fn(&mut self, item: &hir::Item, body: &hir::Block) @@ -678,18 +705,6 @@ fn error_380(ccx: &CrateCtxt, span: Span) { Trait for ..`) must have no methods or associated items") } -fn error_565(ccx: &CrateCtxt, span: Span) { - span_err!(ccx.tcx.sess, span, E0565, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) can not have predicates") -} - -fn error_566(ccx: &CrateCtxt, span: Span) { - span_err!(ccx.tcx.sess, span, E0566, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) can not have type parameters") -} - fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!(ccx.tcx.sess, span, E0392, diff --git a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs b/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs deleted file mode 100644 index cdf4b405fd83e..0000000000000 --- a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs +++ /dev/null @@ -1,32 +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. - -// Test for a potential corner case in current impl where you have an -// auto trait (Magic1) that depends on a normal trait (Magic2) which -// in turn depends on the auto trait (Magic1). This was incorrectly -// being considered coinductive, but because of the normal trait -// interfering, it should not be. - -#![feature(optin_builtin_traits)] - -trait Magic1: Magic2 { } -impl Magic1 for .. {} - -trait Magic2 { } -impl Magic2 for T { } - -fn is_magic1() { } - -#[derive(Debug)] -struct NoClone; - -fn main() { - is_magic1::(); //~ ERROR E0275 -} diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index ec8db996600d1..168148b92fe44 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -14,7 +14,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} +trait Magic: Copy {} //~ ERROR E0565 impl Magic for .. {} fn copy(x: T) -> (T, T) { (x, x) } @@ -23,6 +23,6 @@ fn copy(x: T) -> (T, T) { (x, x) } struct NoClone; fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 + let (a, b) = copy(NoClone); println!("{:?} {:?}", a, b); } diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs similarity index 91% rename from src/test/compile-fail/issue-29859.rs rename to src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index 3419e66af1393..60da647f68240 100644 --- a/src/test/compile-fail/issue-29859.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 +trait Magic : Sized where Option : Magic {} //~ ERROR E0565 impl Magic for .. {} impl Magic for T {} diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs new file mode 100644 index 0000000000000..177d594da18a0 --- /dev/null +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test is for #29859, we need to ensure auto traits, +// (also known previously as default traits), do not have +// supertraits. Since the compiler synthesizes these +// instances on demand, we are essentially enabling +// users to write axioms if we view trait selection, +// as a proof system. +// +// For example the below test allows us to add the rule: +// forall (T : Type), T : Copy +// +// Providing a copy instance for *any* type, which +// is most definitely unsound. Imagine copying a +// type that contains a mutable reference, enabling +// mutable aliasing. +// +// You can imagine an even more dangerous test, +// which currently compiles on nightly. +// +// fn main() { +// let mut i = 10; +// let (a, b) = copy(&mut i); +// println!("{:?} {:?}", a, b); +// } + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} //~ ERROR E0565 +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); +} diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs similarity index 93% rename from src/test/compile-fail/issue-29859-2.rs rename to src/test/compile-fail/typeck-auto-trait-no-typeparams.rs index 258aafb15baf4..f2841a413db9e 100644 --- a/src/test/compile-fail/issue-29859-2.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -10,5 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic {} //~ E0566 +trait Magic {} //~ ERROR E0566 impl Magic for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs b/src/test/compile-fail/typeck-default-trait-impl-superregion.rs deleted file mode 100644 index aa918119fbcee..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs +++ /dev/null @@ -1,27 +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. - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait MyTrait : 'static {} - -impl MyTrait for .. {} - -fn foo() { } - -fn bar<'a>() { - foo::<&'a ()>(); //~ ERROR does not fulfill the required lifetime -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs deleted file mode 100644 index 0b071a9acd092..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs +++ /dev/null @@ -1,29 +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. - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait : NotImplemented {} - -impl MyTrait for .. {} - -fn foo() { bar::() } - -fn bar() { } - -fn main() { - foo::(); //~ ERROR `i32: NotImplemented` is not satisfied - bar::(); //~ ERROR `i64: NotImplemented` is not satisfied -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs deleted file mode 100644 index 3085f45a83dd1..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs +++ /dev/null @@ -1,36 +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. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn bar() { } - -fn test() { - bar::>(); - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs deleted file mode 100644 index 47e87c09d12b1..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs +++ /dev/null @@ -1,36 +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. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn foo() { - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied - // This should probably typecheck. This is #20671. -} - -fn bar() { } - -fn main() { -} From ed5843bcc64c156f69b05c1cf2c8cdf4674e262d Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 18 Aug 2016 11:47:33 -0700 Subject: [PATCH 484/768] Address feedback on secondary changes --- src/librustc_typeck/check/wfcheck.rs | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4576fc9ffdc79..6e39e33c9a8d5 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -296,26 +296,28 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // as it seems confusing to report an error about // extraneous predicates created by things like // an associated type inside the trait. - + let mut err = None; if !items.is_empty() { error_380(self.ccx, span); } else if has_ty_params { - span_err!(self.tcx().sess, span, E0566, - "traits with auto impls (`e.g. unsafe impl \ - Trait for ..`) can not have type parameters") + err = Some(struct_span_err!(self.tcx().sess, span, E0566, + "traits with auto impls (`e.g. impl \ + Trait for ..`) can not have type parameters")); } else if has_predicates { - span_err!(self.tcx().sess, span, E0565, - "traits with auto impls (`e.g. unsafe impl \ - Trait for ..`) can not have predicates") + err = Some(struct_span_err!(self.tcx().sess, span, E0565, + "traits with auto impls (`e.g. impl \ + Trait for ..`) cannot have predicates")); } // Finally if either of the above conditions apply we should add a note // indicating that this error is the result of a recent soundness fix. - if has_ty_params || has_predicates { - self.tcx().sess.span_note_without_error( - span, - "the new auto trait rules are the result of a \ - recent soundness fix; see #29859 for more details") + match err { + None => {}, + Some(mut e) => { + e.note("the new auto trait rules are the result of a \ + recent soundness fix; see #29859 for more details"); + e.emit(); + } } } @@ -325,8 +327,6 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { let trait_def_id = self.tcx().map.local_def_id(item.id); - // TODO: in a second pass, globally rename to auto_trait, - // from default_impl. if self.tcx().trait_has_default_impl(trait_def_id) { self.check_auto_trait(trait_def_id, items, item.span); } @@ -701,7 +701,7 @@ fn error_192(ccx: &CrateCtxt, span: Span) { fn error_380(ccx: &CrateCtxt, span: Span) { span_err!(ccx.tcx.sess, span, E0380, - "traits with default impls (`e.g. unsafe impl \ + "traits with default impls (`e.g. impl \ Trait for ..`) must have no methods or associated items") } From 6eb06e67708614763932c17de5d08a0c1818ce05 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 18 Aug 2016 12:46:20 -0700 Subject: [PATCH 485/768] Forget to update tests to use new error message --- src/test/compile-fail/issue-23080-2.rs | 2 +- src/test/compile-fail/issue-23080.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index b77230a8b340d..9d20c17674bc3 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -13,7 +13,7 @@ #![feature(optin_builtin_traits)] unsafe trait Trait { -//~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items +//~^ ERROR E0380 type Output; } diff --git a/src/test/compile-fail/issue-23080.rs b/src/test/compile-fail/issue-23080.rs index 99373a69697ae..2e8cba87be515 100644 --- a/src/test/compile-fail/issue-23080.rs +++ b/src/test/compile-fail/issue-23080.rs @@ -13,7 +13,7 @@ #![feature(optin_builtin_traits)] unsafe trait Trait { -//~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items +//~^ ERROR E0380 fn method(&self) { println!("Hello"); } From 9510add6a3148f753776d6f6ac324690dba4a5d5 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 29 Aug 2016 01:54:10 -0700 Subject: [PATCH 486/768] Remove illegal bound from doc test --- src/test/rustdoc/auxiliary/rustdoc-default-impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs index c2ff7a0054f19..52bd386ba595b 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs @@ -14,7 +14,7 @@ pub mod bar { use std::marker; - pub trait Bar: 'static {} + pub trait Bar {} impl Bar for .. {} From eb1c7161dd79b55e022cd0c661f9018d406b3fe4 Mon Sep 17 00:00:00 2001 From: johnthagen Date: Fri, 2 Sep 2016 15:32:13 -0400 Subject: [PATCH 487/768] Update supported Windows versions to match Getting Started page. --- src/doc/book/nightly-rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/nightly-rust.md b/src/doc/book/nightly-rust.md index b3be71038a992..25570cb5503c9 100644 --- a/src/doc/book/nightly-rust.md +++ b/src/doc/book/nightly-rust.md @@ -54,7 +54,7 @@ binary downloads][install-page]. Oh, we should also mention the officially supported platforms: -* Windows (7, 8, Server 2008 R2) +* Windows (7+) * Linux (2.6.18 or later, various distributions), x86 and x86-64 * OSX 10.7 (Lion) or greater, x86 and x86-64 From ecc6c39e876b69496bc88ef47ff3a339662346b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 22 Aug 2016 17:07:11 -0700 Subject: [PATCH 488/768] rustc: Implement custom derive (macros 1.1) This commit is an implementation of [RFC 1681] which adds support to the compiler for first-class user-define custom `#[derive]` modes with a far more stable API than plugins have today. [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md The main features added by this commit are: * A new `rustc-macro` crate-type. This crate type represents one which will provide custom `derive` implementations and perhaps eventually flower into the implementation of macros 2.0 as well. * A new `rustc_macro` crate in the standard distribution. This crate will provide the runtime interface between macro crates and the compiler. The API here is particularly conservative right now but has quite a bit of room to expand into any manner of APIs required by macro authors. * The ability to load new derive modes through the `#[macro_use]` annotations on other crates. All support added here is gated behind the `rustc_macro` feature gate, both for the library support (the `rustc_macro` crate) as well as the language features. There are a few minor differences from the implementation outlined in the RFC, such as the `rustc_macro` crate being available as a dylib and all symbols are `dlsym`'d directly instead of having a shim compiled. These should only affect the implementation, however, not the public interface. This commit also ended up touching a lot of code related to `#[derive]`, making a few notable changes: * Recognized derive attributes are no longer desugared to `derive_Foo`. Wasn't sure how to keep this behavior and *not* expose it to custom derive. * Derive attributes no longer have access to unstable features by default, they have to opt in on a granular level. * The `derive(Copy,Clone)` optimization is now done through another "obscure attribute" which is just intended to ferry along in the compiler that such an optimization is possible. The `derive(PartialEq,Eq)` optimization was also updated to do something similar. --- One part of this PR which needs to be improved before stabilizing are the errors and exact interfaces here. The error messages are relatively poor quality and there are surprising spects of this such as `#[derive(PartialEq, Eq, MyTrait)]` not working by default. The custom attributes added by the compiler end up becoming unstable again when going through a custom impl. Hopefully though this is enough to start allowing experimentation on crates.io! syntax-[breaking-change] --- mk/crates.mk | 10 +- src/librustc/middle/dependency_format.rs | 9 +- src/librustc/middle/reachable.rs | 3 +- src/librustc/middle/weak_lang_items.rs | 1 + src/librustc/session/config.rs | 6 + src/librustc/session/mod.rs | 8 + src/librustc/ty/context.rs | 5 + src/librustc_driver/derive_registrar.rs | 37 +++ src/librustc_driver/driver.rs | 18 ++ src/librustc_driver/lib.rs | 2 +- src/librustc_macro/Cargo.toml | 12 + src/librustc_macro/lib.rs | 169 ++++++++++ src/librustc_metadata/Cargo.toml | 4 +- src/librustc_metadata/common.rs | 2 + src/librustc_metadata/creader.rs | 204 ++++++++---- src/librustc_metadata/cstore.rs | 14 +- src/librustc_metadata/decoder.rs | 5 + src/librustc_metadata/encoder.rs | 13 +- src/librustc_metadata/lib.rs | 6 +- src/librustc_metadata/macro_import.rs | 101 +++++- src/librustc_plugin/registry.rs | 1 - src/librustc_trans/back/link.rs | 8 +- src/librustc_trans/back/linker.rs | 32 +- src/librustc_trans/back/symbol_names.rs | 5 + src/libsyntax/ext/base.rs | 33 +- src/libsyntax/ext/expand.rs | 11 +- src/libsyntax/feature_gate.rs | 24 +- src/libsyntax_ext/Cargo.toml | 3 +- src/libsyntax_ext/deriving/clone.rs | 17 +- src/libsyntax_ext/deriving/custom.rs | 97 ++++++ src/libsyntax_ext/deriving/mod.rs | 296 ++++++++++-------- src/libsyntax_ext/lib.rs | 5 + src/libsyntax_ext/rustc_macro_registrar.rs | 280 +++++++++++++++++ src/rustc/Cargo.lock | 10 + .../rustc-macro/append-impl.rs | 33 ++ .../rustc-macro/at-the-root.rs | 25 ++ .../rustc-macro/attribute.rs | 46 +++ .../rustc-macro/auxiliary/append-impl.rs | 31 ++ .../rustc-macro/auxiliary/derive-a-2.rs | 25 ++ .../rustc-macro/auxiliary/derive-a.rs | 25 ++ .../rustc-macro/auxiliary/derive-bad.rs | 26 ++ .../rustc-macro/auxiliary/derive-panic.rs | 25 ++ .../auxiliary/derive-unstable-2.rs | 29 ++ .../rustc-macro/auxiliary/derive-unstable.rs | 26 ++ .../rustc-macro/cannot-link.rs | 16 + .../rustc-macro/define-two.rs | 28 ++ .../rustc-macro/derive-bad.rs | 25 ++ .../rustc-macro/derive-still-gated.rs | 22 ++ .../rustc-macro/expand-to-unstable-2.rs | 25 ++ .../rustc-macro/expand-to-unstable.rs | 25 ++ .../rustc-macro/export-macro.rs | 19 ++ .../rustc-macro/exports.rs | 22 ++ .../rustc-macro/feature-gate-1.rs | 13 + .../rustc-macro/feature-gate-2.rs | 13 + .../rustc-macro/feature-gate-3.rs} | 13 +- .../rustc-macro/feature-gate-4.rs | 15 + .../rustc-macro/feature-gate-5.rs | 12 + .../rustc-macro/import.rs | 22 ++ .../rustc-macro/load-panic.rs | 23 ++ .../require-rustc-macro-crate-type.rs | 21 ++ .../rustc-macro/shadow-builtin.rs | 22 ++ .../rustc-macro/shadow.rs | 21 ++ .../rustc-macro/signature.rs | 24 ++ .../rustc-macro/two-crate-types-1.rs | 14 + .../rustc-macro/two-crate-types-2.rs | 12 + src/test/compile-fail/issue-32655.rs | 7 +- .../run-pass-fulldeps/rustc-macro/add-impl.rs | 25 ++ .../rustc-macro/auxiliary/add-impl.rs | 33 ++ .../rustc-macro/auxiliary/derive-a.rs | 27 ++ .../rustc-macro/auxiliary/derive-atob.rs | 26 ++ .../rustc-macro/auxiliary/derive-ctod.rs | 26 ++ .../auxiliary/derive-same-struct.rs | 32 ++ .../auxiliary/expand-with-a-macro.rs | 36 +++ .../rustc-macro/derive-same-struct.rs | 23 ++ .../rustc-macro/expand-with-a-macro.rs | 30 ++ .../run-pass-fulldeps/rustc-macro/load-two.rs | 30 ++ .../run-pass-fulldeps/rustc-macro/smoke.rs | 29 ++ ...ociated-types-normalize-unifield-struct.rs | 3 - .../builtin-superkinds-in-metadata.rs | 2 - src/test/run-pass/coherence-impl-in-fn.rs | 2 - src/test/run-pass/deriving-bounds.rs | 2 - src/test/run-pass/issue-20797.rs | 2 - src/test/run-pass/issue-2288.rs | 2 - .../sync-send-iterators-in-libcollections.rs | 2 - 84 files changed, 2211 insertions(+), 277 deletions(-) create mode 100644 src/librustc_driver/derive_registrar.rs create mode 100644 src/librustc_macro/Cargo.toml create mode 100644 src/librustc_macro/lib.rs create mode 100644 src/libsyntax_ext/deriving/custom.rs create mode 100644 src/libsyntax_ext/rustc_macro_registrar.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/attribute.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/define-two.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/exports.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs rename src/test/{run-pass/single-derive-attr-with-gate.rs => compile-fail-fulldeps/rustc-macro/feature-gate-3.rs} (68%) create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/import.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/shadow.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/signature.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/add-impl.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/load-two.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/smoke.rs diff --git a/mk/crates.mk b/mk/crates.mk index a915d07384f3c..06ad07de136b1 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental + rustc_const_eval rustc_const_math rustc_incremental rustc_macro HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -99,7 +99,7 @@ DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos -DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros +DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize @@ -118,11 +118,13 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_trans rustc_privacy rustc_lint rustc_plugin \ rustc_metadata syntax_ext proc_macro \ rustc_passes rustc_save_analysis rustc_const_eval \ - rustc_incremental syntax_pos rustc_errors + rustc_incremental syntax_pos rustc_errors rustc_macro DEPS_rustc_errors := log libc serialize syntax_pos DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags -DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math +DEPS_rustc_macro := std syntax +DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math \ + rustc_macro syntax_ext DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index cf6905ecf439a..7822fe2536f1f 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -139,8 +139,13 @@ fn calculate_type(sess: &session::Session, } } - // Everything else falls through below - config::CrateTypeExecutable | config::CrateTypeDylib => {}, + // Everything else falls through below. This will happen either with the + // `-C prefer-dynamic` or because we're a rustc-macro crate. Note that + // rustc-macro crates are required to be dylibs, and they're currently + // required to link to libsyntax as well. + config::CrateTypeExecutable | + config::CrateTypeDylib | + config::CrateTypeRustcMacro => {}, } let mut formats = FnvHashMap(); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index e29a7cf9d6846..1f9738556d925 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -138,7 +138,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Creates a new reachability computation context. fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { - *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib + *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || + *ty == config::CrateTypeRustcMacro }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 6fb1b16705fe4..c2f275e6deaf8 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { let needs_check = sess.crate_types.borrow().iter().any(|kind| { match *kind { config::CrateTypeDylib | + config::CrateTypeRustcMacro | config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b129..a2f926aa92c52 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -475,6 +475,7 @@ pub enum CrateType { CrateTypeRlib, CrateTypeStaticlib, CrateTypeCdylib, + CrateTypeRustcMacro, } #[derive(Clone, Hash)] @@ -962,6 +963,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { if sess.opts.debug_assertions { ret.push(attr::mk_word_item(InternedString::new("debug_assertions"))); } + if sess.opts.crate_types.contains(&CrateTypeRustcMacro) { + ret.push(attr::mk_word_item(InternedString::new("rustc_macro"))); + } return ret; } @@ -1547,6 +1551,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateTypeDylib, "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, + "rustc-macro" => CrateTypeRustcMacro, _ => { return Err(format!("unknown crate type: `{}`", part)); @@ -1635,6 +1640,7 @@ impl fmt::Display for CrateType { CrateTypeRlib => "rlib".fmt(f), CrateTypeStaticlib => "staticlib".fmt(f), CrateTypeCdylib => "cdylib".fmt(f), + CrateTypeRustcMacro => "rustc-macro".fmt(f), } } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 338c656379959..ee2837e7bf1ab 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -62,6 +62,7 @@ pub struct Session { pub entry_fn: RefCell>, pub entry_type: Cell>, pub plugin_registrar_fn: Cell>, + pub derive_registrar_fn: Cell>, pub default_sysroot: Option, // The name of the root source file of the crate, in the local file system. // The path is always expected to be absolute. `None` means that there is no @@ -314,6 +315,12 @@ impl Session { format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) } + pub fn generate_derive_registrar_symbol(&self, + svh: &Svh, + index: DefIndex) -> String { + format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize()) + } + pub fn sysroot<'a>(&'a self) -> &'a Path { match self.opts.maybe_sysroot { Some (ref sysroot) => sysroot, @@ -501,6 +508,7 @@ pub fn build_session_(sopts: config::Options, entry_fn: RefCell::new(None), entry_type: Cell::new(None), plugin_registrar_fn: Cell::new(None), + derive_registrar_fn: Cell::new(None), default_sysroot: default_sysroot, local_crate_source_file: local_crate_source_file, working_dir: env::current_dir().unwrap(), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e048e618e84d6..725bbf6adfd42 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -495,6 +495,10 @@ pub struct GlobalCtxt<'tcx> { /// Cache for layouts computed from types. pub layout_cache: RefCell, &'tcx Layout>>, + + /// Map from function to the `#[derive]` mode that it's defining. Only used + /// by `rustc-macro` crates. + pub derive_macros: RefCell>, } impl<'tcx> GlobalCtxt<'tcx> { @@ -756,6 +760,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { crate_name: token::intern_and_get_ident(crate_name), data_layout: data_layout, layout_cache: RefCell::new(FnvHashMap()), + derive_macros: RefCell::new(NodeMap()), }, f) } } diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs new file mode 100644 index 0000000000000..ea7621e16e7b7 --- /dev/null +++ b/src/librustc_driver/derive_registrar.rs @@ -0,0 +1,37 @@ +// 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. + +use rustc::dep_graph::DepNode; +use rustc::hir::intravisit::Visitor; +use rustc::hir::map::Map; +use rustc::hir; +use syntax::ast; +use syntax::attr; + +pub fn find(hir_map: &Map) -> Option { + let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); + let krate = hir_map.krate(); + + let mut finder = Finder { registrar: None }; + krate.visit_all_items(&mut finder); + finder.registrar +} + +struct Finder { + registrar: Option, +} + +impl<'v> Visitor<'v> for Finder { + fn visit_item(&mut self, item: &hir::Item) { + if attr::contains_name(&item.attrs, "rustc_derive_registrar") { + self.registrar = Some(item.id); + } + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b5..47a0399b63283 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -55,6 +55,8 @@ use syntax::util::node_count::NodeCounter; use syntax; use syntax_ext; +use derive_registrar; + #[derive(Clone)] pub struct Resolutions { pub def_map: DefMap, @@ -696,6 +698,18 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, sess.diagnostic()) }); + krate = time(time_passes, "maybe creating a macro crate", || { + let crate_types = sess.crate_types.borrow(); + let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro); + let num_crate_types = crate_types.len(); + syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess, + krate, + is_rustc_macro_crate, + num_crate_types, + sess.diagnostic(), + &sess.features.borrow()) + }); + let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas); @@ -838,6 +852,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || { plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) })); + sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); let region_map = time(time_passes, "region resolution", @@ -1171,6 +1186,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { Some(config::CrateTypeStaticlib) } + Some(ref n) if *n == "rustc-macro" => { + Some(config::CrateTypeRustcMacro) + } Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable), Some(_) => { session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index efadf1ff488df..6616e9579e818 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -107,7 +107,7 @@ pub mod test; pub mod driver; pub mod pretty; pub mod target_features; - +mod derive_registrar; const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; diff --git a/src/librustc_macro/Cargo.toml b/src/librustc_macro/Cargo.toml new file mode 100644 index 0000000000000..6b3ee21d9aceb --- /dev/null +++ b/src/librustc_macro/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_macro" +version = "0.0.0" + +[lib] +name = "rustc_macro" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +syntax = { path = "../libsyntax" } diff --git a/src/librustc_macro/lib.rs b/src/librustc_macro/lib.rs new file mode 100644 index 0000000000000..c2a2cc2ecd64d --- /dev/null +++ b/src/librustc_macro/lib.rs @@ -0,0 +1,169 @@ +// 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. + +//! A support library for macro authors when defining new macros. +//! +//! This library, provided by the standard distribution, provides the types +//! consumed in the interfaces of procedurally defined macro definitions. +//! Currently the primary use of this crate is to provide the ability to define +//! new custom derive modes through `#[rustc_macro_derive]`. +//! +//! Added recently as part of [RFC 1681] this crate is currently *unstable* and +//! requires the `#![feature(rustc_macro_lib)]` directive to use. Eventually, +//! though, it is intended for this crate to become stable to use (perhaps under +//! a different name). +//! +//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md +//! +//! Note that this crate is intentionally very bare-bones currently. The main +//! type, `TokenStream`, only supports `fmt::Display` and `FromStr` +//! implementations, indicating that it can only go to and come from a string. +//! This functionality is intended to be expanded over time as more surface +//! area for macro authors is stabilized. + +#![crate_name = "rustc_macro"] +#![unstable(feature = "rustc_macro_lib", issue = "27812")] +#![crate_type = "rlib"] +#![crate_type = "dylib"] +#![cfg_attr(not(stage0), deny(warnings))] +#![deny(missing_docs)] + +#![feature(rustc_private)] +#![feature(staged_api)] +#![feature(lang_items)] + +extern crate syntax; + +use std::fmt; +use std::str::FromStr; + +use syntax::ast; +use syntax::parse; +use syntax::ptr::P; + +/// The main type provided by this crate, representing an abstract stream of +/// tokens. +/// +/// This is both the input and output of `#[rustc_macro_derive]` definitions. +/// Currently it's required to be a list of valid Rust items, but this +/// restriction may be lifted in the future. +/// +/// The API of this type is intentionally bare-bones, but it'll be expanded over +/// time! +pub struct TokenStream { + inner: Vec>, +} + +/// Error returned from `TokenStream::from_str`. +#[derive(Debug)] +pub struct LexError { + _inner: (), +} + +/// Permanently unstable internal implementation details of this crate. This +/// should not be used. +/// +/// These methods are used by the rest of the compiler to generate instances of +/// `TokenStream` to hand to macro definitions, as well as consume the output. +/// +/// Note that this module is also intentionally separate from the rest of the +/// crate. This allows the `#[unstable]` directive below to naturally apply to +/// all of the contents. +#[unstable(feature = "rustc_macro_internals", issue = "27812")] +#[doc(hidden)] +pub mod __internal { + use std::cell::Cell; + + use syntax::ast; + use syntax::ptr::P; + use syntax::parse::ParseSess; + use super::TokenStream; + + pub fn new_token_stream(item: P) -> TokenStream { + TokenStream { inner: vec![item] } + } + + pub fn token_stream_items(stream: TokenStream) -> Vec> { + stream.inner + } + + pub trait Registry { + fn register_custom_derive(&mut self, + trait_name: &str, + expand: fn(TokenStream) -> TokenStream); + } + + // Emulate scoped_thread_local!() here essentially + thread_local! { + static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _); + } + + pub fn set_parse_sess(sess: &ParseSess, f: F) -> R + where F: FnOnce() -> R + { + struct Reset { prev: *const ParseSess } + + impl Drop for Reset { + fn drop(&mut self) { + CURRENT_SESS.with(|p| p.set(self.prev)); + } + } + + CURRENT_SESS.with(|p| { + let _reset = Reset { prev: p.get() }; + p.set(sess); + f() + }) + } + + pub fn with_parse_sess(f: F) -> R + where F: FnOnce(&ParseSess) -> R + { + let p = CURRENT_SESS.with(|p| p.get()); + assert!(!p.is_null()); + f(unsafe { &*p }) + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + __internal::with_parse_sess(|sess| { + let src = src.to_string(); + let cfg = Vec::new(); + let name = "rustc-macro source code".to_string(); + let mut parser = parse::new_parser_from_source_str(sess, cfg, name, + src); + let mut ret = TokenStream { inner: Vec::new() }; + loop { + match parser.parse_item() { + Ok(Some(item)) => ret.inner.push(item), + Ok(None) => return Ok(ret), + Err(mut err) => { + err.cancel(); + return Err(LexError { _inner: () }) + } + } + } + }) + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for item in self.inner.iter() { + let item = syntax::print::pprust::item_to_string(item); + try!(f.write_str(&item)); + try!(f.write_str("\n")); + } + Ok(()) + } +} diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 2d3302c2eef3a..d70510896b96e 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -19,6 +19,8 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } +rustc_macro = { path = "../librustc_macro" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_ext = { path = "../libsyntax_ext" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 85cf41e42a273..1e6c74bef8da5 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -234,6 +234,8 @@ pub fn rustc_version() -> String { pub const tag_panic_strategy: usize = 0x114; +pub const tag_macro_derive_registrar: usize = 0x115; + // NB: increment this if you change the format of metadata such that // rustc_version can't be found. pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7e1f3ea618c97..2524348dc1a96 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -130,18 +130,23 @@ struct ExtensionCrate { metadata: PMDSource, dylib: Option, target_only: bool, + + ident: String, + name: String, + span: Span, + should_link: bool, } enum PMDSource { Registered(Rc), - Owned(MetadataBlob), + Owned(loader::Library), } impl PMDSource { pub fn as_slice<'a>(&'a self) -> &'a [u8] { match *self { PMDSource::Registered(ref cmd) => cmd.data(), - PMDSource::Owned(ref mdb) => mdb.as_slice(), + PMDSource::Owned(ref lib) => lib.metadata.as_slice(), } } } @@ -151,6 +156,17 @@ enum LoadResult { Loaded(loader::Library), } +pub struct Macros { + pub macro_rules: Vec, + + /// An array of pairs where the first element is the name of the custom + /// derive (e.g. the trait being derived) and the second element is the + /// index of the definition. + pub custom_derive_registrar: Option, + pub svh: Svh, + pub dylib: Option, +} + impl<'a> CrateReader<'a> { pub fn new(sess: &'a Session, cstore: &'a CStore, @@ -281,6 +297,7 @@ impl<'a> CrateReader<'a> { explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + info!("register crate `extern crate {} as {}`", name, ident); self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it @@ -319,6 +336,11 @@ impl<'a> CrateReader<'a> { explicitly_linked: Cell::new(explicitly_linked), }); + if decoder::get_derive_registrar_fn(cmeta.data.as_slice()).is_some() { + self.sess.span_err(span, "crates of the `rustc-macro` crate type \ + cannot be linked at runtime"); + } + let source = cstore::CrateSource { dylib: dylib, rlib: rlib, @@ -349,9 +371,11 @@ impl<'a> CrateReader<'a> { kind: PathKind, explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + info!("resolving crate `extern crate {} as {}`", name, ident); let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), None => { + info!("falling back to a load"); let mut load_ctxt = loader::Context { sess: self.sess, span: span, @@ -412,6 +436,7 @@ impl<'a> CrateReader<'a> { self.cstore.iter_crate_data(|cnum, data| { if data.name() == meta_name && meta_hash == data.hash() { assert!(loader.hash.is_none()); + info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); } }); @@ -483,6 +508,8 @@ impl<'a> CrateReader<'a> { } fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { + info!("read extension crate {} `extern crate {} as {}` linked={}", + info.id, info.name, info.ident, info.should_link); let target_triple = &self.sess.opts.target_triple[..]; let is_cross = target_triple != config::host_triple(); let mut should_link = info.should_link && !is_cross; @@ -533,16 +560,7 @@ impl<'a> CrateReader<'a> { } LoadResult::Loaded(library) => { let dylib = library.dylib.clone(); - let metadata = if should_link { - // Register crate now to avoid double-reading metadata - let (_, cmd, _) = self.register_crate(&None, &info.ident, - &info.name, span, - library, true); - PMDSource::Registered(cmd) - } else { - // Not registering the crate; just hold on to the metadata - PMDSource::Owned(library.metadata) - }; + let metadata = PMDSource::Owned(library); (dylib, metadata) } }; @@ -551,59 +569,97 @@ impl<'a> CrateReader<'a> { metadata: metadata, dylib: dylib.map(|p| p.0), target_only: target_only, + name: info.name.to_string(), + ident: info.ident.to_string(), + span: span, + should_link: should_link, } } - /// Read exported macros. - pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec { + pub fn read_macros(&mut self, item: &ast::Item) -> Macros { let ci = self.extract_crate_info(item).unwrap(); let ekrate = self.read_extension_crate(item.span, &ci); let source_name = format!("<{} macros>", item.ident); - let mut macros = vec![]; + let mut ret = Macros { + macro_rules: Vec::new(), + custom_derive_registrar: None, + svh: decoder::get_crate_hash(ekrate.metadata.as_slice()), + dylib: None, + }; decoder::each_exported_macro(ekrate.metadata.as_slice(), - |name, attrs, span, body| { - // NB: Don't use parse::parse_tts_from_source_str because it parses with - // quote_depth > 0. - let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - self.local_crate_config.clone(), - source_name.clone(), - body); - let lo = p.span.lo; - let body = match p.parse_all_token_trees() { - Ok(body) => body, - Err(mut err) => { - err.emit(); - self.sess.abort_if_errors(); - unreachable!(); - } - }; - let local_span = mk_sp(lo, p.last_span.hi); - - // Mark the attrs as used - for attr in &attrs { - attr::mark_used(attr); + |name, attrs, span, body| { + // NB: Don't use parse::parse_tts_from_source_str because it parses with + // quote_depth > 0. + let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, + self.local_crate_config.clone(), + source_name.clone(), + body); + let lo = p.span.lo; + let body = match p.parse_all_token_trees() { + Ok(body) => body, + Err(mut err) => { + err.emit(); + self.sess.abort_if_errors(); + unreachable!(); } + }; + let local_span = mk_sp(lo, p.last_span.hi); - macros.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(name), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: local_span, - imported_from: Some(item.ident), - // overridden in plugin/load.rs - export: false, - use_locally: false, - allow_internal_unstable: false, - - body: body, - }); - self.sess.imported_macro_spans.borrow_mut() - .insert(local_span, (name.as_str().to_string(), span)); - true + // Mark the attrs as used + for attr in &attrs { + attr::mark_used(attr); + } + + ret.macro_rules.push(ast::MacroDef { + ident: ast::Ident::with_empty_ctxt(name), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + span: local_span, + imported_from: Some(item.ident), + // overridden in plugin/load.rs + export: false, + use_locally: false, + allow_internal_unstable: false, + + body: body, + }); + self.sess.imported_macro_spans.borrow_mut() + .insert(local_span, (name.as_str().to_string(), span)); + true + }); + + match decoder::get_derive_registrar_fn(ekrate.metadata.as_slice()) { + Some(id) => ret.custom_derive_registrar = Some(id), + + // If this crate is not a rustc-macro crate then we might be able to + // register it with the local crate store to prevent loading the + // metadata twice. + // + // If it's a rustc-macro crate, though, then we definitely don't + // want to register it with the local crate store as we're just + // going to use it as we would a plugin. + None => { + ekrate.register(self); + return ret } - ); - macros + } + + self.cstore.add_used_for_derive_macros(item); + ret.dylib = ekrate.dylib.clone(); + if ret.dylib.is_none() { + span_bug!(item.span, "rustc-macro crate not dylib"); + } + + if ekrate.target_only { + let message = format!("rustc-macro crate is not available for \ + triple `{}` (only found {})", + config::host_triple(), + self.sess.opts.target_triple); + self.sess.span_fatal(item.span, &message); + } + + return ret } /// Look for a plugin registrar. Returns library path, crate @@ -774,6 +830,7 @@ impl<'a> CrateReader<'a> { match *ct { config::CrateTypeExecutable => need_exe_alloc = true, config::CrateTypeDylib | + config::CrateTypeRustcMacro | config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, config::CrateTypeRlib => {} @@ -858,6 +915,27 @@ impl<'a> CrateReader<'a> { } } +impl ExtensionCrate { + fn register(self, creader: &mut CrateReader) { + if !self.should_link { + return + } + + let library = match self.metadata { + PMDSource::Owned(lib) => lib, + PMDSource::Registered(_) => return, + }; + + // Register crate now to avoid double-reading metadata + creader.register_crate(&None, + &self.ident, + &self.name, + self.span, + library, + true); + } +} + impl<'a> LocalCrateReader<'a> { fn new(sess: &'a Session, cstore: &'a CStore, @@ -906,11 +984,25 @@ impl<'a> LocalCrateReader<'a> { fn process_item(&mut self, i: &ast::Item) { match i.node { ast::ItemKind::ExternCrate(_) => { - if !should_link(i) { - return; + // If this `extern crate` item has `#[macro_use]` then we can + // safely skip it. These annotations were processed during macro + // expansion and are already loaded (if necessary) into our + // crate store. + // + // Note that it's important we *don't* fall through below as + // some `#[macro_use]` crate are explicitly not linked (e.g. + // macro crates) so we want to ensure we avoid `resolve_crate` + // with those. + if attr::contains_name(&i.attrs, "macro_use") { + if self.cstore.was_used_for_derive_macros(i) { + return + } } if let Some(info) = self.creader.extract_crate_info(i) { + if !info.should_link { + return; + } let (cnum, _, _) = self.creader.resolve_crate(&None, &info.ident, &info.name, diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index d786cc5ba0eb7..952d7008d0f27 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -28,13 +28,13 @@ use rustc::hir::svh::Svh; use rustc::middle::cstore::ExternCrate; use rustc::session::config::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet}; use std::cell::{RefCell, Ref, Cell}; use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; -use syntax::ast; +use syntax::ast::{self, Ident}; use syntax::attr; use syntax::codemap; use syntax_pos; @@ -115,6 +115,7 @@ pub struct CStore { pub inlined_item_cache: RefCell>>, pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, + pub used_for_derive_macro: RefCell>, } impl CStore { @@ -130,6 +131,7 @@ impl CStore { visible_parent_map: RefCell::new(FnvHashMap()), inlined_item_cache: RefCell::new(FnvHashMap()), defid_for_inlined_node: RefCell::new(FnvHashMap()), + used_for_derive_macro: RefCell::new(FnvHashSet()), } } @@ -286,6 +288,14 @@ impl CStore { { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } + + pub fn was_used_for_derive_macros(&self, i: &ast::Item) -> bool { + self.used_for_derive_macro.borrow().contains(&i.ident) + } + + pub fn add_used_for_derive_macros(&self, i: &ast::Item) { + self.used_for_derive_macro.borrow_mut().insert(i.ident); + } } impl CrateMetadata { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7117cdb731cf3..9a13be8ade52a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1398,6 +1398,11 @@ pub fn each_exported_macro(data: &[u8], mut f: F) where } } +pub fn get_derive_registrar_fn(data: &[u8]) -> Option { + reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar) + .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) +} + pub fn get_macro_span(doc: rbml::Doc) -> Span { let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo); let lo = BytePos(reader::doc_as_u32(lo_doc)); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b3ac678d7120d..bb4cf70bd3b3e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -31,7 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; -use rustc::session::config::{self, PanicStrategy}; +use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::Encodable; @@ -1567,7 +1567,8 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { /// Serialize the text of the exported macros fn encode_macro_defs(rbml_w: &mut Encoder, - krate: &hir::Crate) { + krate: &hir::Crate, + tcx: TyCtxt) { rbml_w.start_tag(tag_macro_defs); for def in &krate.exported_macros { rbml_w.start_tag(tag_macro_def); @@ -1585,6 +1586,12 @@ fn encode_macro_defs(rbml_w: &mut Encoder, rbml_w.end_tag(); } rbml_w.end_tag(); + + if tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { + let id = tcx.sess.derive_registrar_fn.get().unwrap(); + let did = tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32()); + } } fn encode_struct_field_attrs(ecx: &EncodeContext, @@ -1882,7 +1889,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, // Encode macro definitions i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_macro_defs(rbml_w, krate); + encode_macro_defs(rbml_w, krate, ecx.tcx); stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode the def IDs of impls, for coherence checking. diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index a96fa8a006d89..a3afb9d84bd30 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -19,11 +19,13 @@ #![feature(box_patterns)] #![feature(enumset)] +#![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(rustc_macro_lib)] +#![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(question_mark)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -33,12 +35,14 @@ extern crate flate; extern crate rbml; extern crate serialize as rustc_serialize; // used by deriving extern crate rustc_errors as errors; +extern crate syntax_ext; #[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate rustc_back; extern crate rustc_llvm; +extern crate rustc_macro; extern crate rustc_const_math; pub use rustc::middle; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index fa31b6f4c7224..22691975050e5 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -10,16 +10,25 @@ //! Used by `rustc` when loading a crate with exported macros. -use creader::CrateReader; +use std::collections::HashSet; +use std::env; +use std::mem; + +use creader::{CrateReader, Macros}; use cstore::CStore; +use rustc::hir::def_id::DefIndex; use rustc::session::Session; -use rustc::util::nodemap::{FnvHashSet, FnvHashMap}; - -use syntax::parse::token; +use rustc::util::nodemap::FnvHashMap; +use rustc_back::dynamic_lib::DynamicLibrary; +use rustc_macro::TokenStream; +use rustc_macro::__internal::Registry; use syntax::ast; use syntax::attr; +use syntax::ext::base::LoadedMacro; use syntax::ext; +use syntax::parse::token; +use syntax_ext::deriving::custom::CustomDerive; use syntax_pos::Span; pub struct MacroLoader<'a> { @@ -47,7 +56,9 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { pub type MacroSelection = FnvHashMap; impl<'a> ext::base::MacroLoader for MacroLoader<'a> { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + fn load_crate(&mut self, + extern_crate: &ast::Item, + allows_macros: bool) -> Vec { // Parse the attributes relating to macros. let mut import = Some(FnvHashMap()); // None => load all let mut reexport = FnvHashMap(); @@ -105,7 +116,7 @@ impl<'a> MacroLoader<'a> { allows_macros: bool, import: Option, reexport: MacroSelection) - -> Vec { + -> Vec { if let Some(sel) = import.as_ref() { if sel.is_empty() && reexport.is_empty() { return Vec::new(); @@ -118,10 +129,11 @@ impl<'a> MacroLoader<'a> { return Vec::new(); } - let mut macros = Vec::new(); - let mut seen = FnvHashSet(); + let mut macros = self.reader.read_macros(vi); + let mut ret = Vec::new(); + let mut seen = HashSet::new(); - for mut def in self.reader.read_exported_macros(vi) { + for mut def in macros.macro_rules.drain(..) { let name = def.ident.name.as_str(); def.use_locally = match import.as_ref() { @@ -132,10 +144,29 @@ impl<'a> MacroLoader<'a> { def.allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable"); debug!("load_macros: loaded: {:?}", def); - macros.push(def); + ret.push(LoadedMacro::Def(def)); seen.insert(name); } + if let Some(index) = macros.custom_derive_registrar { + // custom derive crates currently should not have any macro_rules! + // exported macros, enforced elsewhere + assert_eq!(ret.len(), 0); + + if import.is_some() { + self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \ + selectively imported from, must \ + use `#[macro_use]`"); + } + + if reexport.len() > 0 { + self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \ + reexported from"); + } + + self.load_derive_macros(vi.span, ¯os, index, &mut ret); + } + if let Some(sel) = import.as_ref() { for (name, span) in sel { if !seen.contains(&name) { @@ -152,6 +183,54 @@ impl<'a> MacroLoader<'a> { } } - macros + return ret + } + + /// Load the custom derive macros into the list of macros we're loading. + /// + /// Note that this is intentionally similar to how we load plugins today, + /// but also intentionally separate. Plugins are likely always going to be + /// implemented as dynamic libraries, but we have a possible future where + /// custom derive (and other macro-1.1 style features) are implemented via + /// executables and custom IPC. + fn load_derive_macros(&mut self, + span: Span, + macros: &Macros, + index: DefIndex, + ret: &mut Vec) { + // Make sure the path contains a / or the linker will search for it. + let path = macros.dylib.as_ref().unwrap(); + let path = env::current_dir().unwrap().join(path); + let lib = match DynamicLibrary::open(Some(&path)) { + Ok(lib) => lib, + Err(err) => self.sess.span_fatal(span, &err), + }; + + let sym = self.sess.generate_derive_registrar_symbol(¯os.svh, index); + let registrar = unsafe { + let sym = match lib.symbol(&sym) { + Ok(f) => f, + Err(err) => self.sess.span_fatal(span, &err), + }; + mem::transmute::<*mut u8, fn(&mut Registry)>(sym) + }; + + struct MyRegistrar<'a>(&'a mut Vec); + + impl<'a> Registry for MyRegistrar<'a> { + fn register_custom_derive(&mut self, + trait_name: &str, + expand: fn(TokenStream) -> TokenStream) { + let derive = Box::new(CustomDerive::new(expand)); + self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(), + derive)); + } + } + + registrar(&mut MyRegistrar(ret)); + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + mem::forget(lib); } } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 5ae6584aed425..6db821b2cd8d1 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -156,7 +156,6 @@ impl<'a> Registry<'a> { self.llvm_passes.push(name.to_owned()); } - /// Register an attribute with an attribute type. /// /// Registered attributes will bypass the `custom_attribute` feature gate. diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b21785c27dae5..b970c63a22433 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -238,6 +238,7 @@ pub fn invalid_output_for_target(sess: &Session, match (sess.target.target.options.dynamic_linking, sess.target.target.options.executables, crate_type) { (false, _, config::CrateTypeCdylib) | + (false, _, config::CrateTypeRustcMacro) | (false, _, config::CrateTypeDylib) => true, (_, false, config::CrateTypeExecutable) => true, _ => false @@ -261,6 +262,7 @@ pub fn filename_for_input(sess: &Session, outputs.out_directory.join(&format!("lib{}.rlib", libname)) } config::CrateTypeCdylib | + config::CrateTypeRustcMacro | config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); @@ -291,7 +293,8 @@ pub fn each_linked_rlib(sess: &Session, let fmts = sess.dependency_formats.borrow(); let fmts = fmts.get(&config::CrateTypeExecutable) .or_else(|| fmts.get(&config::CrateTypeStaticlib)) - .or_else(|| fmts.get(&config::CrateTypeCdylib)); + .or_else(|| fmts.get(&config::CrateTypeCdylib)) + .or_else(|| fmts.get(&config::CrateTypeRustcMacro)); let fmts = fmts.unwrap_or_else(|| { bug!("could not find formats for rlibs") }); @@ -738,7 +741,8 @@ fn link_args(cmd: &mut Linker, // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main // object file, so we link that in here. - if crate_type == config::CrateTypeDylib { + if crate_type == config::CrateTypeDylib || + crate_type == config::CrateTypeRustcMacro { cmd.add_object(&outputs.with_extension("metadata.o")); } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index f2d5b128d2705..58cad5c117f93 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufWriter}; use std::io::prelude::*; +use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; use std::process::Command; @@ -28,16 +29,16 @@ use syntax::ast; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. pub struct LinkerInfo { - dylib_exports: Vec, - cdylib_exports: Vec + exports: HashMap>, } impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, reachable: &[String]) -> LinkerInfo { LinkerInfo { - dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib), - cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib) + exports: scx.sess().crate_types.borrow().iter().map(|&c| { + (c, exported_symbols(scx, reachable, c)) + }).collect(), } } @@ -243,7 +244,8 @@ impl<'a> Linker for GnuLinker<'a> { // exported symbols to ensure we don't expose any more. The object files // have far more public symbols than we actually want to export, so we // hide them all here. - if crate_type == CrateType::CrateTypeDylib { + if crate_type == CrateType::CrateTypeDylib || + crate_type == CrateType::CrateTypeRustcMacro { return } @@ -254,7 +256,7 @@ impl<'a> Linker for GnuLinker<'a> { let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; - for sym in &self.info.cdylib_exports { + for sym in self.info.exports[&crate_type].iter() { writeln!(f, " {};", sym)?; } writeln!(f, "\n local:\n *;\n}};")?; @@ -274,7 +276,7 @@ impl<'a> Linker for GnuLinker<'a> { }; let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); - for sym in &self.info.cdylib_exports { + for sym in self.info.exports[&crate_type].iter() { writeln!(f, "{}{}", prefix, sym)?; } Ok(()) @@ -427,12 +429,7 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - let symbols = if crate_type == CrateType::CrateTypeCdylib { - &self.info.cdylib_exports - } else { - &self.info.dylib_exports - }; - for symbol in symbols { + for symbol in self.info.exports[&crate_type].iter() { writeln!(f, " {}", symbol)?; } Ok(()) @@ -450,13 +447,10 @@ fn exported_symbols(scx: &SharedCrateContext, reachable: &[String], crate_type: CrateType) -> Vec { - if !scx.sess().crate_types.borrow().contains(&crate_type) { - return vec![]; - } - // See explanation in GnuLinker::export_symbols, for // why we don't ever need dylib symbols on non-MSVC. - if crate_type == CrateType::CrateTypeDylib { + if crate_type == CrateType::CrateTypeDylib || + crate_type == CrateType::CrateTypeRustcMacro { if !scx.sess().target.target.options.is_like_msvc { return vec![]; } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 9b02cbe6721f3..143275fa7117b 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -188,6 +188,11 @@ impl<'a, 'tcx> Instance<'tcx> { let idx = def_id.index; return scx.sess().generate_plugin_registrar_symbol(svh, idx); } + if scx.sess().derive_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = def_id.index; + return scx.sess().generate_derive_registrar_symbol(svh, idx); + } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 43e190f5deb81..3b1c01319c492 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -27,10 +27,10 @@ use ptr::P; use util::small_vector::SmallVector; use util::lev_distance::find_best_match_for_name; use fold::Folder; +use feature_gate; use std::collections::{HashMap, HashSet}; use std::rc::Rc; -use std::default::Default; use tokenstream; @@ -568,12 +568,18 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) } pub trait MacroLoader { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) + -> Vec; +} + +pub enum LoadedMacro { + Def(ast::MacroDef), + CustomDerive(String, Box), } pub struct DummyMacroLoader; impl MacroLoader for DummyMacroLoader { - fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { + fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { Vec::new() } } @@ -593,6 +599,7 @@ pub struct ExtCtxt<'a> { pub exported_macros: Vec, pub syntax_env: SyntaxEnv, + pub derive_modes: HashMap>, pub recursion_count: usize, pub filename: Option, @@ -616,6 +623,7 @@ impl<'a> ExtCtxt<'a> { exported_macros: Vec::new(), loader: loader, syntax_env: env, + derive_modes: HashMap::new(), recursion_count: 0, filename: None, @@ -714,6 +722,25 @@ impl<'a> ExtCtxt<'a> { } } + pub fn insert_custom_derive(&mut self, + name: &str, + ext: Box, + sp: Span) { + if !self.ecfg.enable_rustc_macro() { + feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic, + "rustc_macro", + sp, + feature_gate::GateIssue::Language, + "loading custom derive macro crates \ + is experimentally supported"); + } + let name = token::intern_and_get_ident(name); + if self.derive_modes.insert(name.clone(), ext).is_some() { + self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", + name)); + } + } + pub fn struct_span_warn(&self, sp: Span, msg: &str) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 15ebf95d62393..d06b77a5b0549 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -440,8 +440,7 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe callee: NameAndSpan { format: MacroAttribute(intern(&attr.name())), span: Some(attr.span), - // attributes can do whatever they like, for now - allow_internal_unstable: true, + allow_internal_unstable: false, } }); @@ -538,7 +537,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. for def in self.cx.loader.load_crate(item, self.at_crate_root) { - self.cx.insert_macro(def); + match def { + LoadedMacro::Def(def) => self.cx.insert_macro(def), + LoadedMacro::CustomDerive(name, ext) => { + self.cx.insert_custom_derive(&name, ext, item.span); + } + } } } else { let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false); @@ -688,6 +692,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = custom_derive, fn enable_pushpop_unsafe = pushpop_unsafe, + fn enable_rustc_macro = rustc_macro, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 02c44c3a56d7e..683d5277359e8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -47,7 +47,7 @@ macro_rules! setter { } macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. const ACTIVE_FEATURES: &'static [(&'static str, &'static str, @@ -75,14 +75,14 @@ macro_rules! declare_features { } }; - ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents features which has since been removed (it was once Active) const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ $((stringify!($feature), $ver, $issue)),+ ]; }; - ($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Those language feature has since been Accepted (it was once Active) const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ $((stringify!($feature), $ver, $issue)),+ @@ -288,7 +288,10 @@ declare_features! ( (active, abi_sysv64, "1.13.0", Some(36167)), // Use the import semantics from RFC 1560. - (active, item_like_imports, "1.13.0", Some(35120)) + (active, item_like_imports, "1.13.0", Some(35120)), + + // Macros 1.1 + (active, rustc_macro, "1.13.0", Some(35900)), ); declare_features! ( @@ -302,7 +305,6 @@ declare_features! ( (removed, struct_inherit, "1.0.0", None), (removed, test_removed_feature, "1.0.0", None), (removed, visible_private_types, "1.0.0", None), - (removed, unsafe_no_drop_flag, "1.0.0", None) ); declare_features! ( @@ -330,7 +332,7 @@ declare_features! ( (accepted, type_macros, "1.13.0", Some(27245)), (accepted, while_let, "1.0.0", None), // Allows `#[deprecated]` attribute - (accepted, deprecated, "1.9.0", Some(29935)) + (accepted, deprecated, "1.9.0", Some(29935)), ); // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -543,6 +545,15 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat is an experimental feature", cfg_fn!(linked_from))), + ("rustc_macro_derive", Normal, Gated("rustc_macro", + "the `#[rustc_macro_derive]` attribute \ + is an experimental feature", + cfg_fn!(rustc_macro))), + + ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs", + "internal implementation detail", + cfg_fn!(rustc_attrs))), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), @@ -616,6 +627,7 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), + ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)), ]; #[derive(Debug, Eq, PartialEq)] diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 040c6c8ebff26..6910e6400d4f8 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } log = { path = "../liblog" } +rustc_errors = { path = "../librustc_errors" } +rustc_macro = { path = "../librustc_macro" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index f1a3a1f41b14e..c7afaaf4796a4 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -49,7 +49,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) if ty_params.is_empty() && - attr::contains_name(&annitem.attrs, "derive_Copy") => { + attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; unify_fieldless_variants = true; @@ -110,12 +110,12 @@ fn cs_clone(name: &str, Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), }; - let subcall = |field: &FieldInfo| { + let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; let span = if mode == Mode::Shallow { // set the expn ID so we can call the unstable method - Span { expn_id: cx.backtrace(), ..trait_span } + super::allow_unstable(cx, field.span, "derive(Clone)") } else { field.span }; @@ -147,8 +147,10 @@ fn cs_clone(name: &str, match mode { Mode::Shallow => { - let mut stmts: Vec<_> = - all_fields.iter().map(subcall).map(|e| cx.stmt_expr(e)).collect(); + let mut stmts = all_fields.iter().map(|f| { + let call = subcall(cx, f); + cx.stmt_expr(call) + }).collect::>(); stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); cx.expr_block(cx.block(trait_span, stmts)) } @@ -166,14 +168,15 @@ fn cs_clone(name: &str, name)) } }; - cx.field_imm(field.span, ident, subcall(field)) + let call = subcall(cx, field); + cx.field_imm(field.span, ident, call) }) .collect::>(); cx.expr_struct(trait_span, ctor_path, fields) } VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(subcall).collect(); + let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); let path = cx.expr_path(ctor_path); cx.expr_call(trait_span, path, subcalls) } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs new file mode 100644 index 0000000000000..1f9c24a0dcd69 --- /dev/null +++ b/src/libsyntax_ext/deriving/custom.rs @@ -0,0 +1,97 @@ +// 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. + +use std::panic; + +use rustc_macro::{TokenStream, __internal}; +use syntax::ast::{self, ItemKind}; +use syntax::codemap::Span; +use syntax::ext::base::*; +use syntax::fold::{self, Folder}; +use errors::FatalError; + +pub struct CustomDerive { + inner: fn(TokenStream) -> TokenStream, +} + +impl CustomDerive { + pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive { + CustomDerive { inner: inner } + } +} + +impl MultiItemModifier for CustomDerive { + fn expand(&self, + ecx: &mut ExtCtxt, + span: Span, + _meta_item: &ast::MetaItem, + item: Annotatable) + -> Vec { + let item = match item { + Annotatable::Item(item) => item, + Annotatable::ImplItem(_) | + Annotatable::TraitItem(_) => { + ecx.span_err(span, "custom derive attributes may only be \ + applied to struct/enum items"); + return Vec::new() + } + }; + match item.node { + ItemKind::Struct(..) | + ItemKind::Enum(..) => {} + _ => { + ecx.span_err(span, "custom derive attributes may only be \ + applied to struct/enum items"); + return Vec::new() + } + } + + let input = __internal::new_token_stream(item); + let res = __internal::set_parse_sess(&ecx.parse_sess, || { + let inner = self.inner; + panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input))) + }); + let item = match res { + Ok(stream) => __internal::token_stream_items(stream), + Err(e) => { + let msg = "custom derive attribute panicked"; + let mut err = ecx.struct_span_fatal(span, msg); + if let Some(s) = e.downcast_ref::() { + err.help(&format!("message: {}", s)); + } + if let Some(s) = e.downcast_ref::<&'static str>() { + err.help(&format!("message: {}", s)); + } + + err.emit(); + panic!(FatalError); + } + }; + + // Right now we have no knowledge of spans at all in custom derive + // macros, everything is just parsed as a string. Reassign all spans to + // the #[derive] attribute for better errors here. + item.into_iter().flat_map(|item| { + ChangeSpan { span: span }.fold_item(item) + }).map(Annotatable::Item).collect() + } +} + +struct ChangeSpan { span: Span } + +impl Folder for ChangeSpan { + fn new_span(&mut self, _sp: Span) -> Span { + self.span + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } +} diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 81085122e875b..5582166c12e9c 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,7 +12,7 @@ use syntax::ast::{self, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; -use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; +use syntax::ext::base::MultiModifier; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -61,6 +61,7 @@ pub mod decodable; pub mod hash; pub mod debug; pub mod default; +pub mod custom; #[path="cmp/partial_eq.rs"] pub mod partial_eq; @@ -74,156 +75,201 @@ pub mod ord; pub mod generic; +fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { + Span { + expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern(attr_name)), + span: Some(span), + allow_internal_unstable: true, + }, + }), + ..span + } +} + fn expand_derive(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, annotatable: Annotatable) - -> Annotatable { + -> Vec { debug!("expand_derive: span = {:?}", span); debug!("expand_derive: mitem = {:?}", mitem); debug!("expand_derive: annotatable input = {:?}", annotatable); - let annot = annotatable.map_item_or(|item| { - item.map(|mut item| { - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); - } + let mut item = match annotatable { + Annotatable::Item(item) => item, + other => { + cx.span_err(span, "`derive` can only be applied to items"); + return vec![other] + } + }; - let traits = mitem.meta_item_list().unwrap_or(&[]); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); - } + if mitem.value_str().is_some() { + cx.span_err(mitem.span, "unexpected value in `derive`"); + } - let mut found_partial_eq = false; - let mut eq_span = None; - - for titem in traits.iter().rev() { - let tname = if let Some(word) = titem.word() { - word.name() - } else { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - }; - - if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "custom_derive", - titem.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CUSTOM_DERIVE); - continue; - } + let traits = mitem.meta_item_list().unwrap_or(&[]); + if traits.is_empty() { + cx.span_warn(mitem.span, "empty trait list in `derive`"); + } - let span = Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: titem.span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(intern(&format!("derive({})", tname))), - span: Some(titem.span), - allow_internal_unstable: true, - }, - }), - ..titem.span - }; - - if &tname[..] == "Eq" { - eq_span = Some(span); - } else if &tname[..] == "PartialEq" { - found_partial_eq = true; - } + // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) + // `#[structural_match]` attribute. + if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") && + traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") { + let structural_match = intern_and_get_ident("structural_match"); + let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + let meta = cx.meta_word(span, structural_match); + item = item.map(|mut i| { + i.attrs.push(cx.attribute(span, meta)); + i + }); + } - // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(span, - cx.meta_word(titem.span, - intern_and_get_ident(&format!("derive_{}", tname))))); - } + // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is + // the same as the copy implementation. + // + // Add a marker attribute here picked up during #[derive(Clone)] + if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") && + traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") { + let marker = intern_and_get_ident("rustc_copy_clone_marker"); + let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + let meta = cx.meta_word(span, marker); + item = item.map(|mut i| { + i.attrs.push(cx.attribute(span, meta)); + i + }); + } - // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) - // `#[structural_match]` attribute. - if let Some(eq_span) = eq_span { - if found_partial_eq { - let structural_match = intern_and_get_ident("structural_match"); - item.attrs.push(cx.attribute(eq_span, cx.meta_word(eq_span, structural_match))); - } + let mut other_items = Vec::new(); + + let mut iter = traits.iter(); + while let Some(titem) = iter.next() { + + let tword = match titem.word() { + Some(name) => name, + None => { + cx.span_err(titem.span, "malformed `derive` entry"); + continue } + }; + let tname = tword.name(); + + // If this is a built-in derive mode, then we expand it immediately + // here. + if is_builtin_trait(&tname) { + let name = intern_and_get_ident(&format!("derive({})", tname)); + let mitem = cx.meta_word(titem.span, name); + + let span = Span { + expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: titem.span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern(&format!("derive({})", tname))), + span: Some(titem.span), + allow_internal_unstable: true, + }, + }), + ..titem.span + }; + + let my_item = Annotatable::Item(item); + expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| { + other_items.push(a); + }); + item = my_item.expect_item(); + + // Otherwise if this is a `rustc_macro`-style derive mode, we process it + // here. The logic here is to: + // + // 1. Collect the remaining `#[derive]` annotations into a list. If + // there are any left, attach a `#[derive]` attribute to the item + // that we're currently expanding with the remaining derive modes. + // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander. + // 3. Expand the current item we're expanding, getting back a list of + // items that replace it. + // 4. Extend the returned list with the current list of items we've + // collected so far. + // 5. Return everything! + // + // If custom derive extensions end up threading through the `#[derive]` + // attribute, we'll get called again later on to continue expanding + // those modes. + } else if let Some(ext) = cx.derive_modes.remove(&tname) { + let remaining_derives = iter.cloned().collect::>(); + if remaining_derives.len() > 0 { + let list = cx.meta_list(titem.span, + intern_and_get_ident("derive"), + remaining_derives); + let attr = cx.attribute(titem.span, list); + item = item.map(|mut i| { + i.attrs.push(attr); + i + }); + } + let titem = cx.meta_list_item_word(titem.span, tname.clone()); + let mitem = cx.meta_list(titem.span, + intern_and_get_ident("derive"), + vec![titem]); + let item = Annotatable::Item(item); + let mut items = ext.expand(cx, mitem.span, &mitem, item); + items.extend(other_items); + cx.derive_modes.insert(tname.clone(), ext); + return items + + // If we've gotten this far then it means that we're in the territory of + // the old custom derive mechanism. If the feature isn't enabled, we + // issue an error, otherwise manufacture the `derive_Foo` attribute. + } else if !cx.ecfg.enable_custom_derive() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "custom_derive", + titem.span, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_CUSTOM_DERIVE); + } else { + let name = intern_and_get_ident(&format!("derive_{}", tname)); + let mitem = cx.meta_word(titem.span, name); + item = item.map(|mut i| { + i.attrs.push(cx.attribute(mitem.span, mitem)); + i + }); + } + } - item - }) - }, - |a| { - cx.span_err(span, - "`derive` can only be applied to items"); - a - }); - debug!("expand_derive: annotatable output = {:?}", annot); - annot + other_items.insert(0, Annotatable::Item(item)); + return other_items } macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn register_all(env: &mut SyntaxEnv) { - // Define the #[derive_*] extensions. - $({ - struct DeriveExtension; - - impl MultiItemDecorator for DeriveExtension { - fn expand(&self, - ecx: &mut ExtCtxt, - sp: Span, - mitem: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable)) { - if !ecx.parse_sess.codemap().span_allows_unstable(sp) - && !ecx.ecfg.features.unwrap().custom_derive { - // FIXME: - // https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303 - // This is just to avoid breakage with syntex. - // Remove that to spawn an error instead. - let cm = ecx.parse_sess.codemap(); - let parent = cm.with_expn_info(ecx.backtrace(), - |info| info.unwrap().call_site.expn_id); - cm.with_expn_info(parent, |info| { - if info.is_some() { - let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn( - sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE, - ); - if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() { - w.help( - &format!("add #![feature(custom_derive)] to \ - the crate attributes to enable") - ); - } - w.emit(); - } else { - feature_gate::emit_feature_err( - &ecx.parse_sess.span_diagnostic, - "custom_derive", sp, feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_DERIVE_UNDERSCORE - ); - - return; - } - }) - } - - warn_if_deprecated(ecx, sp, $name); - $func(ecx, sp, mitem, annotatable, push); - } - } - - env.insert(intern(concat!("derive_", $name)), - MultiDecorator(Box::new(DeriveExtension))); - })+ - - env.insert(intern("derive"), - MultiModifier(Box::new(expand_derive))); + env.insert(intern("derive"), MultiModifier(Box::new(expand_derive))); } - fn is_builtin_trait(name: &str) -> bool { + pub fn is_builtin_trait(name: &str) -> bool { match name { $( $name )|+ => true, _ => false, } } + + fn expand_builtin(name: &str, + ecx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut FnMut(Annotatable)) { + match name { + $( + $name => { + warn_if_deprecated(ecx, span, $name); + $func(ecx, span, mitem, item, push); + } + )* + _ => panic!("not a builtin derive mode: {}", name), + } + } } } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 3aa62339b477e..4bae9ec5a1a1f 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -19,6 +19,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(rustc_macro_lib)] +#![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] @@ -28,6 +30,7 @@ extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; +extern crate rustc_macro; extern crate rustc_errors as errors; use syntax::ext::base::{MacroExpanderFn, NormalTT}; @@ -44,6 +47,8 @@ mod format; mod log_syntax; mod trace_macros; +pub mod rustc_macro_registrar; + // for custom_derive pub mod deriving; diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs new file mode 100644 index 0000000000000..7693e2416f4b0 --- /dev/null +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -0,0 +1,280 @@ +// 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. + +use std::mem; + +use errors; +use syntax::ast::{self, Ident, NodeId}; +use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; +use syntax::ext::base::{ExtCtxt, DummyMacroLoader}; +use syntax::ext::build::AstBuilder; +use syntax::ext::expand::ExpansionConfig; +use syntax::parse::ParseSess; +use syntax::parse::token::{self, InternedString}; +use syntax::feature_gate::Features; +use syntax::ptr::P; +use syntax_pos::{Span, DUMMY_SP}; +use syntax::visit::{self, Visitor}; + +use deriving; + +struct CustomDerive { + trait_name: InternedString, + function_name: Ident, + span: Span, +} + +struct CollectCustomDerives<'a> { + derives: Vec, + in_root: bool, + handler: &'a errors::Handler, + is_rustc_macro_crate: bool, +} + +pub fn modify(sess: &ParseSess, + mut krate: ast::Crate, + is_rustc_macro_crate: bool, + num_crate_types: usize, + handler: &errors::Handler, + features: &Features) -> ast::Crate { + let mut loader = DummyMacroLoader; + let mut cx = ExtCtxt::new(sess, + Vec::new(), + ExpansionConfig::default("rustc_macro".to_string()), + &mut loader); + + let mut collect = CollectCustomDerives { + derives: Vec::new(), + in_root: true, + handler: handler, + is_rustc_macro_crate: is_rustc_macro_crate, + }; + visit::walk_crate(&mut collect, &krate); + + if !is_rustc_macro_crate { + return krate + } else if !features.rustc_macro { + let mut err = handler.struct_err("the `rustc-macro` crate type is \ + experimental"); + err.help("add #![feature(rustc_macro)] to the crate attributes to \ + enable"); + err.emit(); + } + + if num_crate_types > 1 { + handler.err("cannot mix `rustc-macro` crate type with others"); + } + + krate.module.items.push(mk_registrar(&mut cx, &collect.derives)); + + if krate.exported_macros.len() > 0 { + handler.err("cannot export macro_rules! macros from a `rustc-macro` \ + crate type currently"); + } + + return krate +} + +impl<'a> CollectCustomDerives<'a> { + fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { + if self.is_rustc_macro_crate && + self.in_root && + *vis == ast::Visibility::Public { + self.handler.span_err(sp, + "`rustc-macro` crate types cannot \ + export any items other than functions \ + tagged with `#[rustc_macro_derive]` \ + currently"); + } + } +} + +impl<'a> Visitor for CollectCustomDerives<'a> { + fn visit_item(&mut self, item: &ast::Item) { + // First up, make sure we're checking a bare function. If we're not then + // we're just not interested in this item. + // + // If we find one, try to locate a `#[rustc_macro_derive]` attribute on + // it. + match item.node { + ast::ItemKind::Fn(..) => {} + _ => { + self.check_not_pub_in_root(&item.vis, item.span); + return visit::walk_item(self, item) + } + } + + let mut attrs = item.attrs.iter() + .filter(|a| a.check_name("rustc_macro_derive")); + let attr = match attrs.next() { + Some(attr) => attr, + None => { + self.check_not_pub_in_root(&item.vis, item.span); + return visit::walk_item(self, item) + } + }; + + if let Some(a) = attrs.next() { + self.handler.span_err(a.span(), "multiple `#[rustc_macro_derive]` \ + attributes found"); + } + + if !self.is_rustc_macro_crate { + self.handler.span_err(attr.span(), + "the `#[rustc_macro_derive]` attribute is \ + only usable with crates of the `rustc-macro` \ + crate type"); + } + + // Once we've located the `#[rustc_macro_derive]` attribute, verify + // that it's of the form `#[rustc_macro_derive(Foo)]` + let list = match attr.meta_item_list() { + Some(list) => list, + None => { + self.handler.span_err(attr.span(), + "attribute must be of form: \ + #[rustc_macro_derive(TraitName)]"); + return + } + }; + if list.len() != 1 { + self.handler.span_err(attr.span(), + "attribute must only have one argument"); + return + } + let attr = &list[0]; + let trait_name = match attr.name() { + Some(name) => name, + _ => { + self.handler.span_err(attr.span(), "not a meta item"); + return + } + }; + if !attr.is_word() { + self.handler.span_err(attr.span(), "must only be one word"); + } + + if deriving::is_builtin_trait(&trait_name) { + self.handler.span_err(attr.span(), + "cannot override a built-in #[derive] mode"); + } + + if self.derives.iter().any(|d| d.trait_name == trait_name) { + self.handler.span_err(attr.span(), + "derive mode defined twice in this crate"); + } + + if self.in_root { + self.derives.push(CustomDerive { + span: item.span, + trait_name: trait_name, + function_name: item.ident, + }); + } else { + let msg = "functions tagged with `#[rustc_macro_derive]` must \ + currently reside in the root of the crate"; + self.handler.span_err(item.span, msg); + } + + visit::walk_item(self, item); + } + + fn visit_mod(&mut self, m: &ast::Mod, _s: Span, id: NodeId) { + let mut prev_in_root = self.in_root; + if id != ast::CRATE_NODE_ID { + prev_in_root = mem::replace(&mut self.in_root, false); + } + visit::walk_mod(self, m); + self.in_root = prev_in_root; + } + + fn visit_mac(&mut self, mac: &ast::Mac) { + visit::walk_mac(self, mac) + } +} + +// Creates a new module which looks like: +// +// mod $gensym { +// extern crate rustc_macro; +// +// use rustc_macro::__internal::Registry; +// +// #[plugin_registrar] +// fn registrar(registrar: &mut Registry) { +// registrar.register_custom_derive($name_trait1, ::$name1); +// registrar.register_custom_derive($name_trait2, ::$name2); +// // ... +// } +// } +fn mk_registrar(cx: &mut ExtCtxt, + custom_derives: &[CustomDerive]) -> P { + let eid = cx.codemap().record_expansion(ExpnInfo { + call_site: DUMMY_SP, + callee: NameAndSpan { + format: MacroAttribute(token::intern("rustc_macro")), + span: None, + allow_internal_unstable: true, + } + }); + let span = Span { expn_id: eid, ..DUMMY_SP }; + + let rustc_macro = token::str_to_ident("rustc_macro"); + let krate = cx.item(span, + rustc_macro, + Vec::new(), + ast::ItemKind::ExternCrate(None)); + + let __internal = token::str_to_ident("__internal"); + let registry = token::str_to_ident("Registry"); + let registrar = token::str_to_ident("registrar"); + let register_custom_derive = token::str_to_ident("register_custom_derive"); + let stmts = custom_derives.iter().map(|cd| { + let path = cx.path_global(cd.span, vec![cd.function_name]); + let trait_name = cx.expr_str(cd.span, cd.trait_name.clone()); + (path, trait_name) + }).map(|(path, trait_name)| { + let registrar = cx.expr_ident(span, registrar); + let ufcs_path = cx.path(span, vec![rustc_macro, __internal, registry, + register_custom_derive]); + cx.expr_call(span, + cx.expr_path(ufcs_path), + vec![registrar, trait_name, cx.expr_path(path)]) + }).map(|expr| { + cx.stmt_expr(expr) + }).collect::>(); + + let path = cx.path(span, vec![rustc_macro, __internal, registry]); + let registrar_path = cx.ty_path(path); + let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable); + let func = cx.item_fn(span, + registrar, + vec![cx.arg(span, registrar, arg_ty)], + cx.ty(span, ast::TyKind::Tup(Vec::new())), + cx.block(span, stmts)); + + let derive_registrar = token::intern_and_get_ident("rustc_derive_registrar"); + let derive_registrar = cx.meta_word(span, derive_registrar); + let derive_registrar = cx.attribute(span, derive_registrar); + let func = func.map(|mut i| { + i.attrs.push(derive_registrar); + i.vis = ast::Visibility::Public; + i + }); + let module = cx.item_mod(span, + span, + ast::Ident::with_empty_ctxt(token::gensym("registrar")), + Vec::new(), + vec![krate, func]); + module.map(|mut i| { + i.vis = ast::Visibility::Public; + i + }) +} diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index fde2f83e220f9..3377fc43d8a60 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -214,6 +214,13 @@ dependencies = [ "rustc_bitflags 0.0.0", ] +[[package]] +name = "rustc_macro" +version = "0.0.0" +dependencies = [ + "syntax 0.0.0", +] + [[package]] name = "rustc_metadata" version = "0.0.0" @@ -228,8 +235,10 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_llvm 0.0.0", + "rustc_macro 0.0.0", "serialize 0.0.0", "syntax 0.0.0", + "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] @@ -400,6 +409,7 @@ dependencies = [ "fmt_macros 0.0.0", "log 0.0.0", "rustc_errors 0.0.0", + "rustc_macro 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs new file mode 100644 index 0000000000000..fa0b5763803ff --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs @@ -0,0 +1,33 @@ +// 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. + +// aux-build:append-impl.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate append_impl; + +trait Append { + fn foo(&self); +} + +#[derive(PartialEq, + Append, + Eq)] +//~^^ ERROR: the semantics of constant patterns is not yet settled +struct A { + inner: u32, +} + +fn main() { + A { inner: 3 }.foo(); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs new file mode 100644 index 0000000000000..46724523d1c70 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs @@ -0,0 +1,25 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +pub mod a { //~ `rustc-macro` crate types cannot export any items + use rustc_macro::TokenStream; + + #[rustc_macro_derive(B)] + pub fn bar(a: TokenStream) -> TokenStream { + //~^ ERROR: must currently reside in the root of the crate + a + } +} + diff --git a/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs new file mode 100644 index 0000000000000..7740238aeacc9 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs @@ -0,0 +1,46 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +#[rustc_macro_derive] +//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] +pub fn foo1(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive = "foo"] +//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] +pub fn foo2(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive( + a = "b" +)] +//~^^ ERROR: must only be one word +pub fn foo3(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive(b, c)] +//~^ ERROR: attribute must only have one argument +pub fn foo4(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive(d(e))] +//~^ ERROR: must only be one word +pub fn foo5(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs new file mode 100644 index 0000000000000..c3d295e02c163 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs @@ -0,0 +1,31 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Append)] +pub fn derive_a(input: TokenStream) -> TokenStream { + let mut input = input.to_string(); + input.push_str(" + impl Append for A { + fn foo(&self) {} + } + "); + input.parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs new file mode 100644 index 0000000000000..ff00a9d96a30a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs @@ -0,0 +1,25 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs new file mode 100644 index 0000000000000..ff00a9d96a30a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs @@ -0,0 +1,25 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs new file mode 100644 index 0000000000000..5dd42d28b7be1 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs @@ -0,0 +1,26 @@ +// 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. + +// no-prefer-dynamic +// force-host + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(_input: TokenStream) -> TokenStream { + "struct A { inner }".parse().unwrap() +} + diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs new file mode 100644 index 0000000000000..d867082ed5e52 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs @@ -0,0 +1,25 @@ +// 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. + +// no-prefer-dynamic +// force-host + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(_input: TokenStream) -> TokenStream { + panic!("nope!"); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs new file mode 100644 index 0000000000000..9eebad897564a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs @@ -0,0 +1,29 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Unstable)] +pub fn derive(_input: TokenStream) -> TokenStream { + + " + #[rustc_foo] + fn foo() {} + ".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs new file mode 100644 index 0000000000000..f4a1ec9970067 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs @@ -0,0 +1,26 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Unstable)] +pub fn derive(_input: TokenStream) -> TokenStream { + + "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs new file mode 100644 index 0000000000000..1f135330a9995 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs @@ -0,0 +1,16 @@ +// 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. + +// aux-build:derive-a.rs + +extern crate derive_a; +//~^ ERROR: crates of the `rustc-macro` crate type cannot be linked at runtime + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs new file mode 100644 index 0000000000000..e4f21dc23840b --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs @@ -0,0 +1,28 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn foo(input: TokenStream) -> TokenStream { + input +} + +#[rustc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate +pub fn bar(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs new file mode 100644 index 0000000000000..f3a73af299357 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:derive-bad.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_bad; + +#[derive( + A +)] +//~^^ ERROR: custom derive attribute panicked +//~| HELP: called `Result::unwrap()` on an `Err` value: LexError +struct A; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs new file mode 100644 index 0000000000000..a46d79f517f7d --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.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. + +// aux-build:derive-a.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_a; + +#[derive_A] //~ ERROR: attributes of the form `#[derive_*]` are reserved for the compiler +struct A; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs new file mode 100644 index 0000000000000..29b9fd228094a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:derive-unstable-2.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_unstable_2; + +#[derive(Unstable)] +//~^ ERROR: reserved for internal compiler +struct A; + +fn main() { + foo(); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs new file mode 100644 index 0000000000000..874081760f662 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:derive-unstable.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_unstable; + +#[derive(Unstable)] +//~^ ERROR: use of unstable library feature +struct A; + +fn main() { + unsafe { foo(); } +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs new file mode 100644 index 0000000000000..759f3d32e16e6 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs @@ -0,0 +1,19 @@ +// 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. + +// error-pattern: cannot export macro_rules! macros from a `rustc-macro` crate + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +#[macro_export] +macro_rules! foo { + ($e:expr) => ($e) +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/exports.rs b/src/test/compile-fail-fulldeps/rustc-macro/exports.rs new file mode 100644 index 0000000000000..e985356dc5844 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/exports.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. + +#![crate_type = "rustc-macro"] +#![allow(warnings)] + +pub fn a() {} //~ ERROR: cannot export any items +pub struct B; //~ ERROR: cannot export any items +pub enum C {} //~ ERROR: cannot export any items +pub mod d {} //~ ERROR: cannot export any items + +mod e {} +struct F; +enum G {} +fn h() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs new file mode 100644 index 0000000000000..86afc08cae861 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs @@ -0,0 +1,13 @@ +// 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. + +// error-pattern: the `rustc-macro` crate type is experimental + +#![crate_type = "rustc-macro"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs new file mode 100644 index 0000000000000..1a19f6046d9e1 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs @@ -0,0 +1,13 @@ +// 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. + +extern crate rustc_macro; //~ ERROR: use of unstable library feature + +fn main() {} diff --git a/src/test/run-pass/single-derive-attr-with-gate.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs similarity index 68% rename from src/test/run-pass/single-derive-attr-with-gate.rs rename to src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs index addc56e9c4210..9f47f07bd023d 100644 --- a/src/test/run-pass/single-derive-attr-with-gate.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,13 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +#![crate_type = "rustc-macro"] -#![feature(custom_derive)] - -#[derive_Clone] -struct Test; - -pub fn main() { - Test.clone(); +#[rustc_macro_derive(Foo)] //~ ERROR: is an experimental feature +pub fn foo() { } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs new file mode 100644 index 0000000000000..0fdd13bc30cce --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs @@ -0,0 +1,15 @@ +// 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. + +// aux-build:derive-a.rs + +#[macro_use] +extern crate derive_a; +//~^ ERROR: loading custom derive macro crates is experimentally supported diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs new file mode 100644 index 0000000000000..e44b29a170517 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs @@ -0,0 +1,12 @@ +// 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. + +#[cfg(rustc_macro)] //~ ERROR: experimental and subject to change +fn foo() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/import.rs b/src/test/compile-fail-fulldeps/rustc-macro/import.rs new file mode 100644 index 0000000000000..c1d0823cb6b84 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/import.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. + +// aux-build:derive-a.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_a; + +use derive_a::derive_a; +//~^ ERROR: unresolved import `derive_a::derive_a` + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs new file mode 100644 index 0000000000000..0d08d27c38e46 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-panic.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_panic; + +#[derive(A)] +//~^ ERROR: custom derive attribute panicked +//~| HELP: message: nope! +struct Foo; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs new file mode 100644 index 0000000000000..cdc50acea9262 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(rustc_macro)] + +extern crate rustc_macro; + +#[rustc_macro_derive(Foo)] +//~^ ERROR: only usable with crates of the `rustc-macro` crate type +pub fn foo(a: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + a +} + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs new file mode 100644 index 0000000000000..1353a234b4836 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(PartialEq)] +//~^ ERROR: cannot override a built-in #[derive] mode +pub fn foo(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs new file mode 100644 index 0000000000000..33330ed8f6a05 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:derive-a.rs +// aux-build:derive-a-2.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_a; +#[macro_use] +extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A` + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/signature.rs b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs new file mode 100644 index 0000000000000..9662cc69e1e14 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs @@ -0,0 +1,24 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![allow(warnings)] + +extern crate rustc_macro; + +#[rustc_macro_derive(A)] +unsafe extern fn foo(a: i32, b: u32) -> u32 { + //~^ ERROR: mismatched types + //~| NOTE: expected normal fn, found unsafe fn + //~| NOTE: expected type `fn(rustc_macro::TokenStream) -> rustc_macro::TokenStream` + //~| NOTE: found type `unsafe extern "C" fn(i32, u32) -> u32 {foo}` + loop {} +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs new file mode 100644 index 0000000000000..35f6149ad4946 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs @@ -0,0 +1,14 @@ +// 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. + +// error-pattern: cannot mix `rustc-macro` crate type with others + +#![crate_type = "rustc-macro"] +#![crate_type = "rlib"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs new file mode 100644 index 0000000000000..ec95e3e4685be --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs @@ -0,0 +1,12 @@ +// 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. + +// error-pattern: cannot mix `rustc-macro` crate type with others +// compile-flags: --crate-type rlib --crate-type rustc-macro diff --git a/src/test/compile-fail/issue-32655.rs b/src/test/compile-fail/issue-32655.rs index edd7fe4a1e588..25ecd5d08626d 100644 --- a/src/test/compile-fail/issue-32655.rs +++ b/src/test/compile-fail/issue-32655.rs @@ -13,7 +13,7 @@ macro_rules! foo ( () => ( - #[derive_Clone] //~ WARN attributes of the form + #[derive_Clone] //~ ERROR attributes of the form struct T; ); ); @@ -25,9 +25,8 @@ macro_rules! bar ( foo!(); bar!( - #[derive_Clone] //~ WARN attributes of the form + #[derive_Clone] //~ ERROR attributes of the form struct S; ); -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {} diff --git a/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs new file mode 100644 index 0000000000000..226c082564ae4 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:add-impl.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate add_impl; + +#[derive(AddImpl)] +struct B; + +fn main() { + B.foo(); + foo(); + bar::foo(); +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs new file mode 100644 index 0000000000000..8aab423af0a3b --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs @@ -0,0 +1,33 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AddImpl)] +// #[cfg(rustc_macro)] +pub fn derive(input: TokenStream) -> TokenStream { + (input.to_string() + " + impl B { + fn foo(&self) {} + } + + fn foo() {} + + mod bar { pub fn foo() {} } + ").parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs new file mode 100644 index 0000000000000..4dd6ad88b757c --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs @@ -0,0 +1,27 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + assert!(input.contains("#[derive(Eq, Copy, Clone)]")); + "#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs new file mode 100644 index 0000000000000..5b85e2b2a7c4b --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs @@ -0,0 +1,26 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AToB)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert_eq!(input, "struct A;\n"); + "struct B;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs new file mode 100644 index 0000000000000..54f8dff509ab0 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs @@ -0,0 +1,26 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(CToD)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert_eq!(input, "struct C;\n"); + "struct D;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs new file mode 100644 index 0000000000000..d83e352e3b175 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs @@ -0,0 +1,32 @@ +// 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. + +// no-prefer-dynamic +// compile-flags:--crate-type rustc-macro + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AToB)] +pub fn derive1(input: TokenStream) -> TokenStream { + println!("input1: {:?}", input.to_string()); + assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n"); + "#[derive(BToC)] struct B;".parse().unwrap() +} + +#[rustc_macro_derive(BToC)] +pub fn derive2(input: TokenStream) -> TokenStream { + assert_eq!(input.to_string(), "struct B;\n"); + "struct C;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs new file mode 100644 index 0000000000000..96aea407e6e74 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs @@ -0,0 +1,36 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![deny(warnings)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + r#" + struct A; + + impl A { + fn a(&self) { + panic!("hello"); + } + } + "#.parse().unwrap() +} + diff --git a/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs new file mode 100644 index 0000000000000..ee0d594564883 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-same-struct.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_same_struct; + +#[derive(AToB, BToC)] +struct A; + +fn main() { + C; +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs new file mode 100644 index 0000000000000..cc59be2d75df3 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs @@ -0,0 +1,30 @@ +// 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. + +// aux-build:expand-with-a-macro.rs +// ignore-stage1 + +#![feature(rustc_macro)] +#![deny(warnings)] + +#[macro_use] +extern crate expand_with_a_macro; + +use std::panic; + +#[derive(A)] +struct A; + +fn main() { + assert!(panic::catch_unwind(|| { + A.a(); + }).is_err()); +} + diff --git a/src/test/run-pass-fulldeps/rustc-macro/load-two.rs b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs new file mode 100644 index 0000000000000..1500970f02dad --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs @@ -0,0 +1,30 @@ +// 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. + +// aux-build:derive-atob.rs +// aux-build:derive-ctod.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_atob; +#[macro_use] +extern crate derive_ctod; + +#[derive(AToB)] +struct A; + +#[derive(CToD)] +struct C; + +fn main() { + B; + D; +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/smoke.rs b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs new file mode 100644 index 0000000000000..588380f1140c9 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs @@ -0,0 +1,29 @@ +// 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. + +// aux-build:derive-a.rs +// ignore-stage1 + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_a; + +#[derive(Debug, PartialEq, A, Eq, Copy, Clone)] +struct A; + +fn main() { + A; + assert_eq!(A, A); + A.clone(); + let a = A; + let _c = a; + let _d = a; +} diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs index 3dffae99292c6..517033d58702d 100644 --- a/src/test/run-pass/associated-types-normalize-unifield-struct.rs +++ b/src/test/run-pass/associated-types-normalize-unifield-struct.rs @@ -11,9 +11,6 @@ // Regression test for issue #21010: Normalize associated types in // various special paths in the `type_is_immediate` function. - -// pretty-expanded FIXME #23616 - pub trait OffsetState: Sized {} pub trait Offset { type State: OffsetState; diff --git a/src/test/run-pass/builtin-superkinds-in-metadata.rs b/src/test/run-pass/builtin-superkinds-in-metadata.rs index c026ffc6d318d..3259b1cc0679e 100644 --- a/src/test/run-pass/builtin-superkinds-in-metadata.rs +++ b/src/test/run-pass/builtin-superkinds-in-metadata.rs @@ -13,8 +13,6 @@ // Tests (correct) usage of trait super-builtin-kinds cross-crate. -// pretty-expanded FIXME #23616 - extern crate trait_superkinds_in_metadata; use trait_superkinds_in_metadata::{RequiresRequiresShareAndSend, RequiresShare}; use trait_superkinds_in_metadata::RequiresCopy; diff --git a/src/test/run-pass/coherence-impl-in-fn.rs b/src/test/run-pass/coherence-impl-in-fn.rs index b0630b516407b..d7c21340afc39 100644 --- a/src/test/run-pass/coherence-impl-in-fn.rs +++ b/src/test/run-pass/coherence-impl-in-fn.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - pub fn main() { #[derive(Copy, Clone)] enum x { foo } diff --git a/src/test/run-pass/deriving-bounds.rs b/src/test/run-pass/deriving-bounds.rs index 4204d9b5c3eae..6d0a43997bc47 100644 --- a/src/test/run-pass/deriving-bounds.rs +++ b/src/test/run-pass/deriving-bounds.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #[derive(Copy, Clone)] struct Test; diff --git a/src/test/run-pass/issue-20797.rs b/src/test/run-pass/issue-20797.rs index 321ed1a3bb283..de95243665082 100644 --- a/src/test/run-pass/issue-20797.rs +++ b/src/test/run-pass/issue-20797.rs @@ -10,8 +10,6 @@ // Regression test for #20797. -// pretty-expanded FIXME #23616 - #![feature(question_mark)] use std::default::Default; diff --git a/src/test/run-pass/issue-2288.rs b/src/test/run-pass/issue-2288.rs index d16655a68554a..379715f539039 100644 --- a/src/test/run-pass/issue-2288.rs +++ b/src/test/run-pass/issue-2288.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 7fa592105c09d..45ac334dc1d76 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(warnings)] #![feature(collections)] #![feature(drain, enumset, collections_bound, btree_range, vecmap)] From 63671c495bf16dc0f9e1c97fa11af8a895b5ed24 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Sun, 28 Aug 2016 12:57:38 +0200 Subject: [PATCH 489/768] Update E0496 to new format --- src/librustc/middle/resolve_lifetime.rs | 6 ++-- src/test/compile-fail/E0496.rs | 2 ++ .../loops-reject-duplicate-labels-2.rs | 33 ++++++++--------- .../loops-reject-duplicate-labels.rs | 32 +++++++++-------- ...loops-reject-labels-shadowing-lifetimes.rs | 36 ++++++++++++------- .../loops-reject-lifetime-shadowing-label.rs | 3 +- src/test/compile-fail/shadowed-lifetime.rs | 6 ++-- 7 files changed, 69 insertions(+), 49 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ebe4050022153..747f6982ad79d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -395,9 +395,9 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha {} name that is already in scope", shadower.kind.desc(), name, orig.kind.desc())) }; - err.span_note(orig.span, - &format!("shadowed {} `{}` declared here", - orig.kind.desc(), name)); + err.span_label(orig.span, &"first declared here"); + err.span_label(shadower.span, + &format!("lifetime {} already in scope", name)); err.emit(); } diff --git a/src/test/compile-fail/E0496.rs b/src/test/compile-fail/E0496.rs index 4ca3cd9c13da6..8aeeeebcb5676 100644 --- a/src/test/compile-fail/E0496.rs +++ b/src/test/compile-fail/E0496.rs @@ -13,7 +13,9 @@ struct Foo<'a> { } impl<'a> Foo<'a> { + //~^ NOTE first declared here fn f<'a>(x: &'a i32) { //~ ERROR E0496 + //~^ NOTE lifetime 'a already in scope } } diff --git a/src/test/compile-fail/loops-reject-duplicate-labels-2.rs b/src/test/compile-fail/loops-reject-duplicate-labels-2.rs index 4a3338c4bf6c8..ca18ca3796a10 100644 --- a/src/test/compile-fail/loops-reject-duplicate-labels-2.rs +++ b/src/test/compile-fail/loops-reject-duplicate-labels-2.rs @@ -19,30 +19,31 @@ // https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833 pub fn foo() { - { 'fl: for _ in 0..10 { break; } } //~ NOTE shadowed label `'fl` declared here + { 'fl: for _ in 0..10 { break; } } //~ NOTE first declared here { 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope - - { 'lf: loop { break; } } //~ NOTE shadowed label `'lf` declared here + //~^ NOTE lifetime 'fl already in scope + { 'lf: loop { break; } } //~ NOTE first declared here { 'lf: for _ in 0..10 { break; } } //~ WARN label name `'lf` shadows a label name that is already in scope - - { 'wl: while 2 > 1 { break; } } //~ NOTE shadowed label `'wl` declared here + //~^ NOTE lifetime 'lf already in scope + { 'wl: while 2 > 1 { break; } } //~ NOTE first declared here { 'wl: loop { break; } } //~ WARN label name `'wl` shadows a label name that is already in scope - - { 'lw: loop { break; } } //~ NOTE shadowed label `'lw` declared here + //~^ NOTE lifetime 'wl already in scope + { 'lw: loop { break; } } //~ NOTE first declared here { 'lw: while 2 > 1 { break; } } //~ WARN label name `'lw` shadows a label name that is already in scope - - { 'fw: for _ in 0..10 { break; } } //~ NOTE shadowed label `'fw` declared here + //~^ NOTE lifetime 'lw already in scope + { 'fw: for _ in 0..10 { break; } } //~ NOTE first declared here { 'fw: while 2 > 1 { break; } } //~ WARN label name `'fw` shadows a label name that is already in scope - - { 'wf: while 2 > 1 { break; } } //~ NOTE shadowed label `'wf` declared here + //~^ NOTE lifetime 'fw already in scope + { 'wf: while 2 > 1 { break; } } //~ NOTE first declared here { 'wf: for _ in 0..10 { break; } } //~ WARN label name `'wf` shadows a label name that is already in scope - - { 'tl: while let Some(_) = None:: { break; } } //~ NOTE shadowed label `'tl` declared here + //~^ NOTE lifetime 'wf already in scope + { 'tl: while let Some(_) = None:: { break; } } //~ NOTE first declared here { 'tl: loop { break; } } //~ WARN label name `'tl` shadows a label name that is already in scope - - { 'lt: loop { break; } } //~ NOTE shadowed label `'lt` declared here + //~^ NOTE lifetime 'tl already in scope + { 'lt: loop { break; } } //~ NOTE first declared here { 'lt: while let Some(_) = None:: { break; } } - //~^ WARN label name `'lt` shadows a label name that is already in scope + //~^ WARN label name `'lt` shadows a label name that is already in scope + //~| NOTE lifetime 'lt already in scope } #[rustc_error] diff --git a/src/test/compile-fail/loops-reject-duplicate-labels.rs b/src/test/compile-fail/loops-reject-duplicate-labels.rs index 15446bf642d4d..31f89493896d8 100644 --- a/src/test/compile-fail/loops-reject-duplicate-labels.rs +++ b/src/test/compile-fail/loops-reject-duplicate-labels.rs @@ -16,30 +16,32 @@ // This is testing the exact cases that are in the issue description. fn foo() { - 'fl: for _ in 0..10 { break; } //~ NOTE shadowed label `'fl` declared here + 'fl: for _ in 0..10 { break; } //~ NOTE first declared here 'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope + //~^ NOTE lifetime 'fl already in scope - 'lf: loop { break; } //~ NOTE shadowed label `'lf` declared here + 'lf: loop { break; } //~ NOTE first declared here 'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope - - 'wl: while 2 > 1 { break; } //~ NOTE shadowed label `'wl` declared here + //~^ NOTE lifetime 'lf already in scope + 'wl: while 2 > 1 { break; } //~ NOTE first declared here 'wl: loop { break; } //~ WARN label name `'wl` shadows a label name that is already in scope - - 'lw: loop { break; } //~ NOTE shadowed label `'lw` declared here + //~^ NOTE lifetime 'wl already in scope + 'lw: loop { break; } //~ NOTE first declared here 'lw: while 2 > 1 { break; } //~ WARN label name `'lw` shadows a label name that is already in scope - - 'fw: for _ in 0..10 { break; } //~ NOTE shadowed label `'fw` declared here + //~^ NOTE lifetime 'lw already in scope + 'fw: for _ in 0..10 { break; } //~ NOTE first declared here 'fw: while 2 > 1 { break; } //~ WARN label name `'fw` shadows a label name that is already in scope - - 'wf: while 2 > 1 { break; } //~ NOTE shadowed label `'wf` declared here + //~^ NOTE lifetime 'fw already in scope + 'wf: while 2 > 1 { break; } //~ NOTE first declared here 'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope - - 'tl: while let Some(_) = None:: { break; } //~ NOTE shadowed label `'tl` declared here + //~^ NOTE lifetime 'wf already in scope + 'tl: while let Some(_) = None:: { break; } //~ NOTE first declared here 'tl: loop { break; } //~ WARN label name `'tl` shadows a label name that is already in scope - - 'lt: loop { break; } //~ NOTE shadowed label `'lt` declared here + //~^ NOTE lifetime 'tl already in scope + 'lt: loop { break; } //~ NOTE first declared here 'lt: while let Some(_) = None:: { break; } - //~^ WARN label name `'lt` shadows a label name that is already in scope + //~^ WARN label name `'lt` shadows a label name that is already in scope + //~| NOTE lifetime 'lt already in scope } // Note however that it is okay for the same label to be reused in diff --git a/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs b/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs index bbdd0774ed936..9a735f9c97c96 100644 --- a/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs +++ b/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs @@ -16,9 +16,10 @@ #![allow(dead_code, unused_variables)] fn foo() { - fn foo<'a>() { //~ NOTE shadowed lifetime `'a` declared here + fn foo<'a>() { //~ NOTE first declared here 'a: loop { break 'a; } //~^ WARN label name `'a` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'a already in scope } struct Struct<'b, 'c> { _f: &'b i8, _g: &'c i8 } @@ -40,76 +41,87 @@ fn foo() { } } - impl<'bad, 'c> Struct<'bad, 'c> { //~ NOTE shadowed lifetime `'bad` declared here + impl<'bad, 'c> Struct<'bad, 'c> { //~ NOTE first declared here fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - impl<'b, 'bad> Struct<'b, 'bad> { //~ NOTE shadowed lifetime `'bad` declared here + impl<'b, 'bad> Struct<'b, 'bad> { //~ NOTE first declared here fn meth_bad2(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } impl<'b, 'c> Struct<'b, 'c> { - fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) { - //~^ NOTE shadowed lifetime `'bad` declared here + //~^ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - impl <'bad, 'e> Enum<'bad, 'e> { //~ NOTE shadowed lifetime `'bad` declared here + impl <'bad, 'e> Enum<'bad, 'e> { //~ NOTE first declared here fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - impl <'d, 'bad> Enum<'d, 'bad> { //~ NOTE shadowed lifetime `'bad` declared here + impl <'d, 'bad> Enum<'d, 'bad> { //~ NOTE first declared here fn meth_bad2(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } impl <'d, 'e> Enum<'d, 'e> { - fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } - fn meth_bad4<'a,'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad4<'a,'bad>(x: &'bad i8) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - trait HasDefaultMethod1<'bad> { //~ NOTE shadowed lifetime `'bad` declared here + trait HasDefaultMethod1<'bad> { //~ NOTE first declared here fn meth_okay() { 'c: loop { break 'c; } } fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - trait HasDefaultMethod2<'a,'bad> { //~ NOTE shadowed lifetime `'bad` declared here + trait HasDefaultMethod2<'a,'bad> { //~ NOTE first declared here fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } trait HasDefaultMethod3<'a,'b> { - fn meth_bad<'bad>(&self) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad<'bad>(&self) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } } diff --git a/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs b/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs index 2344d251c9a69..0a90917d975e5 100644 --- a/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs +++ b/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs @@ -27,9 +27,10 @@ fn foo() { let z = 3_i8; - 'a: loop { //~ NOTE shadowed label `'a` declared here + 'a: loop { //~ NOTE first declared here let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; //~^ WARN lifetime name `'a` shadows a label name that is already in scope + //~| NOTE lifetime 'a already in scope assert_eq!((*b)(&z), z); break 'a; } diff --git a/src/test/compile-fail/shadowed-lifetime.rs b/src/test/compile-fail/shadowed-lifetime.rs index 8cbab5f830809..31283623a3ce6 100644 --- a/src/test/compile-fail/shadowed-lifetime.rs +++ b/src/test/compile-fail/shadowed-lifetime.rs @@ -13,16 +13,18 @@ struct Foo<'a>(&'a isize); impl<'a> Foo<'a> { - //~^ NOTE shadowed lifetime `'a` declared here + //~^ NOTE first declared here fn shadow_in_method<'a>(&'a self) -> &'a isize { //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'a already in scope self.0 } fn shadow_in_type<'b>(&'b self) -> &'b isize { - //~^ NOTE shadowed lifetime `'b` declared here + //~^ NOTE first declared here let x: for<'b> fn(&'b isize) = panic!(); //~^ ERROR lifetime name `'b` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'b already in scope self.0 } From 18434f94572ee047aff8898a0d25ee8939585827 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 2 Sep 2016 02:21:53 +0530 Subject: [PATCH 490/768] Update compiler error E0558 to use new error format Fixes #36196 part of #35233 --- src/libsyntax/attr.rs | 5 +++-- src/test/compile-fail/E0558.rs | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 703f3f7adf910..81ee96459fd64 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -438,8 +438,9 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option Date: Fri, 2 Sep 2016 19:54:02 -0400 Subject: [PATCH 491/768] indicate where to copy config.toml.example --- src/bootstrap/config.toml.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef622..9e8910669a064 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -1,5 +1,7 @@ # Sample TOML configuration file for building Rust. # +# To configure rustbuild, copy this file to ../config.toml. +# # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for # `config.toml` in the current directory of a build for build configuration, but From a34485ff1925e81702bbb46bf2a5634fa008672b Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 3 Sep 2016 02:02:03 -0400 Subject: [PATCH 492/768] change wording --- src/bootstrap/config.toml.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 9e8910669a064..20c91960e9ea5 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -1,6 +1,7 @@ # Sample TOML configuration file for building Rust. # -# To configure rustbuild, copy this file to ../config.toml. +# To configure rustbuild, copy this file to the directory from which you will be +# running the build, and name it config.toml. # # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for From 0efc4bf387f962f7ba56a9bc0179fcc72701f53c Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 3 Sep 2016 01:29:12 +0000 Subject: [PATCH 493/768] rustbuild: add config.toml option to disable codegen tests --- src/bootstrap/config.rs | 2 ++ src/bootstrap/config.toml.example | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a8..c1af7bd794cbf 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -144,6 +144,7 @@ struct Rust { rpath: Option, optimize_tests: Option, debuginfo_tests: Option, + codegen_tests: Option, } /// TOML representation of how each build target is configured. @@ -232,6 +233,7 @@ impl Config { set(&mut config.rust_optimize, rust.optimize); set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); + set(&mut config.codegen_tests, rust.codegen_tests); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef622..ef24a948664f0 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -130,6 +130,10 @@ #optimize-tests = true #debuginfo-tests = true +# Flag indicating whether codegen tests will be run or not. If you get an error +# saying that the FileCheck executable is missing, you may want to disable this. +#codegen-tests = true + # ============================================================================= # Options for specific targets # From 1db878fd38eb00daf794d87ab04cb50c7fa6e4fc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Jul 2016 00:15:15 +0300 Subject: [PATCH 494/768] Add unions to AST --- src/librustc_passes/ast_validation.rs | 10 ++++++++++ src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/macros.rs | 7 +++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index dde1a4a759563..b8284f5dcf10d 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -196,6 +196,16 @@ impl<'a> Visitor for AstValidator<'a> { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); } + ItemKind::Union(ref vdata, _) => { + if !vdata.is_struct() { + self.err_handler().span_err(item.span, + "tuple and unit unions are not permitted"); + } + if vdata.fields().len() == 0 { + self.err_handler().span_err(item.span, + "unions cannot have zero fields"); + } + } _ => {} } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fcb99444957c4..4394fb0e14312 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1886,7 +1886,7 @@ pub enum ItemKind { /// A union definition (`union` or `pub union`). /// /// E.g. `union Foo { x: A, y: B }` - Union(VariantData, Generics), // FIXME: not yet implemented + Union(VariantData, Generics), /// A Trait declaration (`trait` or `pub trait`). /// /// E.g. `trait Foo { .. }` or `trait Foo { .. }` diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 25e0428248df4..e2a7ec0a33de1 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -107,6 +107,13 @@ macro_rules! help { }) } +#[macro_export] +macro_rules! unimplemented_unions { + () => ({ + panic!("unions are not fully implemented"); + }) +} + #[macro_export] macro_rules! register_diagnostics { ($($code:tt),*) => ( From 4001c039de931f4e5ad5318b12e333ef30c52d1b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Aug 2016 21:36:28 +0300 Subject: [PATCH 495/768] Add unions to HIR --- src/librustc/hir/fold.rs | 4 ++++ src/librustc/hir/intravisit.rs | 3 ++- src/librustc/hir/map/def_collector.rs | 6 +++--- src/librustc/hir/map/mod.rs | 1 + src/librustc/hir/mod.rs | 3 +++ src/librustc/hir/print.rs | 5 ++++- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 1 + src/librustc_metadata/encoder.rs | 3 +++ src/librustc_privacy/lib.rs | 8 +++++--- src/librustc_trans/collector.rs | 5 +++-- src/librustc_typeck/collect.rs | 3 ++- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustc_typeck/variance/terms.rs | 3 ++- src/librustdoc/visit_ast.rs | 2 ++ 15 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 12bc49c10dabc..57b5599bd1d7f 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -761,6 +761,10 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { let struct_def = folder.fold_variant_data(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } + ItemUnion(struct_def, generics) => { + let struct_def = folder.fold_variant_data(struct_def); + ItemUnion(struct_def, folder.fold_generics(generics)) + } ItemDefaultImpl(unsafety, ref trait_ref) => { ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index bc1dff7c6fc31..62157b1ca3681 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -348,7 +348,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_ty(typ); walk_list!(visitor, visit_impl_item, impl_items); } - ItemStruct(ref struct_definition, ref generics) => { + ItemStruct(ref struct_definition, ref generics) | + ItemUnion(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_id(item.id); visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 77567fc7a4603..389d0a1d50d56 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -302,9 +302,9 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { let def_data = match i.node { hir::ItemDefaultImpl(..) | hir::ItemImpl(..) => DefPathData::Impl, - hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | - hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | - hir::ItemTy(..) => + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) | + hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) | + hir::ItemForeignMod(..) | hir::ItemTy(..) => DefPathData::TypeNs(i.name.as_str()), hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => DefPathData::ValueNs(i.name.as_str()), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5e14bb51ce867..3ffc95e64f5a7 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1030,6 +1030,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemTy(..) => "ty", ItemEnum(..) => "enum", ItemStruct(..) => "struct", + ItemUnion(..) => "union", ItemTrait(..) => "trait", ItemImpl(..) => "impl", ItemDefaultImpl(..) => "default impl", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 295a49d26d0fe..e16005558f82b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1483,6 +1483,8 @@ pub enum Item_ { ItemEnum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo
{x: A}` ItemStruct(VariantData, Generics), + /// A union definition, e.g. `union Foo {x: A, y: B}` + ItemUnion(VariantData, Generics), /// Represents a Trait Declaration ItemTrait(Unsafety, Generics, TyParamBounds, HirVec), @@ -1512,6 +1514,7 @@ impl Item_ { ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", + ItemUnion(..) => "union", ItemTrait(..) => "trait", ItemImpl(..) | ItemDefaultImpl(..) => "item", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 893d6708ead4b..f236bd4884d5b 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -752,7 +752,10 @@ impl<'a> State<'a> { self.head(&visibility_qualified(&item.vis, "struct"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } - + hir::ItemUnion(ref struct_def, ref generics) => { + self.head(&visibility_qualified(&item.vis, "union"))?; + self.print_struct(struct_def, generics, item.name, item.span, true)?; + } hir::ItemDefaultImpl(unsafety, ref trait_ref) => { self.head("")?; self.print_visibility(&item.vis)?; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 1f9738556d925..0625504af88ea 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemDefaultImpl(..) => {} + hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {} } } ast_map::NodeTraitItem(trait_method) => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ebe4050022153..4d1eed612cfd5 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -156,6 +156,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, _, _) | hir::ItemImpl(_, _, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index bb4cf70bd3b3e..e82742004c39f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1179,6 +1179,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { hir::ItemStruct(ref struct_def, _) => { self.encode_addl_struct_info(def_id, struct_def.id(), item); } + hir::ItemUnion(..) => { + unimplemented_unions!(); + } hir::ItemImpl(_, _, _, _, _, ref ast_items) => { self.encode_addl_impl_info(def_id, item.id, ast_items); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 41b7c51e30090..4b13d13fb7058 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -234,7 +234,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } } // Visit everything except for private fields - hir::ItemStruct(ref struct_def, ref generics) => { + hir::ItemStruct(ref struct_def, ref generics) | + hir::ItemUnion(ref struct_def, ref generics) => { if item_level.is_some() { self.reach().visit_generics(generics); for field in struct_def.fields() { @@ -1067,8 +1068,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc check.visit_foreign_item(foreign_item); } } - // Subitems of structs have their own publicity - hir::ItemStruct(ref struct_def, ref generics) => { + // Subitems of structs and unions have their own publicity + hir::ItemStruct(ref struct_def, ref generics) | + hir::ItemUnion(ref struct_def, ref generics) => { check.required_visibility = item_visibility; check.visit_generics(generics); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index c82bfa5c91ba1..bea6f30faec30 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1121,8 +1121,9 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } - hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => { + hir::ItemEnum(_, ref generics) | + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { let ty = { let tables = self.scx.tcx().tables.borrow(); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2b62e513ab27a..f2f3163dde7c7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1637,7 +1637,8 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, hir::ItemFn(_, _, _, _, ref generics, _) | hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => generics, + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) => generics, _ => &no_generics }; diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 2cf84b5745af4..888709d257246 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { debug!("visit_item item={}", tcx.map.node_to_string(item.id)); match item.node { - hir::ItemEnum(..) | hir::ItemStruct(..) => { + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { let scheme = tcx.lookup_item_type(did); // Not entirely obvious: constraints on structs/enums do not diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index c0b53787177d5..1238f7cbcb335 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -234,7 +234,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { match item.node { hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => { + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) => { self.add_inferreds_for_item(item.id, false, generics); } hir::ItemTrait(_, ref generics, _, _) => { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6af36e24d8156..e70fbf4463a22 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -365,6 +365,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.enums.push(self.visit_enum_def(item, name, ed, gen)), hir::ItemStruct(ref sd, ref gen) => om.structs.push(self.visit_variant_data(item, name, sd, gen)), + hir::ItemUnion(..) => + unimplemented_unions!(), hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) => om.fns.push(self.visit_fn(item, name, &**fd, unsafety, constness, abi, gen)), From 35d52a003bf0997d31378796bf59cc66c3ae7683 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Aug 2016 21:56:02 +0300 Subject: [PATCH 496/768] Add unions to definition map --- src/librustc/hir/def.rs | 6 ++++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc_metadata/astencode.rs | 1 + src/librustc_resolve/build_reduced_graph.rs | 21 ++++++++++++++++++++- src/librustc_save_analysis/dump_visitor.rs | 1 + src/librustc_typeck/check/mod.rs | 1 + 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index d15d51aed09a1..aa0eac37ecff1 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -41,6 +41,7 @@ pub enum Def { // If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions) // it denotes a constructor and its DefId refers to NodeId of the struct's constructor. Struct(DefId), + Union(DefId), Label(ast::NodeId), Method(DefId), Err, @@ -109,7 +110,7 @@ impl Def { Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) | Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) | + Def::TyParam(..) | Def::Struct(..) | Def::Union(..) | Def::Trait(..) | Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => { bug!("attempted .var_id() on invalid {:?}", self) @@ -121,7 +122,7 @@ impl Def { match *self { Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) | Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) | - Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) | + Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Local(id, _) | Def::Upvar(id, _, _, _) => { id @@ -147,6 +148,7 @@ impl Def { Def::TyAlias(..) => "type", Def::AssociatedTy(..) => "associated type", Def::Struct(..) => "struct", + Def::Union(..) => "union", Def::Trait(..) => "trait", Def::Method(..) => "method", Def::Const(..) => "constant", diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a74bdb02044de..b17411ced57fb 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -572,7 +572,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { id, expr_ty, def); match def { - Def::Struct(..) | Def::Variant(..) | Def::Const(..) | + Def::Struct(..) | Def::Union(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 0236f9c413ddc..9d9c6f033a960 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -416,6 +416,7 @@ impl tr for Def { Def::Upvar(did1, nid1, index, nid2) } Def::Struct(did) => Def::Struct(did.tr(dcx)), + Def::Union(did) => Def::Union(did.tr(dcx)), Def::Label(nid) => Def::Label(dcx.tr_id(nid)), Def::Err => Def::Err, } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3e9b37f0a95a7..8e97870c21a5b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -278,7 +278,19 @@ impl<'b> Resolver<'b> { self.structs.insert(item_def_id, field_names); } - ItemKind::Union(..) => panic!("`union` is not yet implemented"), + ItemKind::Union(ref vdata, _) => { + let def = Def::Union(self.definitions.local_def_id(item.id)); + self.define(parent, name, TypeNS, (def, sp, vis)); + + // Record the def ID and fields of this union. + let field_names = vdata.fields().iter().enumerate().map(|(index, field)| { + self.resolve_visibility(&field.vis); + field.ident.map(|ident| ident.name) + .unwrap_or_else(|| token::intern(&index.to_string())) + }).collect(); + let item_def_id = self.definitions.local_def_id(item.id); + self.structs.insert(item_def_id, field_names); + } ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {} @@ -461,6 +473,13 @@ impl<'b> Resolver<'b> { let fields = self.session.cstore.struct_field_names(def_id); self.structs.insert(def_id, fields); } + Def::Union(def_id) => { + let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + + // Record the def ID and fields of this union. + let fields = self.session.cstore.struct_field_names(def_id); + self.structs.insert(def_id, fields); + } Def::Struct(..) => {} Def::Local(..) | Def::PrimTy(..) | diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index dbe956f021e4c..f9a20cec42d14 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -300,6 +300,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }.lower(self.tcx)); } Def::Struct(..) | + Def::Union(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 90a9d9bffe7dc..be33f836cc6cd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4118,6 +4118,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match def { // Case 1 and 1b. Reference to a *type* or *enum variant*. Def::Struct(def_id) | + Def::Union(def_id) | Def::Variant(_, def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | From cbd912babab4b8cebe9e90a632117913ca192743 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Aug 2016 01:09:00 +0300 Subject: [PATCH 497/768] Add union types --- src/librustc/infer/freshen.rs | 1 + src/librustc/traits/coherence.rs | 3 +- src/librustc/traits/error_reporting.rs | 1 + src/librustc/traits/select.rs | 7 +- src/librustc/ty/contents.rs | 3 +- src/librustc/ty/context.rs | 4 +- src/librustc/ty/error.rs | 3 + src/librustc/ty/fast_reject.rs | 3 + src/librustc/ty/flags.rs | 2 +- src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 3 + src/librustc/ty/mod.rs | 3 +- src/librustc/ty/outlives.rs | 1 + src/librustc/ty/structural_impls.rs | 2 + src/librustc/ty/sty.rs | 6 ++ src/librustc/ty/util.rs | 5 +- src/librustc/ty/walk.rs | 1 + src/librustc/ty/wf.rs | 3 +- src/librustc/util/ppaux.rs | 5 +- src/librustc_lint/types.rs | 34 ++++++++- src/librustc_metadata/tyencode.rs | 5 ++ src/librustc_trans/collector.rs | 1 + src/librustc_trans/debuginfo/type_names.rs | 1 + src/librustc_trans/trans_item.rs | 1 + src/librustc_trans/type_of.rs | 83 +++++++++------------ src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 5 +- src/librustc_typeck/variance/constraints.rs | 3 +- src/librustdoc/clean/mod.rs | 1 + 29 files changed, 124 insertions(+), 69 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index f793d489cab06..8aeb0757f5de2 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyFnPtr(_) | ty::TyTrait(..) | ty::TyStruct(..) | + ty::TyUnion(..) | ty::TyClosure(..) | ty::TyNever | ty::TyTuple(..) | diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index a5a415dd27c65..f856e110ea2a5 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -261,7 +261,8 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> } ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) => { def.did.is_local() } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 6d6d7c2b3ba0a..95e83d404a74c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -166,6 +166,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyParam(..) => Some(14), ty::TyAnon(..) => Some(15), ty::TyNever => Some(16), + ty::TyUnion(..) => Some(17), ty::TyInfer(..) | ty::TyError => None } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 0573f0c5bbaa0..f8f10d9c26541 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1780,7 +1780,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.last().into_iter().cloned().collect())) } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | + ty::TyEnum(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where(ty::Binder(match sized_crit.sty { @@ -1836,7 +1837,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.to_vec())) } - ty::TyStruct(..) | ty::TyEnum(..) | + ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { // Fallback to whatever user-defined impls exist in this case. None @@ -1933,7 +1934,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { substs.types().collect() } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { def.all_fields() .map(|f| f.ty(self.tcx(), substs)) .collect() diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 53bf046d6b597..d7d4693c1165f 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -224,7 +224,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | + ty::TyEnum(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { TypeContents::union(&v.fields, |f| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 725bbf6adfd42..8dd7bc562d7c1 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1032,8 +1032,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, - TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); + TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait, + TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len()); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 3d60d326b2b0f..0e33e396f7e18 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -247,6 +247,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyStruct(def, _) => { format!("struct `{}`", tcx.item_path_str(def.did)) } + ty::TyUnion(def, _) => { + format!("union `{}`", tcx.item_path_str(def.did)) + } ty::TyClosure(..) => "closure".to_string(), ty::TyTuple(_) => "tuple".to_string(), ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index f7472d611befe..23678d1e37742 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -66,6 +66,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyStruct(def, _) => { Some(StructSimplifiedType(def.did)) } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyRef(_, mt) => { // since we introduce auto-refs during method lookup, we // just treat &T and T as equivalent from the point of diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 1afd49ab47fbf..ce6e4d6516ec6 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -102,7 +102,7 @@ impl FlagComputation { } } - &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => { + &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => { self.add_substs(substs); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 62bd30e255592..42ec2b18fb022 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -320,6 +320,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn characteristic_def_id_of_type(ty: Ty) -> Option { match ty.sty { ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) | ty::TyEnum(adt_def, _) => Some(adt_def.did), ty::TyTrait(ref data) => Some(data.principal.def_id()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1ede8545e08e8..622966ca5aba6 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -896,6 +896,9 @@ impl<'a, 'gcx, 'tcx> Layout { non_zero: Some(def.did) == tcx.lang_items.non_zero() } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyEnum(def, substs) => { let hint = *tcx.lookup_repr_hints(def.did).get(0) .unwrap_or(&attr::ReprAny); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e9c01f5bad66e..ddf25538ee4d0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1421,6 +1421,7 @@ bitflags! { const IS_PHANTOM_DATA = 1 << 3, const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 5, + const IS_UNION = 1 << 7, } } @@ -1818,7 +1819,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } } - TyEnum(adt, substs) | TyStruct(adt, substs) => { + TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => { // recursive case let adt = tcx.lookup_adt_def_master(adt.did); adt.calculate_sized_constraint_inner(tcx, stack); diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 4d5b38212f600..a7bb0374b75bf 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyNever | // ... ty::TyEnum(..) | // OutlivesNominalType ty::TyStruct(..) | // OutlivesNominalType + ty::TyUnion(..) | // OutlivesNominalType ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index ad3769605abd9..952641f6832f9 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -495,6 +495,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)), + ty::TyUnion(did, substs) => ty::TyUnion(did, substs.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -524,6 +525,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), + ty::TyUnion(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0e3f18c4474ea..b023cdad9ee23 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -120,6 +120,11 @@ pub enum TypeVariants<'tcx> { /// See warning about substitutions for enumerated types. TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// A union type, defined with `union`. + /// + /// See warning about substitutions for enumerated types. + TyUnion(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly /// move the contents of a box out of that box, and methods of any type @@ -1227,6 +1232,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } TyEnum(_, substs) | TyStruct(_, substs) | + TyUnion(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 77d16287fedc6..971fc2cee804f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -430,6 +430,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), TyStruct(d, _) | + TyUnion(d, _) | TyEnum(d, _) => self.def_id(d.did), TyArray(_, n) => self.hash(n), TyRawPtr(m) | @@ -558,7 +559,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { }) => Some(true), TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | TyAnon(..) | + TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span)); @@ -598,7 +599,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyStr | TyTrait(..) | TySlice(_) => Some(false), - TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | + TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyAnon(..) | TyError => None }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span)); diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 409f5a85997bd..cea3bd6348dbe 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -95,6 +95,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { } ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | + ty::TyUnion(_, ref substs) | ty::TyAnon(_, ref substs) => { stack.extend(substs.types().rev()); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index aef646a7aacaf..599e2be4db247 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -337,7 +337,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { + ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) => { // WfNominalType let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 7e2cc2938ca9e..d0e02f2e8acdd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use hir::def_id::DefId; use ty::subst::{self, Subst, Substs}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use ty::{TyBool, TyChar, TyStruct, TyEnum}; +use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::TyClosure; @@ -869,7 +868,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyEnum(def, substs) | TyStruct(def, substs) => { + TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && !tcx.tcache.borrow().contains_key(&def.did) { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 40e78c007ccfd..54cec3fd7e135 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -377,7 +377,8 @@ enum FfiResult { FfiSafe, FfiUnsafe(&'static str), FfiBadStruct(DefId, &'static str), - FfiBadEnum(DefId, &'static str) + FfiBadUnion(DefId, &'static str), + FfiBadEnum(DefId, &'static str), } /// Check if this enum can be safely exported based on the @@ -452,12 +453,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } } } FfiSafe } + ty::TyUnion(def, substs) => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found union without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } + + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + } + } + FfiSafe + } ty::TyEnum(def, substs) => { if def.variants.is_empty() { // Empty enums are okay... although sort of useless. @@ -507,7 +528,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } } } @@ -614,6 +635,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { &format!("found non-foreign-function-safe member in \ struct marked #[repr(C)]: {}", s)); } + FfiResult::FfiBadUnion(_, s) => { + // FIXME: This diagnostic is difficult to read, and doesn't + // point at the relevant field. + self.cx.span_lint(IMPROPER_CTYPES, sp, + &format!("found non-foreign-function-safe member in \ + union marked #[repr(C)]: {}", s)); + } FfiResult::FfiBadEnum(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant variant. diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 954ca878c01ef..b334a21c07c7a 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -170,6 +170,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx enc_substs(w, cx, substs); write!(w, "]"); } + ty::TyUnion(def, substs) => { + write!(w, "u[{}|", (cx.ds)(cx.tcx, def.did)); + enc_substs(w, cx, substs); + write!(w, "]"); + } ty::TyClosure(def, substs) => { write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, substs.func_substs); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index bea6f30faec30..47b3bb36cb930 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -798,6 +798,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, /* nothing to do */ } ty::TyStruct(ref adt_def, substs) | + ty::TyUnion(ref adt_def, substs) | ty::TyEnum(ref adt_def, substs) => { for field in adt_def.all_fields() { let field_type = monomorphize::apply_param_substs(scx, diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index f757578e6954d..bd839243e201f 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -45,6 +45,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8a0f37230c8df..deef0b09a17b0 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -397,6 +397,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), ty::TyStruct(adt_def, substs) | + ty::TyUnion(adt_def, substs) | ty::TyEnum(adt_def, substs) => { push_item_name(tcx, adt_def.did, output); push_type_params(tcx, substs, &[], output); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6605d12e2e127..d5d8f049681da 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -89,27 +89,23 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::nil(cx) } - ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => { - let repr = adt::represent_type(cx, t); - adt::sizing_type_of(cx, &repr, false) + ty::TyStruct(..) if t.is_simd() => { + let e = t.simd_type(cx.tcx()); + if !e.is_machine() { + cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + t, e)) + } + let llet = type_of(cx, e); + let n = t.simd_size(cx.tcx()) as u64; + ensure_array_fits_in_address_space(cx, llet, n, t); + Type::vector(&llet, n) } - ty::TyStruct(..) => { - if t.is_simd() { - let e = t.simd_type(cx.tcx()); - if !e.is_machine() { - cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - t, e)) - } - let llet = type_of(cx, e); - let n = t.simd_size(cx.tcx()) as u64; - ensure_array_fits_in_address_space(cx, llet, n, t); - Type::vector(&llet, n) - } else { - let repr = adt::represent_type(cx, t); - adt::sizing_type_of(cx, &repr, false) - } + ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) | + ty::TyEnum(..) | ty::TyClosure(..) => { + let repr = adt::represent_type(cx, t); + adt::sizing_type_of(cx, &repr, false) } ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | @@ -244,15 +240,6 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TyUint(t) => Type::uint_from_ty(cx, t), ty::TyFloat(t) => Type::float_from_ty(cx, t), ty::TyNever => Type::nil(cx), - ty::TyEnum(def, ref substs) => { - // Only create the named struct, but don't fill it in. We - // fill it in *after* placing it into the type cache. This - // avoids creating more than one copy of the enum when one - // of the enum's variants refers to the enum itself. - let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, def.did, substs); - adt::incomplete_type_of(cx, &repr, &name[..]) - } ty::TyClosure(..) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. @@ -307,26 +294,28 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); adt::type_of(cx, &repr) } - ty::TyStruct(def, ref substs) => { - if t.is_simd() { - let e = t.simd_type(cx.tcx()); - if !e.is_machine() { - cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - t, e)) - } - let llet = in_memory_type_of(cx, e); - let n = t.simd_size(cx.tcx()) as u64; - ensure_array_fits_in_address_space(cx, llet, n, t); - Type::vector(&llet, n) - } else { - // Only create the named struct, but don't fill it in. We fill it - // in *after* placing it into the type cache. This prevents - // infinite recursion with recursive struct types. - let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, def.did, substs); - adt::incomplete_type_of(cx, &repr, &name[..]) + ty::TyStruct(..) if t.is_simd() => { + let e = t.simd_type(cx.tcx()); + if !e.is_machine() { + cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + t, e)) } + let llet = in_memory_type_of(cx, e); + let n = t.simd_size(cx.tcx()) as u64; + ensure_array_fits_in_address_space(cx, llet, n, t); + Type::vector(&llet, n) + } + ty::TyStruct(def, ref substs) | + ty::TyUnion(def, ref substs) | + ty::TyEnum(def, ref substs) => { + // Only create the named struct, but don't fill it in. We + // fill it in *after* placing it into the type cache. This + // avoids creating more than one copy of the enum when one + // of the enum's variants refers to the enum itself. + let repr = adt::represent_type(cx, t); + let name = llvm_type_name(cx, def.did, substs); + adt::incomplete_type_of(cx, &repr, &name[..]) } ty::TyInfer(..) | diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 3a6076774330d..b73b8b9988766 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -439,7 +439,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; for variant in &def.variants { for field in variant.fields.iter() { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f743ef2187561..a20195bd801d9 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -24,7 +24,7 @@ use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyStruct, TyTrait, TyNever, TyTuple}; +use rustc::ty::{TyRef, TyStruct, TyUnion, TyTrait, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; @@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { match ty.sty { TyEnum(def, _) | - TyStruct(def, _) => { + TyStruct(def, _) | + TyUnion(def, _) => { Some(def.did) } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 888709d257246..e20e74be67cd3 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -344,7 +344,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { + ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) => { let item_type = self.tcx().lookup_item_type(def.did); // This edge is actually implied by the call to diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e4b6a30d5bcb3..92bb265ca995a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1801,6 +1801,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), + ty::TyUnion(..) => unimplemented_unions!(), ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; From a014323e456c00f93134d03b4af95844b2ed4b95 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 9 Aug 2016 01:18:47 +0300 Subject: [PATCH 498/768] Lower unions from AST to HIR and from HIR to types Parse union items and add a feature for them --- src/librustc/hir/lowering.rs | 5 ++++- src/librustc/ty/context.rs | 5 +++++ src/librustc/ty/mod.rs | 10 +++++++--- src/librustc_privacy/lib.rs | 2 +- src/librustc_typeck/check/dropck.rs | 3 ++- src/librustc_typeck/collect.rs | 10 ++++++++++ src/libsyntax/feature_gate.rs | 9 +++++++++ src/libsyntax/parse/parser.rs | 31 +++++++++++++++++++++++++++++ 8 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6739d3f662ac6..80e034721d63f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -638,7 +638,10 @@ impl<'a> LoweringContext<'a> { let struct_def = self.lower_variant_data(struct_def); hir::ItemStruct(struct_def, self.lower_generics(generics)) } - ItemKind::Union(..) => panic!("`union` is not yet implemented"), + ItemKind::Union(ref vdata, ref generics) => { + let vdata = self.lower_variant_data(vdata); + hir::ItemUnion(vdata, self.lower_generics(generics)) + } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), self.lower_trait_ref(trait_ref)) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 8dd7bc562d7c1..0fc1641d31f70 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1321,6 +1321,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyStruct(def, substs)) } + pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + self.mk_ty(TyUnion(def, substs)) + } + pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ddf25538ee4d0..4cda74911138e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1514,7 +1514,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum AdtKind { Struct, Enum } +pub enum AdtKind { Struct, Union, Enum } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum VariantKind { Struct, Tuple, Unit } @@ -1545,8 +1545,10 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { if Some(did) == tcx.lang_items.phantom_data() { flags = flags | AdtFlags::IS_PHANTOM_DATA; } - if let AdtKind::Enum = kind { - flags = flags | AdtFlags::IS_ENUM; + match kind { + AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, + AdtKind::Union => flags = flags | AdtFlags::IS_UNION, + AdtKind::Struct => {} } AdtDefData { did: did, @@ -1569,6 +1571,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn adt_kind(&self) -> AdtKind { if self.flags.get().intersects(AdtFlags::IS_ENUM) { AdtKind::Enum + } else if self.flags.get().intersects(AdtFlags::IS_UNION) { + AdtKind::Union } else { AdtKind::Struct } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4b13d13fb7058..cd2eb4d2b58bd 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -383,7 +383,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { - if def.adt_kind() == ty::AdtKind::Struct && + if def.adt_kind() != ty::AdtKind::Enum && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private", field.name, self.tcx.item_path_str(def.did)) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index b73b8b9988766..bd47ff0b00b7b 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -304,7 +304,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( tcx.item_path_str(def_id), variant), ty::AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)) + tcx.item_path_str(def_id)), + ty::AdtKind::Union => unimplemented_unions!(), }; span_note!( &mut err, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f2f3163dde7c7..7f9de2becee6e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1069,6 +1069,16 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, adt } +fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + it: &hir::Item, + def: &hir::VariantData) + -> ty::AdtDefMaster<'tcx> +{ + let did = ccx.tcx.map.local_def_id(it.id); + let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; + ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants) +} + fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) -> Option { debug!("disr expr, checking {}", pprust::expr_to_string(e)); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 683d5277359e8..b40124bd7741a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -292,6 +292,9 @@ declare_features! ( // Macros 1.1 (active, rustc_macro, "1.13.0", Some(35900)), + + // Allows untagged unions `union U { ... }` + (active, untagged_unions, "1.13.0", Some(32836)), ); declare_features! ( @@ -953,6 +956,12 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } } + ast::ItemKind::Union(..) => { + gate_feature_post!(&self, untagged_unions, + i.span, + "unions are unstable and not fully implemented"); + } + ast::ItemKind::DefaultImpl(..) => { gate_feature_post!(&self, optin_builtin_traits, i.span, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 92ec0fdb3de31..290a59cf1e591 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5102,6 +5102,25 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Struct(vdata, generics), None)) } + /// Parse union Foo { ... } + fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { + let class_name = self.parse_ident()?; + let mut generics = self.parse_generics()?; + + let vdata = if self.token.is_keyword(keywords::Where) { + generics.where_clause = self.parse_where_clause()?; + VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) + } else if self.token == token::OpenDelim(token::Brace) { + VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) + } else { + let token_str = self.this_token_to_string(); + return Err(self.fatal(&format!("expected `where` or `{{` after union \ + name, found `{}`", token_str))) + }; + + Ok((class_name, ItemKind::Union(vdata, generics), None)) + } + pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec> { let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { @@ -5938,6 +5957,18 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + if self.eat_keyword(keywords::Union) { + // UNION ITEM + let (ident, item_, extra_attrs) = self.parse_item_union()?; + let last_span = self.last_span; + let item = self.mk_item(lo, + last_span.hi, + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility) } From 641d8e9e4c12b3753cf4e2a9ac901ad08ea90e00 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 10 Aug 2016 21:00:17 +0300 Subject: [PATCH 499/768] Some better support for unions through the compiler --- src/librustc/hir/check_attr.rs | 13 +++-- src/librustc/hir/map/def_collector.rs | 3 +- src/librustc/infer/error_reporting.rs | 4 +- src/librustc/middle/dead.rs | 20 ++++---- src/librustc/middle/expr_use_visitor.rs | 51 +++++++++++-------- src/librustc/middle/stability.rs | 9 ++-- src/librustc/traits/coherence.rs | 2 +- src/librustc/traits/error_reporting.rs | 1 + src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 3 ++ src/librustc/ty/mod.rs | 10 ++-- src/librustc/ty/relate.rs | 7 +++ src/librustc/ty/sty.rs | 7 +-- src/librustc/ty/util.rs | 17 ++++--- src/librustc_borrowck/borrowck/check_loans.rs | 4 +- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 1 + .../borrowck/mir/elaborate_drops.rs | 4 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 7 +-- src/librustc_const_eval/eval.rs | 3 +- src/librustc_driver/test.rs | 1 + .../calculate_svh/svh_visitor.rs | 1 + src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 17 +++++-- src/librustc_lint/unused.rs | 1 + src/librustc_mir/hair/cx/expr.rs | 5 +- src/librustc_mir/hair/cx/pattern.rs | 7 ++- src/librustc_mir/transform/type_check.rs | 4 +- src/librustc_passes/consts.rs | 1 + src/librustc_privacy/lib.rs | 10 ++-- src/librustc_resolve/lib.rs | 5 +- src/librustc_save_analysis/lib.rs | 5 +- src/librustc_trans/adt.rs | 3 ++ src/librustc_trans/collector.rs | 1 + src/librustc_trans/common.rs | 6 +-- src/librustc_trans/debuginfo/metadata.rs | 7 +++ src/librustc_trans/glue.rs | 3 ++ src/librustc_trans/type_of.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/dropck.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 51 ++++++++++--------- src/librustc_typeck/check/mod.rs | 45 +++++++++------- src/librustc_typeck/check/wfcheck.rs | 3 ++ src/librustc_typeck/coherence/mod.rs | 3 +- src/librustc_typeck/coherence/orphan.rs | 7 ++- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/collect.rs | 3 +- src/librustc_typeck/variance/constraints.rs | 1 + 51 files changed, 243 insertions(+), 134 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 53624702c848b..a2d4239388ace 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -18,6 +18,7 @@ use syntax::visit::Visitor; enum Target { Fn, Struct, + Union, Enum, Other, } @@ -27,6 +28,7 @@ impl Target { match item.node { ast::ItemKind::Fn(..) => Target::Fn, ast::ItemKind::Struct(..) => Target::Struct, + ast::ItemKind::Union(..) => Target::Union, ast::ItemKind::Enum(..) => Target::Enum, _ => Target::Other, } @@ -62,8 +64,10 @@ impl<'a> CheckAttrVisitor<'a> { let message = match &*name { "C" => { conflicting_reprs += 1; - if target != Target::Struct && target != Target::Enum { - "attribute should be applied to struct or enum" + if target != Target::Struct && + target != Target::Union && + target != Target::Enum { + "attribute should be applied to struct, enum or union" } else { continue } @@ -71,8 +75,9 @@ impl<'a> CheckAttrVisitor<'a> { "packed" => { // Do not increment conflicting_reprs here, because "packed" // can be used to modify another repr hint - if target != Target::Struct { - "attribute should be applied to struct" + if target != Target::Struct && + target != Target::Union { + "attribute should be applied to struct or union" } else { continue } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 389d0a1d50d56..29fb19fd42152 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -331,7 +331,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { }); } } - hir::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { // If this is a tuple-like struct, register the constructor. if !struct_def.is_struct() { this.create_def(struct_def.id(), diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 0cd39882b7cde..efce0c8354bac 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -105,6 +105,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match item.node { hir::ItemImpl(..) => "impl", hir::ItemStruct(..) => "struct", + hir::ItemUnion(..) => "union", hir::ItemEnum(..) => "enum", hir::ItemTrait(..) => "trait", hir::ItemFn(..) => "function body", @@ -1370,7 +1371,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { } hir::TyPath(ref maybe_qself, ref path) => { match self.tcx.expect_def(cur_ty.id) { - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { + Def::Enum(did) | Def::TyAlias(did) | + Def::Struct(did) | Def::Union(did) => { let generics = self.tcx.lookup_generics(did); let expected = diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 824383b11afcb..9a63ad4b9859e 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_definition(&mut self, id: ast::NodeId) { - use ty::TypeVariants::{TyEnum, TyStruct}; + use ty::TypeVariants::{TyEnum, TyStruct, TyUnion}; let def = self.tcx.expect_def(id); @@ -96,7 +96,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { match substs.substs.type_at(0).sty { - TyEnum(tyid, _) | TyStruct(tyid, _) => { + TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => { self.check_def_id(tyid.did) } _ => {} @@ -132,10 +132,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { - if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.insert_def_id(def.struct_variant().field_named(name).did); - } else { - span_bug!(lhs.span, "named field access on non-struct") + match self.tcx.expr_ty_adjusted(lhs).sty { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + self.insert_def_id(def.struct_variant().field_named(name).did); + } + _ => span_bug!(lhs.span, "named field access on non-struct"), } } @@ -148,7 +149,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { let variant = match self.tcx.node_id_to_type(lhs.id).sty { - ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => { + ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } _ => span_bug!(lhs.span, "non-ADT in struct pattern") @@ -185,7 +186,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match *node { ast_map::NodeItem(item) => { match item.node { - hir::ItemStruct(..) => { + hir::ItemStruct(..) | hir::ItemUnion(..) => { self.struct_has_extern_repr = item.attrs.iter().any(|attr| { attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr) .contains(&attr::ReprExtern) @@ -423,7 +424,8 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { | hir::ItemConst(..) | hir::ItemFn(..) | hir::ItemEnum(..) - | hir::ItemStruct(..) => true, + | hir::ItemStruct(..) + | hir::ItemUnion(..) => true, _ => false }; let ctor_id = get_struct_ctor_id(item); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 798702e6fd657..7214049f6cd64 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -672,30 +672,36 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - if let ty::TyStruct(def, substs) = with_cmt.ty.sty { - // Consume those fields of the with expression that are needed. - for with_field in &def.struct_variant().fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field( - &*with_expr, - with_cmt.clone(), - with_field.name, - with_field.ty(self.tcx(), substs) - ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + match with_cmt.ty.sty { + ty::TyStruct(def, substs) => { + // Consume those fields of the with expression that are needed. + for with_field in &def.struct_variant().fields { + if !contains_field_named(with_field, fields) { + let cmt_field = self.mc.cat_field( + &*with_expr, + with_cmt.clone(), + with_field.name, + with_field.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + } } } - } else { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - span_bug!( - with_expr.span, - "with expression doesn't evaluate to a struct"); + ty::TyUnion(..) => { + unimplemented_unions!(); } - }; + _ => { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + span_bug!( + with_expr.span, + "with expression doesn't evaluate to a struct"); + } + } + } // walk the with expression so that complex expressions // are properly handled. @@ -1012,7 +1018,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); delegate.matched_pat(pat, downcast_cmt, match_mode); } - Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => { + Some(Def::Struct(..)) | Some(Def::Union(..)) | + Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => { debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); delegate.matched_pat(pat, cmt_pat, match_mode); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c20fcc3fe1dc6..e6979c2545330 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -561,7 +561,9 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did, + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + def.struct_variant().field_named(field.node).did + } _ => span_bug!(e.span, "stability::check_expr: named field access on non-struct") } @@ -579,7 +581,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprStruct(_, ref expr_fields, _) => { let type_ = tcx.expr_ty(e); match type_.sty { - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { // check the stability of each field that appears // in the construction expression. for field in expr_fields { @@ -647,7 +649,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, if is_internal(tcx, pat.span) { return; } let v = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(), + Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) | + Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(), Some(_) | None => return, }; match pat.node { diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index f856e110ea2a5..0a7d3e6e76d8f 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -224,7 +224,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) => + ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => def.is_fundamental(), ty::TyTrait(ref data) => tcx.has_attr(data.principal.def_id(), "fundamental"), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 95e83d404a74c..e5ebe96932d4f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match (type_category(a), type_category(b)) { (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) | + (&ty::TyUnion(def_a, _), &ty::TyUnion(def_b, _)) | (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) => def_a == def_b, _ => cat_a == cat_b diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 42ec2b18fb022..ba8d332850925 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -263,6 +263,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // anything other than a simple path. match self_ty.sty { ty::TyStruct(adt_def, substs) | + ty::TyUnion(adt_def, substs) | ty::TyEnum(adt_def, substs) => { if substs.types().next().is_none() { // ignore regions self.push_item_path(buffer, adt_def.did); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 622966ca5aba6..ac5e3c6fa7009 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1256,6 +1256,9 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. if def.variants.is_empty() || def.variants.len() > 2 { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4cda74911138e..ee2188e8e112c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -948,6 +948,7 @@ impl<'tcx> TraitPredicate<'tcx> { .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) | ty::TyEnum(adt_def, _) => Some(adt_def.did), _ => @@ -1341,6 +1342,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } hir::ItemEnum(..) | hir::ItemStruct(..) | + hir::ItemUnion(..) | hir::ItemTy(..) | hir::ItemImpl(..) | hir::ItemConst(..) | @@ -1615,7 +1617,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { /// Asserts this is a struct and returns the struct's unique /// variant. pub fn struct_variant(&self) -> &VariantDefData<'gcx, 'container> { - assert_eq!(self.adt_kind(), AdtKind::Struct); + let adt_kind = self.adt_kind(); + assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union); &self.variants[0] } @@ -1674,7 +1677,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> { match def { Def::Variant(_, vid) => self.variant_with_id(vid), - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), + Def::Struct(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), _ => bug!("unexpected def {:?} in variant_of_def", def) } } @@ -2413,7 +2417,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Def::Variant(enum_did, did) => { self.lookup_adt_def(enum_did).variant_with_id(did) } - Def::Struct(did) => { + Def::Struct(did) | Def::Union(did) => { self.lookup_adt_def(did).struct_variant() } _ => bug!("expect_variant_def used with unexpected def {:?}", def) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 5c157ff32e7bb..dfae19487b6f0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -447,6 +447,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_struct(a_def, substs)) } + (&ty::TyUnion(a_def, a_substs), &ty::TyUnion(b_def, b_substs)) + if a_def == b_def => + { + let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; + Ok(tcx.mk_union(a_def, substs)) + } + (&ty::TyClosure(a_id, a_substs), &ty::TyClosure(b_id, b_substs)) if a_id == b_id => diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b023cdad9ee23..165f86fbef538 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -922,7 +922,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { - TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), + TyEnum(def, _) | TyStruct(def, _) | TyUnion(def, _) => def.is_empty(), // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested // and they don't break anything. But I'm keeping my changes small for now. @@ -985,7 +985,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_structural(&self) -> bool { match self.sty { - TyStruct(..) | TyTuple(_) | TyEnum(..) | + TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) | TyArray(..) | TyClosure(..) => true, _ => self.is_slice() | self.is_trait() } @@ -1204,6 +1204,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { match self.sty { TyTrait(ref tt) => Some(tt.principal.def_id()), TyStruct(def, _) | + TyUnion(def, _) | TyEnum(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None @@ -1212,7 +1213,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_adt_def(&self) -> Option> { match self.sty { - TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), + TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt), _ => None } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 971fc2cee804f..ad209094600ae 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -138,7 +138,7 @@ impl<'tcx> ParameterEnvironment<'tcx> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| { let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) => { + ty::TyStruct(struct_def, substs) | ty::TyUnion(struct_def, substs) => { for field in struct_def.all_fields() { let field_ty = field.ty(tcx, substs); if infcx.type_moves_by_default(field_ty, span) { @@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { for field in def.all_fields() { let field_ty = field.ty(self, substs); if let TyError = field_ty.sty { @@ -203,7 +203,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { i: usize, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { + (&TyStruct(def, substs), None) | + (&TyUnion(def, substs), None) => { def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) } (&TyEnum(def, substs), Some(vid)) => { @@ -225,7 +226,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { n: Name, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { + (&TyStruct(def, substs), None) | + (&TyUnion(def, substs), None) => { def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) } (&TyEnum(def, substs), Some(vid)) => { @@ -661,7 +663,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(tcx, sp, seen, ty) } - TyStruct(def, substs) | TyEnum(def, substs) => { + TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => { find_nonrepresentable(tcx, sp, seen, @@ -678,7 +680,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { match ty.sty { - TyStruct(ty_def, _) | TyEnum(ty_def, _) => { + TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => { ty_def == def } _ => false @@ -688,6 +690,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | + (&TyUnion(did_a, ref substs_a), &TyUnion(did_b, ref substs_b)) | (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { if did_a != did_b { return false; @@ -710,7 +713,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("is_type_structurally_recursive: {:?}", ty); match ty.sty { - TyStruct(def, _) | TyEnum(def, _) => { + TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index e86fa9a05f372..b4c6689c24b9e 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -796,7 +796,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) | + ty::TyEnum(def, _) if def.has_dtor() => { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 9431dcdbcac8e..3cf02fc85a463 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -178,7 +178,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { - ty::TyStruct(def, _) | ty::TyEnum(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { if def.has_dtor() { Some(cmt.clone()) } else { diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index fc17633d63b93..61c85e393d2dd 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -149,6 +149,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 885bbe856c8fb..c5d1034537989 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,7 +709,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { self.open_drop_for_adt(c, def, substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -893,7 +893,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, _) | ty::TyEnum(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { if def.has_dtor() { self.tcx.sess.span_warn( c.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 887c7deb86be0..be408e2db5c34 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -261,7 +261,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", lv, ty); true diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e71a780dd89bc..de28cbb7c9c96 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -566,7 +566,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pat = match left_ty.sty { ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { + ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { let v = ctor.variant_for_adt(adt); match v.kind { VariantKind::Struct => { @@ -792,7 +792,8 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => match cx.tcx.expect_def(pat.id) { Def::Variant(_, id) => vec![Variant(id)], - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], + Def::Struct(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], Def::Const(..) | Def::AssociatedConst(..) => span_bug!(pat.span, "const pattern should've been rewritten"), def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def), @@ -836,7 +837,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us _ => bug!() }, ty::TyRef(..) => 1, - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { + ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { ctor.variant_for_adt(adt).fields.len() } ty::TyArray(_, n) => n, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index d71add3258fbd..81fe19812ca47 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -258,7 +258,8 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, format!("floating point constants cannot be used in patterns")); } ty::TyEnum(adt_def, _) | - ty::TyStruct(adt_def, _) => { + ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) => { if !tcx.has_attr(adt_def.did, "structural_match") { tcx.sess.add_lint( lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 460a6e68a5c5a..9f5f82c144ccd 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -220,6 +220,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | + hir::ItemUnion(..) | hir::ItemTrait(..) | hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c1158dc2d5fe9..d4a3ab59f9cb3 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -419,6 +419,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::AssociatedTy(..) | Def::TyParam(..) | Def::Struct(..) | + Def::Union(..) | Def::Trait(..) | Def::Method(..) | Def::Const(..) | diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 0e130c3bb66bf..1094d0ee12bbd 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -111,7 +111,7 @@ impl LateLintPass for NonCamelCaseTypes { } match it.node { - hir::ItemTy(..) | hir::ItemStruct(..) => { + hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { self.check_case(cx, "type", it.name, it.span) } hir::ItemTrait(..) => { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a103386e2c980..571d1222baaa4 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -116,7 +116,8 @@ impl LateLintPass for BoxPointers { hir::ItemFn(..) | hir::ItemTy(..) | hir::ItemEnum(..) | - hir::ItemStruct(..) => + hir::ItemStruct(..) | + hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)), _ => () @@ -124,7 +125,8 @@ impl LateLintPass for BoxPointers { // If it's a struct, we also have to check the fields' types match it.node { - hir::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { for struct_field in struct_def.fields() { self.check_heap_type(cx, struct_field.span, cx.tcx.node_id_to_type(struct_field.id)); @@ -348,6 +350,7 @@ impl LateLintPass for MissingDoc { hir::ItemMod(..) => "a module", hir::ItemEnum(..) => "an enum", hir::ItemStruct(..) => "a struct", + hir::ItemUnion(..) => "a union", hir::ItemTrait(_, _, _, ref items) => { // Issue #11592, traits are always considered exported, even when private. if it.vis == hir::Visibility::Inherited { @@ -467,6 +470,14 @@ impl LateLintPass for MissingCopyImplementations { let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx))) } + hir::ItemUnion(_, ref ast_generics) => { + if ast_generics.is_parameterized() { + return; + } + let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); + (def, cx.tcx.mk_union(def, + cx.tcx.mk_substs(Substs::empty()))) + } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; @@ -523,7 +534,7 @@ impl LateLintPass for MissingDebugImplementations { } match item.node { - hir::ItemStruct(..) | hir::ItemEnum(..) => {}, + hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {}, _ => return, } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 924b768958d69..44f1cf7b53356 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -137,6 +137,7 @@ impl LateLintPass for UnusedResults { ty::TyNever => return, ty::TyBool => return, ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) => { let attrs = cx.tcx.get_attrs(def.did); check_must_use(cx, &attrs[..], s.span) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6e8a5771eea94..0469d44de4ba6 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -477,6 +477,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }) } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyEnum(adt, substs) => { match cx.tcx.expect_def(expr.id) { Def::Variant(enum_id, variant_id) => { @@ -579,7 +582,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { let index = match cx.tcx.expr_ty_adjusted(source).sty { - ty::TyStruct(adt_def, _) => + ty::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => span_bug!( diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 0bd22cd2d9308..30f79796aaa6d 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -217,7 +217,9 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Struct(_, ref fields, _) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, + ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) | + ty::TyEnum(adt_def, _) => adt_def, _ => { span_bug!( pat.span, @@ -313,7 +315,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => { + Def::Struct(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) => { PatternKind::Leaf { subpatterns: subpatterns } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 21d4ae595e8ac..55bd51cd75ba9 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -281,7 +281,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { (&adt_def.variants[variant_index], substs) } LvalueTy::Ty { ty } => match ty.sty { - ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs) + ty::TyStruct(adt_def, substs) | + ty::TyUnion(adt_def, substs) | + ty::TyEnum(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 2d1b6e1315f8b..c3749bf4546f3 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -440,6 +440,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { v.add_qualif(ConstQualif::NEEDS_DROP); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cd2eb4d2b58bd..25601b6bfec7f 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -174,7 +174,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.update(trait_item.id, item_level); } } - hir::ItemStruct(ref def, _) => { + hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => { if !def.is_struct() { self.update(def.id(), item_level); } @@ -321,8 +321,8 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor< if let hir::TyPath(_, ref path) = ty.node { let def = self.ev.tcx.expect_def(ty.id); match def { - Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | - Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { + Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | + Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) { let item = self.ev.tcx.map.expect_item(node_id); if let Def::TyAlias(..) = def { @@ -943,8 +943,8 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, // free type aliases, but this isn't done yet. return } - Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | - Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { + Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | + Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { // Non-local means public (private items can't leave their crate, modulo bugs) if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { let item = self.tcx.map.expect_item(node_id); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1224c694a4e6e..db0704db33fd5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2187,6 +2187,7 @@ impl<'a> Resolver<'a> { Def::Trait(_) | Def::Enum(_) | Def::Struct(_) | + Def::Union(_) | Def::TyAlias(_) => true, _ => false, }, @@ -2389,7 +2390,7 @@ impl<'a> Resolver<'a> { PatKind::Struct(ref path, _, _) => { self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| { match def { - Def::Struct(..) | Def::Variant(..) | + Def::Struct(..) | Def::Union(..) | Def::Variant(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true, _ => false, } @@ -2735,7 +2736,7 @@ impl<'a> Resolver<'a> { // Look for a field with the same name in the current self_type. if let Some(resolution) = self.def_map.get(&node_id) { match resolution.base_def { - Def::Enum(did) | Def::TyAlias(did) | + Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) | Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => { if let Some(fields) = self.structs.get(&did) { if fields.iter().any(|&field_name| name == field_name) { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index db535e22f194d..47f3a06de1bd1 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -404,7 +404,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } }; match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); @@ -423,7 +423,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ExprKind::Struct(ref path, _, _) => { match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); Some(Data::TypeRefData(TypeRefData { @@ -487,6 +487,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } Def::Struct(def_id) | + Def::Union(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | Def::Trait(def_id) | diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 2fb7a69d36186..069eef7895c84 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -176,6 +176,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &ftys[..], packed, t)) } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyClosure(_, ref substs) => { Univariant(mk_struct(cx, &substs.upvar_tys, false, t)) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 47b3bb36cb930..4bea5d7e87fc9 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -744,6 +744,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // monomorphized Drop::drop() implementation. let destructor_did = match ty.sty { ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) => def.destructor(), _ => None }; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index f4682de7dff6a..6ae6f8aead77d 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -88,8 +88,8 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - return false; } match ty.sty { - ty::TyStruct(..) | ty::TyEnum(..) | ty::TyTuple(..) | ty::TyArray(_, _) | - ty::TyClosure(..) => { + ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | + ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { let llty = sizing_type_of(ccx, ty); llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type()) } @@ -205,7 +205,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> { -> Self { match ty.sty { - ty::TyStruct(adt, substs) | ty::TyEnum(adt, substs) => { + ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => { let variant = match opt_def { None => adt.struct_variant(), Some(def) => adt.variant_of_def(def) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 67d4a0e044c9c..f30880ac9beb5 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -184,6 +184,10 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str("struct "); from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); }, + ty::TyUnion(def, substs) => { + unique_type_id.push_str("union "); + from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); + }, ty::TyTuple(component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, @@ -781,6 +785,9 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyTuple(ref elements) => { prepare_tuple_metadata(cx, t, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 9e1e415f62a67..5da9ef3646e6b 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -470,6 +470,9 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None) } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyTrait(..) => { // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index d5d8f049681da..b5565109306b4 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -331,7 +331,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..) + ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..) if !t.is_simd() => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &repr, &mut llty); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6c9cc5f5e132a..c445455ef2bc5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1476,7 +1476,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span, partition_bounds(tcx, span, &[])) } - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { + Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { tcx.prohibit_type_params(base_segments.split_last().unwrap().1); self.ast_path_to_ty(rscope, span, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f8a2e82edc2a6..5fdfa19190bdb 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -510,7 +510,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check subpatterns. let substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(pat.span, "struct variant is not an ADT") }; self.check_struct_pat_fields(pat.span, fields, variant, substs, etc); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index bd47ff0b00b7b..3e37602169a7a 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -45,6 +45,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyEnum(adt_def, self_to_impl_substs) | + ty::TyUnion(adt_def, self_to_impl_substs) | ty::TyStruct(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, drop_impl_did, @@ -495,7 +496,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) => { + ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { def.is_dtorck(tcx) } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2e2cb2765d93d..edee730086871 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -293,7 +293,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } ty::TyBox(_) => { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 46b3f503b6e76..6d8a73b8a6aa0 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -164,30 +164,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // give a helping note that it has to be called as (x.f)(...). if let Some(expr) = rcvr_expr { for (ty, _) in self.autoderef(span, rcvr_ty) { - if let ty::TyStruct(def, substs) = ty.sty { - if let Some(field) = def.struct_variant().find_field_named(item_name) { - let snippet = tcx.sess.codemap().span_to_snippet(expr.span); - let expr_string = match snippet { - Ok(expr_string) => expr_string, - _ => "s".into() // Default to a generic placeholder for the - // expression when we can't generate a - // string snippet - }; - - let field_ty = field.ty(tcx, substs); - - if self.is_fn_ty(&field_ty, span) { - err.span_note(span, &format!( - "use `({0}.{1})(...)` if you meant to call the function \ - stored in the `{1}` field", - expr_string, item_name)); - } else { - err.span_note(span, &format!( - "did you mean to write `{0}.{1}`?", - expr_string, item_name)); + match ty.sty { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => { + if let Some(field) = def.struct_variant().find_field_named(item_name) { + let snippet = tcx.sess.codemap().span_to_snippet(expr.span); + let expr_string = match snippet { + Ok(expr_string) => expr_string, + _ => "s".into() // Default to a generic placeholder for the + // expression when we can't generate a + // string snippet + }; + + let field_ty = field.ty(tcx, substs); + + if self.is_fn_ty(&field_ty, span) { + err.span_note(span, &format!( + "use `({0}.{1})(...)` if you meant to call the function \ + stored in the `{1}` field", + expr_string, item_name)); + } else { + err.span_note(span, &format!( + "did you mean to write `{0}.{1}`?", + expr_string, item_name)); + } + break; } - break; } + _ => {} } } } @@ -355,7 +358,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_expr: Option<&hir::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), + ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + def.did.is_local() + } ty::TyTrait(ref tr) => tr.principal.def_id().is_local(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index be33f836cc6cd..679ced1987e6c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -762,6 +762,9 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { hir::ItemStruct(..) => { check_struct(ccx, it.id, it.span); } + hir::ItemUnion(..) => { + unimplemented_unions!(); + } hir::ItemTy(_, ref generics) => { let pty_ty = ccx.tcx.node_id_to_type(it.id); check_bounds_are_used(ccx, generics, pty_ty); @@ -2942,18 +2945,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { - if let ty::TyStruct(base_def, substs) = base_t.sty { - debug!("struct named {:?}", base_t); - if let Some(field) = base_def.struct_variant().find_field_named(field.node) { - let field_ty = self.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { - autoderef.finalize(lvalue_pref, Some(base)); - self.write_ty(expr.id, field_ty); - self.write_autoderef_adjustment(base.id, autoderefs); - return; + match base_t.sty { + ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => { + debug!("struct named {:?}", base_t); + if let Some(field) = base_def.struct_variant().find_field_named(field.node) { + let field_ty = self.field_ty(expr.span, field, substs); + if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { + autoderef.finalize(lvalue_pref, Some(base)); + self.write_ty(expr.id, field_ty); + self.write_autoderef_adjustment(base.id, autoderefs); + return; + } + private_candidate = Some((base_def.did, field_ty)); } - private_candidate = Some((base_def.did, field_ty)); } + _ => {} } } autoderef.unambiguous_final_ty(); @@ -2986,12 +2992,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { but no field with that name was found", field.node, actual) }, expr_t); - if let ty::TyRawPtr(..) = expr_t.sty { - err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ - `(*{0}).{1}`", pprust::expr_to_string(base), field.node)); - } - if let ty::TyStruct(def, _) = expr_t.sty { - Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); + match expr_t.sty { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); + } + ty::TyRawPtr(..) => { + err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ + `(*{0}).{1}`", pprust::expr_to_string(base), field.node)); + } + _ => {} } err.emit(); self.write_error(expr.id); @@ -3125,7 +3134,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { check_completeness: bool) { let tcx = self.tcx; let substs = match adt_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3217,7 +3226,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); return None; } - Def::Variant(type_did, _) | Def::Struct(type_did) => { + Def::Variant(type_did, _) | Def::Struct(type_did) | Def::Union(type_did) => { Some((type_did, self.tcx.expect_variant_def(def))) } Def::TyAlias(did) => { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 435442bd30a65..19bee13b6f603 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -142,6 +142,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } + hir::ItemUnion(..) => { + unimplemented_unions!(); + } hir::ItemEnum(ref enum_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { fcx.enum_variants(enum_def) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a20195bd801d9..fba145efa9507 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -242,7 +242,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { ty::TyEnum(type_def, _) | - ty::TyStruct(type_def, _) => { + ty::TyStruct(type_def, _) | + ty::TyUnion(type_def, _) => { type_def.set_destructor(method_def_id.def_id()); } _ => { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bcce64cb110c6..4c38475335ce8 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -76,7 +76,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) => { self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { @@ -293,7 +294,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { - ty::TyStruct(self_def, _) | ty::TyEnum(self_def, _) => + ty::TyStruct(self_def, _) | + ty::TyUnion(self_def, _) | + ty::TyEnum(self_def, _) => Some(self_def.did), ty::TyBox(..) => self.tcx.lang_items.owned_box(), diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index f60fb9583a661..c4d925372f18d 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { - hir::ItemEnum(..) | hir::ItemStruct(..) => { + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { let type_def_id = self.tcx.map.local_def_id(item.id); self.check_for_overlapping_inherent_impls(type_def_id); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7f9de2becee6e..1d260b9dbb290 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -931,7 +931,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), trait_item_def_ids); }, - hir::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { let def_id = ccx.tcx.map.local_def_id(it.id); let scheme = type_scheme_of_def_id(ccx, def_id); let predicates = predicates_of_item(ccx, it); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index e20e74be67cd3..24eb29f45a5e5 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -185,6 +185,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { hir::ItemTy(..) | hir::ItemEnum(..) | hir::ItemStruct(..) | + hir::ItemUnion(..) | hir::ItemTrait(..) => is_inferred = true, hir::ItemFn(..) => is_inferred = false, _ => cannot_happen!(), From 6792bd99febc646f22814b6759e31e622850f405 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 10 Aug 2016 21:00:17 +0300 Subject: [PATCH 500/768] Support unions in rustdoc --- src/librustdoc/clean/inline.rs | 19 +++++++ src/librustdoc/clean/mod.rs | 36 ++++++++++++- src/librustdoc/doctree.rs | 15 ++++++ src/librustdoc/fold.rs | 7 +++ src/librustdoc/html/item_type.rs | 4 ++ src/librustdoc/html/render.rs | 81 ++++++++++++++++++++++++++++-- src/librustdoc/html/static/main.js | 3 +- src/librustdoc/passes.rs | 2 +- src/librustdoc/visit_ast.rs | 24 ++++++++- src/librustdoc/visit_lib.rs | 1 + src/test/rustdoc/union.rs | 20 ++++++++ 11 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 src/test/rustdoc/union.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 20d4c41765540..4250979a24033 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -88,6 +88,11 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, ret.extend(build_impls(cx, tcx, did)); clean::StructItem(build_struct(cx, tcx, did)) } + Def::Union(did) => { + record_extern_fqn(cx, did, clean::TypeUnion); + ret.extend(build_impls(cx, tcx, did)); + clean::UnionItem(build_union(cx, tcx, did)) + } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeTypedef); ret.extend(build_impls(cx, tcx, did)); @@ -214,6 +219,20 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, + did: DefId) -> clean::Union { + let t = tcx.lookup_item_type(did); + let predicates = tcx.lookup_predicates(did); + let variant = tcx.lookup_adt_def(did).struct_variant(); + + clean::Union { + struct_type: doctree::Plain, + generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), + fields: variant.fields.clean(cx), + fields_stripped: false, + } +} + fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::ItemEnum { let t = tcx.lookup_item_type(did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 92bb265ca995a..f8ec5a55e7d4c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -321,6 +321,7 @@ impl Item { pub fn has_stripped_fields(&self) -> Option { match self.inner { StructItem(ref _struct) => Some(_struct.fields_stripped), + UnionItem(ref union) => Some(union.fields_stripped), VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => { Some(vstruct.fields_stripped) }, @@ -351,6 +352,7 @@ pub enum ItemEnum { ExternCrateItem(String, Option), ImportItem(Import), StructItem(Struct), + UnionItem(Union), EnumItem(Enum), FunctionItem(Function), ModuleItem(Module), @@ -414,6 +416,7 @@ impl Clean for doctree::Module { items.extend(self.extern_crates.iter().map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); items.extend(self.structs.iter().map(|x| x.clean(cx))); + items.extend(self.unions.iter().map(|x| x.clean(cx))); items.extend(self.enums.iter().map(|x| x.clean(cx))); items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); @@ -1464,6 +1467,7 @@ pub enum TypeKind { TypeConst, TypeStatic, TypeStruct, + TypeUnion, TypeTrait, TypeVariant, TypeTypedef, @@ -1801,12 +1805,13 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), - ty::TyUnion(..) => unimplemented_unions!(), ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; let kind = match self.sty { ty::TyStruct(..) => TypeStruct, + ty::TyUnion(..) => TypeUnion, _ => TypeEnum, }; inline::record_extern_fqn(cx, did, kind); @@ -1929,6 +1934,14 @@ pub struct Struct { pub fields_stripped: bool, } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct Union { + pub struct_type: doctree::StructType, + pub generics: Generics, + pub fields: Vec, + pub fields_stripped: bool, +} + impl Clean for doctree::Struct { fn clean(&self, cx: &DocContext) -> Item { Item { @@ -1949,6 +1962,26 @@ impl Clean for doctree::Struct { } } +impl Clean for doctree::Union { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), + attrs: self.attrs.clean(cx), + source: self.whence.clean(cx), + def_id: cx.map.local_def_id(self.id), + visibility: self.vis.clean(cx), + stability: self.stab.clean(cx), + deprecation: self.depr.clean(cx), + inner: UnionItem(Union { + struct_type: self.struct_type, + generics: self.generics.clean(cx), + fields: self.fields.clean(cx), + fields_stripped: false, + }), + } + } +} + /// This is a more limited form of the standard Struct, different in that /// it lacks the things most items have (name, id, parameterization). Found /// only as a variant in an enum. @@ -2748,6 +2781,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Enum(i) => (i, TypeEnum), Def::Trait(i) => (i, TypeTrait), Def::Struct(i) => (i, TypeStruct), + Def::Union(i) => (i, TypeUnion), Def::Mod(i) => (i, TypeModule), Def::Static(i, _) => (i, TypeStatic), Def::Variant(i, _) => (i, TypeEnum), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 04d176c36c8cf..cc62fcfa0aa8b 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -30,6 +30,7 @@ pub struct Module { pub extern_crates: Vec, pub imports: Vec, pub structs: Vec, + pub unions: Vec, pub enums: Vec, pub fns: Vec, pub mods: Vec, @@ -62,6 +63,7 @@ impl Module { extern_crates: Vec::new(), imports : Vec::new(), structs : Vec::new(), + unions : Vec::new(), enums : Vec::new(), fns : Vec::new(), mods : Vec::new(), @@ -108,6 +110,19 @@ pub struct Struct { pub whence: Span, } +pub struct Union { + pub vis: hir::Visibility, + pub stab: Option, + pub depr: Option, + pub id: NodeId, + pub struct_type: StructType, + pub name: Name, + pub generics: hir::Generics, + pub attrs: hir::HirVec, + pub fields: hir::HirVec, + pub whence: Span, +} + pub struct Enum { pub vis: hir::Visibility, pub stab: Option, diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 5595c749256df..8d6ab221c4fce 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -49,6 +49,13 @@ pub trait DocFolder : Sized { i.fields.iter().any(|f| f.is_stripped()); StructItem(i) }, + UnionItem(mut i) => { + let num_fields = i.fields.len(); + i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + i.fields_stripped |= num_fields != i.fields.len() || + i.fields.iter().any(|f| f.is_stripped()); + UnionItem(i) + }, EnumItem(mut i) => { let num_variants = i.variants.len(); i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect(); diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index be19217928467..9ce3c79e2f19b 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -40,6 +40,7 @@ pub enum ItemType { AssociatedType = 16, Constant = 17, AssociatedConst = 18, + Union = 19, } @@ -62,6 +63,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ExternCrateItem(..) => ItemType::ExternCrate, clean::ImportItem(..) => ItemType::Import, clean::StructItem(..) => ItemType::Struct, + clean::UnionItem(..) => ItemType::Union, clean::EnumItem(..) => ItemType::Enum, clean::FunctionItem(..) => ItemType::Function, clean::TypedefItem(..) => ItemType::Typedef, @@ -89,6 +91,7 @@ impl From for ItemType { fn from(kind: clean::TypeKind) -> ItemType { match kind { clean::TypeStruct => ItemType::Struct, + clean::TypeUnion => ItemType::Union, clean::TypeEnum => ItemType::Enum, clean::TypeFunction => ItemType::Function, clean::TypeTrait => ItemType::Trait, @@ -108,6 +111,7 @@ impl ItemType { ItemType::ExternCrate => "externcrate", ItemType::Import => "import", ItemType::Struct => "struct", + ItemType::Union => "union", ItemType::Enum => "enum", ItemType::Function => "fn", ItemType::Typedef => "type", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6d523ff381556..c1bb9d9f633bc 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1053,6 +1053,7 @@ impl DocFolder for Cache { // information if present. Some(&(ref fqp, ItemType::Trait)) | Some(&(ref fqp, ItemType::Struct)) | + Some(&(ref fqp, ItemType::Union)) | Some(&(ref fqp, ItemType::Enum)) => Some(&fqp[..fqp.len() - 1]), Some(..) => Some(&*self.stack), @@ -1106,7 +1107,8 @@ impl DocFolder for Cache { clean::TypedefItem(..) | clean::TraitItem(..) | clean::FunctionItem(..) | clean::ModuleItem(..) | clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | - clean::ConstantItem(..) | clean::StaticItem(..) + clean::ConstantItem(..) | clean::StaticItem(..) | + clean::UnionItem(..) if !self.stripped_mod => { // Reexported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, @@ -1141,7 +1143,8 @@ impl DocFolder for Cache { // Maintain the parent stack let orig_parent_is_trait_impl = self.parent_is_trait_impl; let parent_pushed = match item.inner { - clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => { + clean::TraitItem(..) | clean::EnumItem(..) | + clean::StructItem(..) | clean::UnionItem(..) => { self.parent_stack.push(item.def_id); self.parent_is_trait_impl = false; true @@ -1557,6 +1560,7 @@ impl<'a> fmt::Display for Item<'a> { clean::FunctionItem(..) => write!(fmt, "Function ")?, clean::TraitItem(..) => write!(fmt, "Trait ")?, clean::StructItem(..) => write!(fmt, "Struct ")?, + clean::UnionItem(..) => write!(fmt, "Union ")?, clean::EnumItem(..) => write!(fmt, "Enum ")?, clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, _ => {} @@ -1613,6 +1617,7 @@ impl<'a> fmt::Display for Item<'a> { item_function(fmt, self.cx, self.item, f), clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t), clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s), + clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s), clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e), clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t), clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m), @@ -1715,7 +1720,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ItemType::Trait => 9, ItemType::Function => 10, ItemType::Typedef => 12, - _ => 13 + ty as u8, + ItemType::Union => 13, + _ => 14 + ty as u8, } } @@ -1759,6 +1765,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ItemType::Import => ("reexports", "Reexports"), ItemType::Module => ("modules", "Modules"), ItemType::Struct => ("structs", "Structs"), + ItemType::Union => ("unions", "Unions"), ItemType::Enum => ("enums", "Enums"), ItemType::Function => ("functions", "Functions"), ItemType::Typedef => ("types", "Type Definitions"), @@ -2312,6 +2319,40 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } +fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, + s: &clean::Union) -> fmt::Result { + write!(w, "
")?;
+    render_attributes(w, it)?;
+    render_union(w,
+                 it,
+                 Some(&s.generics),
+                 &s.fields,
+                 "",
+                 true)?;
+    write!(w, "
")?; + + document(w, cx, it)?; + let mut fields = s.fields.iter().filter_map(|f| { + match f.inner { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + } + }).peekable(); + if fields.peek().is_some() { + write!(w, "

Fields

")?; + for (field, ty) in fields { + write!(w, "{name}: {ty} + ", + shortty = ItemType::StructField, + stab = field.stability_class(), + name = field.name.as_ref().unwrap(), + ty = ty)?; + document(w, cx, field)?; + } + } + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) +} + fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, e: &clean::Enum) -> fmt::Result { write!(w, "
")?;
@@ -2514,6 +2555,40 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
     Ok(())
 }
 
+fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
+                g: Option<&clean::Generics>,
+                fields: &[clean::Item],
+                tab: &str,
+                structhead: bool) -> fmt::Result {
+    write!(w, "{}{}{}",
+           VisSpace(&it.visibility),
+           if structhead {"union "} else {""},
+           it.name.as_ref().unwrap())?;
+    if let Some(g) = g {
+        write!(w, "{}", g)?
+    }
+    if let Some(g) = g {
+        write!(w, "{}", WhereClause(g))?
+    }
+
+    write!(w, " {{\n{}", tab)?;
+    for field in fields {
+        if let clean::StructFieldItem(ref ty) = field.inner {
+            write!(w, "    {}{}: {},\n{}",
+                   VisSpace(&field.visibility),
+                   field.name.as_ref().unwrap(),
+                   *ty,
+                   tab)?;
+        }
+    }
+
+    if it.has_stripped_fields().unwrap() {
+        write!(w, "    // some fields omitted\n{}", tab)?;
+    }
+    write!(w, "}}")?;
+    Ok(())
+}
+
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index de7e4d2483b43..9bb7246e7a92e 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -34,7 +34,8 @@
                      "primitive",
                      "associatedtype",
                      "constant",
-                     "associatedconstant"];
+                     "associatedconstant",
+                     "union"];
 
     // used for special search precedence
     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index b8e40790646a7..c60e22824965f 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -113,7 +113,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             clean::TraitItem(..) | clean::FunctionItem(..) |
             clean::VariantItem(..) | clean::MethodItem(..) |
             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
-            clean::ConstantItem(..) => {
+            clean::ConstantItem(..) | clean::UnionItem(..) => {
                 if i.def_id.is_local() {
                     if !self.access_levels.is_exported(i.def_id) {
                         return None;
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index e70fbf4463a22..16a6e994b5a0b 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -108,6 +108,25 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         }
     }
 
+    pub fn visit_union_data(&mut self, item: &hir::Item,
+                            name: ast::Name, sd: &hir::VariantData,
+                            generics: &hir::Generics) -> Union {
+        debug!("Visiting union");
+        let struct_type = struct_type_from_def(&*sd);
+        Union {
+            id: item.id,
+            struct_type: struct_type,
+            name: name,
+            vis: item.vis.clone(),
+            stab: self.stability(item.id),
+            depr: self.deprecation(item.id),
+            attrs: item.attrs.clone(),
+            generics: generics.clone(),
+            fields: sd.fields().iter().cloned().collect(),
+            whence: item.span
+        }
+    }
+
     pub fn visit_enum_def(&mut self, it: &hir::Item,
                           name: ast::Name, def: &hir::EnumDef,
                           params: &hir::Generics) -> Enum {
@@ -258,6 +277,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             match def {
                 Def::Trait(did) |
                 Def::Struct(did) |
+                Def::Union(did) |
                 Def::Enum(did) |
                 Def::TyAlias(did) if !self_is_hidden => {
                     self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public);
@@ -365,8 +385,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.enums.push(self.visit_enum_def(item, name, ed, gen)),
             hir::ItemStruct(ref sd, ref gen) =>
                 om.structs.push(self.visit_variant_data(item, name, sd, gen)),
-            hir::ItemUnion(..) =>
-                unimplemented_unions!(),
+            hir::ItemUnion(ref sd, ref gen) =>
+                om.unions.push(self.visit_union_data(item, name, sd, gen)),
             hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
                 om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
                                           constness, abi, gen)),
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index f6d89f7c1dc89..3af030706b739 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -73,6 +73,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
                     Def::ForeignMod(did) |
                     Def::Trait(did) |
                     Def::Struct(did) |
+                    Def::Union(did) |
                     Def::Enum(did) |
                     Def::TyAlias(did) |
                     Def::Fn(did) |
diff --git a/src/test/rustdoc/union.rs b/src/test/rustdoc/union.rs
new file mode 100644
index 0000000000000..0dcc9098ad75c
--- /dev/null
+++ b/src/test/rustdoc/union.rs
@@ -0,0 +1,20 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+// @has union/union.U.html
+pub union U {
+    // @has - //pre "pub a: u8"
+    pub a: u8,
+    // @has - //pre "// some fields omitted"
+    // @!has - //pre "b: u16"
+    b: u16,
+}

From 5f9ef3c8b28c9a25be74bc2e41399a4c684f07b1 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 15 Aug 2016 16:10:58 +0300
Subject: [PATCH 501/768] Implement encoding/decoding unions in metadata

Add well-formedness check
Implement some more missing code
---
 src/librustc/middle/expr_use_visitor.rs       |  6 +---
 src/librustc/ty/fast_reject.rs                |  5 +--
 src/librustc_metadata/decoder.rs              |  7 ++++
 src/librustc_typeck/check/dropck.rs           |  3 +-
 src/librustc_typeck/check/mod.rs              | 26 +++++++-------
 src/librustc_typeck/check/wfcheck.rs          | 34 ++++++++++---------
 src/test/compile-fail/attr-usage-repr.rs      |  2 +-
 src/test/compile-fail/issue-31769.rs          |  2 +-
 .../compile-fail/union-nonrepresentable.rs    | 18 ++++++++++
 src/test/compile-fail/union-unsized.rs        | 17 ++++++++++
 src/test/run-pass/auxiliary/union.rs          | 16 +++++++++
 src/test/run-pass/union-xcrate.rs             | 21 ++++++++++++
 12 files changed, 119 insertions(+), 38 deletions(-)
 create mode 100644 src/test/compile-fail/union-nonrepresentable.rs
 create mode 100644 src/test/compile-fail/union-unsized.rs
 create mode 100644 src/test/run-pass/auxiliary/union.rs
 create mode 100644 src/test/run-pass/union-xcrate.rs

diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 7214049f6cd64..a6835802f1cf9 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             }
 
             hir::ExprStruct(_, ref fields, ref opt_with) => {
-                self.walk_struct_expr(expr, fields, opt_with);
+                self.walk_struct_expr(fields, opt_with);
             }
 
             hir::ExprTup(ref exprs) => {
@@ -655,7 +655,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn walk_struct_expr(&mut self,
-                        _expr: &hir::Expr,
                         fields: &[hir::Field],
                         opt_with: &Option>) {
         // Consume the expressions supplying values for each field.
@@ -687,9 +686,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            ty::TyUnion(..) => {
-                unimplemented_unions!();
-            }
             _ => {
                 // the base expression should always evaluate to a
                 // struct; however, when EUV is run during typeck, it
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 23678d1e37742..f9ca2484d7efc 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -30,6 +30,7 @@ pub enum SimplifiedType {
     TupleSimplifiedType(usize),
     TraitSimplifiedType(DefId),
     StructSimplifiedType(DefId),
+    UnionSimplifiedType(DefId),
     ClosureSimplifiedType(DefId),
     AnonSimplifiedType(DefId),
     FunctionSimplifiedType(usize),
@@ -66,8 +67,8 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyStruct(def, _) => {
             Some(StructSimplifiedType(def.did))
         }
-        ty::TyUnion(..) => {
-            unimplemented_unions!();
+        ty::TyUnion(def, _) => {
+            Some(UnionSimplifiedType(def.did))
         }
         ty::TyRef(_, mt) => {
             // since we introduce auto-refs during method lookup, we
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 9a13be8ade52a..8775f58d0b22b 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -133,6 +133,7 @@ enum Family {
     DefaultImpl,           // d
     Trait,                 // I
     Struct(VariantKind),   // S, s, u
+    Union,                 // U
     PublicField,           // g
     InheritedField,        // N
     Constant,              // C
@@ -160,6 +161,7 @@ fn item_family(item: rbml::Doc) -> Family {
       'S' => Struct(VariantKind::Struct),
       's' => Struct(VariantKind::Tuple),
       'u' => Struct(VariantKind::Unit),
+      'U' => Union,
       'g' => PublicField,
       'N' => InheritedField,
        c => bug!("unexpected family char: {}", c)
@@ -317,6 +319,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
         ImmStatic => DlDef(Def::Static(did, false)),
         MutStatic => DlDef(Def::Static(did, true)),
         Struct(..) => DlDef(Def::Struct(did)),
+        Union => DlDef(Def::Union(did)),
         Fn        => DlDef(Def::Fn(did)),
         Method | StaticMethod => {
             DlDef(Def::Method(did))
@@ -461,6 +464,10 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
             (ty::AdtKind::Struct,
              vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))])
         }
+        Union => {
+            (ty::AdtKind::Union,
+             vec![get_struct_variant(cdata, doc, did)])
+        }
         _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
                   item_family(doc), did)
     };
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 3e37602169a7a..88add66b7dcb0 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -306,7 +306,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
                                                      variant),
                         ty::AdtKind::Struct => format!("struct {}",
                                                        tcx.item_path_str(def_id)),
-                        ty::AdtKind::Union => unimplemented_unions!(),
+                        ty::AdtKind::Union => format!("union {}",
+                                                       tcx.item_path_str(def_id)),
                     };
                     span_note!(
                         &mut err,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 679ced1987e6c..e2954cecc9c46 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -713,16 +713,18 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     fcx
 }
 
-pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
-    let tcx = ccx.tcx;
-
-    check_representable(tcx, span, id, "struct");
+fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
+    check_representable(ccx.tcx, span, id);
 
-    if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
-        check_simd(tcx, span, id);
+    if ccx.tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
+        check_simd(ccx.tcx, span, id);
     }
 }
 
+fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
+    check_representable(ccx.tcx, span, id);
+}
+
 pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     debug!("check_item_type(it.id={}, it.name={})",
            it.id,
@@ -763,7 +765,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         check_struct(ccx, it.id, it.span);
       }
       hir::ItemUnion(..) => {
-        unimplemented_unions!();
+        check_union(ccx, it.id, it.span);
       }
       hir::ItemTy(_, ref generics) => {
         let pty_ty = ccx.tcx.node_id_to_type(it.id);
@@ -1174,10 +1176,10 @@ fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
-pub fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     sp: Span,
-                                     item_id: ast::NodeId,
-                                     _designation: &str) -> bool {
+fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 sp: Span,
+                                 item_id: ast::NodeId)
+                                 -> bool {
     let rty = tcx.node_id_to_type(item_id);
 
     // Check that it is possible to represent this type. This call identifies
@@ -1277,7 +1279,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         disr_vals.push(current_disr_val);
     }
 
-    check_representable(ccx.tcx, sp, id, "enum");
+    check_representable(ccx.tcx, sp, id);
 }
 
 impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 19bee13b6f603..7cc3be0a89062 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -136,17 +136,21 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                 self.check_item_type(item);
             }
             hir::ItemStruct(ref struct_def, ref ast_generics) => {
-                self.check_type_defn(item, |fcx| {
+                self.check_type_defn(item, false, |fcx| {
                     vec![fcx.struct_variant(struct_def)]
                 });
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
-            hir::ItemUnion(..) => {
-                unimplemented_unions!();
+            hir::ItemUnion(ref struct_def, ref ast_generics) => {
+                self.check_type_defn(item, true, |fcx| {
+                    vec![fcx.struct_variant(struct_def)]
+                });
+
+                self.check_variances_for_type_defn(item, ast_generics);
             }
             hir::ItemEnum(ref enum_def, ref ast_generics) => {
-                self.check_type_defn(item, |fcx| {
+                self.check_type_defn(item, false, |fcx| {
                     fcx.enum_variants(enum_def)
                 });
 
@@ -219,24 +223,22 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     }
 
     /// In a type definition, we check that to ensure that the types of the fields are well-formed.
-    fn check_type_defn(&mut self, item: &hir::Item, mut lookup_fields: F) where
-        F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>)
-                                 -> Vec>
+    fn check_type_defn(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F)
+        where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec>
     {
         self.for_item(item).with_fcx(|fcx, this| {
             let variants = lookup_fields(fcx);
 
             for variant in &variants {
                 // For DST, all intermediate types must be sized.
-                if let Some((_, fields)) = variant.fields.split_last() {
-                    for field in fields {
-                        fcx.register_builtin_bound(
-                            field.ty,
-                            ty::BoundSized,
-                            traits::ObligationCause::new(field.span,
-                                                         fcx.body_id,
-                                                         traits::FieldSized));
-                    }
+                let unsized_len = if all_sized || variant.fields.is_empty() { 0 } else { 1 };
+                for field in &variant.fields[..variant.fields.len() - unsized_len] {
+                    fcx.register_builtin_bound(
+                        field.ty,
+                        ty::BoundSized,
+                        traits::ObligationCause::new(field.span,
+                                                     fcx.body_id,
+                                                     traits::FieldSized));
                 }
 
                 // All field types must be well-formed.
diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs
index 9bad6a8389a5d..b07d3e2f90675 100644
--- a/src/test/compile-fail/attr-usage-repr.rs
+++ b/src/test/compile-fail/attr-usage-repr.rs
@@ -11,7 +11,7 @@
 #![allow(dead_code)]
 #![feature(repr_simd)]
 
-#[repr(C)] //~ ERROR: attribute should be applied to struct or enum
+#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
 fn f() {}
 
 #[repr(C)]
diff --git a/src/test/compile-fail/issue-31769.rs b/src/test/compile-fail/issue-31769.rs
index 4b5df7ea53ca1..7f73d9076ec99 100644
--- a/src/test/compile-fail/issue-31769.rs
+++ b/src/test/compile-fail/issue-31769.rs
@@ -10,5 +10,5 @@
 
 fn main() {
     #[inline] struct Foo;  //~ ERROR attribute should be applied to function
-    #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct or enum
+    #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union
 }
diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union-nonrepresentable.rs
new file mode 100644
index 0000000000000..cb4683c2a0e12
--- /dev/null
+++ b/src/test/compile-fail/union-nonrepresentable.rs
@@ -0,0 +1,18 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U { //~ ERROR recursive type `U` has infinite size
+    a: u8,
+    b: U,
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union-unsized.rs
new file mode 100644
index 0000000000000..381122406d71f
--- /dev/null
+++ b/src/test/compile-fail/union-unsized.rs
@@ -0,0 +1,17 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/run-pass/auxiliary/union.rs b/src/test/run-pass/auxiliary/union.rs
new file mode 100644
index 0000000000000..dc0ca7c81c009
--- /dev/null
+++ b/src/test/run-pass/auxiliary/union.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+pub union U {
+    pub a: u8,
+    b: u16,
+}
diff --git a/src/test/run-pass/union-xcrate.rs b/src/test/run-pass/union-xcrate.rs
new file mode 100644
index 0000000000000..2a76c96ef25f5
--- /dev/null
+++ b/src/test/run-pass/union-xcrate.rs
@@ -0,0 +1,21 @@
+// 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.
+
+// aux-build:union.rs
+
+// #![feature(untagged_unions)]
+
+extern crate union;
+
+type A = union::U;
+
+fn main() {
+    assert_eq!(std::mem::size_of::(), 8);
+}

From c2ca1530dbcde745175569b9f5434fa6643e5766 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 15:43:24 +0300
Subject: [PATCH 502/768] Fix rebase + address comments

---
 src/librustc/middle/dead.rs                 | 2 +-
 src/librustc/middle/stability.rs            | 4 ++--
 src/librustc/ty/sty.rs                      | 2 +-
 src/librustc_lint/builtin.rs                | 3 +--
 src/librustc_typeck/check/method/suggest.rs | 7 ++++---
 src/librustc_typeck/collect.rs              | 5 +++++
 src/librustdoc/clean/inline.rs              | 2 +-
 src/librustdoc/html/item_type.rs            | 1 +
 src/librustdoc/html/render.rs               | 6 ++----
 9 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 9a63ad4b9859e..0b1d9e8d8f69e 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -136,7 +136,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                 self.insert_def_id(def.struct_variant().field_named(name).did);
             }
-            _ => span_bug!(lhs.span, "named field access on non-struct"),
+            _ => span_bug!(lhs.span, "named field access on non-struct/union"),
         }
     }
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e6979c2545330..aea1ee8d82401 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -565,7 +565,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
                     def.struct_variant().field_named(field.node).did
                 }
                 _ => span_bug!(e.span,
-                               "stability::check_expr: named field access on non-struct")
+                               "stability::check_expr: named field access on non-struct/union")
             }
         }
         hir::ExprTupField(ref base_e, ref field) => {
@@ -601,7 +601,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
                 _ => {
                     span_bug!(e.span,
                               "stability::check_expr: struct construction \
-                               of non-struct, type {:?}",
+                               of non-struct/union, type {:?}",
                               type_);
                 }
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 165f86fbef538..d45fde925c511 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -112,7 +112,7 @@ pub enum TypeVariants<'tcx> {
     /// That is, even after substitution it is possible that there are type
     /// variables. This happens when the `TyEnum` corresponds to an enum
     /// definition and not a concrete use of it. This is true for `TyStruct`
-    /// as well.
+    /// and `TyUnion` as well.
     TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
 
     /// A structure type, defined with `struct`.
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 571d1222baaa4..b55cad58e2fe4 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -475,8 +475,7 @@ impl LateLintPass for MissingCopyImplementations {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_union(def,
-                                      cx.tcx.mk_substs(Substs::empty())))
+                (def, cx.tcx.mk_union(def, Substs::empty(cx.tcx)))
             }
             hir::ItemEnum(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 6d8a73b8a6aa0..e4ea9bb407d96 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -166,7 +166,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     for (ty, _) in self.autoderef(span, rcvr_ty) {
                         match ty.sty {
                             ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => {
-                                if let Some(field) = def.struct_variant().find_field_named(item_name) {
+                                if let Some(field) = def.struct_variant().
+                                                         find_field_named(item_name) {
                                     let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
                                     let expr_string = match snippet {
                                         Ok(expr_string) => expr_string,
@@ -179,8 +180,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                                     if self.is_fn_ty(&field_ty, span) {
                                         err.span_note(span, &format!(
-                                            "use `({0}.{1})(...)` if you meant to call the function \
-                                             stored in the `{1}` field",
+                                            "use `({0}.{1})(...)` if you meant to call the \
+                                             function stored in the `{1}` field",
                                             expr_string, item_name));
                                     } else {
                                         err.span_note(span, &format!(
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1d260b9dbb290..a100c919d6f4e 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1587,6 +1587,11 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
                         ccx.tcx.mk_struct(def, substs)
                     }
+                    ItemUnion(ref un, ref generics) => {
+                        let def = convert_union_def(ccx, item, un);
+                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
+                        ccx.tcx.mk_union(def, substs)
+                    }
                     ItemDefaultImpl(..) |
                     ItemTrait(..) |
                     ItemImpl(..) |
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 4250979a24033..b7e371e23f323 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -227,7 +227,7 @@ fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     clean::Union {
         struct_type: doctree::Plain,
-        generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
+        generics: (t.generics, &predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index 9ce3c79e2f19b..b93dc17dbdd7d 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -133,6 +133,7 @@ impl ItemType {
     pub fn name_space(&self) -> NameSpace {
         match *self {
             ItemType::Struct |
+            ItemType::Union |
             ItemType::Enum |
             ItemType::Module |
             ItemType::Typedef |
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index c1bb9d9f633bc..6f66ce88df7a5 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2565,10 +2565,8 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
            if structhead {"union "} else {""},
            it.name.as_ref().unwrap())?;
     if let Some(g) = g {
-        write!(w, "{}", g)?
-    }
-    if let Some(g) = g {
-        write!(w, "{}", WhereClause(g))?
+        write!(w, "{}", g)?;
+        write!(w, "{}", WhereClause(g))?;
     }
 
     write!(w, " {{\n{}", tab)?;

From 957971b63abbc816aebc6654dc68cf9ff15837d7 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 15:44:00 +0300
Subject: [PATCH 503/768] Implement layout calculation and add more trans stubs

---
 src/librustc/ty/layout.rs                | 72 ++++++++++++++++--
 src/librustc_mir/hair/cx/expr.rs         |  5 +-
 src/librustc_trans/adt.rs                | 96 ++++++++++++++++++++++--
 src/librustc_trans/debuginfo/metadata.rs |  5 +-
 src/test/run-pass/union-basic.rs         | 47 ++++++++++++
 5 files changed, 205 insertions(+), 20 deletions(-)
 create mode 100644 src/test/run-pass/union-basic.rs

diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index ac5e3c6fa7009..9270057b54415 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> Struct {
 
         for field in fields {
             if !self.sized {
-                bug!("Struct::compute: field #{} of `{}` comes after unsized field",
+                bug!("Struct::extend: field #{} of `{}` comes after unsized field",
                      self.offset_after_field.len(), scapegoat);
             }
 
@@ -623,6 +623,54 @@ impl<'a, 'gcx, 'tcx> Struct {
     }
 }
 
+/// An untagged union.
+#[derive(PartialEq, Eq, Hash, Debug)]
+pub struct Union {
+    pub align: Align,
+
+    pub min_size: Size,
+
+    /// If true, no alignment padding is used.
+    pub packed: bool,
+}
+
+impl<'a, 'gcx, 'tcx> Union {
+    pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
+        Union {
+            align: if packed { dl.i8_align } else { dl.aggregate_align },
+            min_size: Size::from_bytes(0),
+            packed: packed,
+        }
+    }
+
+    /// Extend the Struct with more fields.
+    pub fn extend(&mut self, dl: &TargetDataLayout,
+                     fields: I,
+                     scapegoat: Ty<'gcx>)
+                     -> Result<(), LayoutError<'gcx>>
+    where I: Iterator>> {
+        for (index, field) in fields.enumerate() {
+            let field = field?;
+            if field.is_unsized() {
+                bug!("Union::extend: field #{} of `{}` is unsized",
+                     index, scapegoat);
+            }
+
+            if !self.packed {
+                self.align = self.align.max(field.align(dl));
+            }
+            self.min_size = cmp::max(self.min_size, field.size(dl));
+        }
+
+        Ok(())
+    }
+
+    /// Get the size with trailing aligment padding.
+    pub fn stride(&self) -> Size {
+        self.min_size.abi_align(self.align)
+    }
+}
+
 /// The first half of a fat pointer.
 /// - For a trait object, this is the address of the box.
 /// - For a slice, this is the base address.
@@ -690,6 +738,11 @@ pub enum Layout {
         non_zero: bool
     },
 
+    /// Untagged unions.
+    UntaggedUnion {
+        variants: Union,
+    },
+
     /// General-case enums: for each case there is a struct, and they
     /// all start with a field for the discriminant.
     General {
@@ -896,8 +949,14 @@ impl<'a, 'gcx, 'tcx> Layout {
                     non_zero: Some(def.did) == tcx.lang_items.non_zero()
                 }
             }
-            ty::TyUnion(..) => {
-                unimplemented_unions!();
+            ty::TyUnion(def, substs) => {
+                let fields = def.struct_variant().fields.iter().map(|field| {
+                    field.ty(tcx, substs).layout(infcx)
+                });
+                let packed = tcx.lookup_packed(def.did);
+                let mut un = Union::new(dl, packed);
+                un.extend(dl, fields, ty)?;
+                UntaggedUnion { variants: un }
             }
             ty::TyEnum(def, substs) => {
                 let hint = *tcx.lookup_repr_hints(def.did).get(0)
@@ -1118,7 +1177,7 @@ impl<'a, 'gcx, 'tcx> Layout {
     pub fn is_unsized(&self) -> bool {
         match *self {
             Scalar {..} | Vector {..} | FatPointer {..} |
-            CEnum {..} | General {..} |
+            CEnum {..} | UntaggedUnion {..} | General {..} |
             RawNullablePointer {..} |
             StructWrappedNullablePointer {..} => false,
 
@@ -1152,6 +1211,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             CEnum { discr, .. } => Int(discr).size(dl),
             Array { size, .. } | General { size, .. } => size,
+            UntaggedUnion { ref variants } => variants.stride(),
 
             Univariant { ref variant, .. } |
             StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@@ -1191,6 +1251,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             CEnum { discr, .. } => Int(discr).align(dl),
             Array { align, .. } | General { align, .. } => align,
+            UntaggedUnion { ref variants } => variants.align,
 
             Univariant { ref variant, .. } |
             StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@@ -1256,9 +1317,6 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
                 }
             }
 
-            ty::TyUnion(..) => {
-                unimplemented_unions!();
-            }
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
                 // Only newtypes and enums w/ nullable pointer optimization.
                 if def.variants.is_empty() || def.variants.len() > 2 {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 0469d44de4ba6..c8f660a2d9c7c 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -459,7 +459,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprStruct(_, ref fields, ref base) => {
             match expr_ty.sty {
-                ty::TyStruct(adt, substs) => {
+                ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => {
                     let field_refs = field_refs(&adt.variants[0], fields);
                     ExprKind::Adt {
                         adt_def: adt,
@@ -477,9 +477,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         })
                     }
                 }
-                ty::TyUnion(..) => {
-                    unimplemented_unions!();
-                }
                 ty::TyEnum(adt, substs) => {
                     match cx.tcx.expect_def(expr.id) {
                         Def::Variant(enum_id, variant_id) => {
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 069eef7895c84..abbb9a5d4dbe5 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -79,6 +79,8 @@ pub enum Repr<'tcx> {
     CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
     /// Single-case variants, and structs/tuples/records.
     Univariant(Struct<'tcx>),
+    /// Untagged unions.
+    UntaggedUnion(Union<'tcx>),
     /// General-case enums: for each case there is a struct, and they
     /// all start with a field for the discriminant.
     General(IntType, Vec>),
@@ -121,6 +123,15 @@ pub struct Struct<'tcx> {
     pub fields: Vec>,
 }
 
+/// For untagged unions.
+#[derive(Eq, PartialEq, Debug)]
+pub struct Union<'tcx> {
+    pub min_size: u64,
+    pub align: u32,
+    pub packed: bool,
+    pub fields: Vec>,
+}
+
 #[derive(Copy, Clone)]
 pub struct MaybeSizedValue {
     pub value: ValueRef,
@@ -176,8 +187,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             Univariant(mk_struct(cx, &ftys[..], packed, t))
         }
-        ty::TyUnion(..) => {
-            unimplemented_unions!();
+        ty::TyUnion(def, substs) => {
+            let ftys = def.struct_variant().fields.iter().map(|field| {
+                monomorphize::field_ty(cx.tcx(), substs, field)
+            }).collect::>();
+            let packed = cx.tcx().lookup_packed(def.did);
+            UntaggedUnion(mk_union(cx, &ftys[..], packed, t))
         }
         ty::TyClosure(_, ref substs) => {
             Univariant(mk_struct(cx, &substs.upvar_tys, false, t))
@@ -482,6 +497,31 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 }
 
+fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                      tys: &[Ty<'tcx>], packed: bool,
+                      _scapegoat: Ty<'tcx>)
+                      -> Union<'tcx> {
+    let mut min_size = 0;
+    let mut align = 0;
+    for llty in tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)) {
+        let field_size = machine::llsize_of_alloc(cx, llty);
+        if min_size < field_size {
+            min_size = field_size;
+        }
+        let field_align = machine::llalign_of_min(cx, llty);
+        if align < field_align {
+            align = field_align;
+        }
+    }
+
+    Union {
+        min_size: min_size,
+        align: align,
+        packed: packed,
+        fields: tys.to_vec(),
+    }
+}
+
 #[derive(Debug)]
 struct IntBounds {
     slo: i64,
@@ -646,7 +686,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 r: &Repr<'tcx>, llty: &mut Type) {
     match *r {
-        CEnum(..) | General(..) | RawNullablePointer { .. } => { }
+        CEnum(..) | General(..) | UntaggedUnion(..) | RawNullablePointer { .. } => { }
         Univariant(ref st) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
             llty.set_struct_body(&struct_llfields(cx, st, false, false),
                                  st.packed)
@@ -690,6 +730,34 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
+        UntaggedUnion(ref un) => {
+            // Use alignment-sized ints to fill all the union storage.
+            let (size, align) = (roundup(un.min_size, un.align), un.align);
+
+            let align_s = align as u64;
+            assert_eq!(size % align_s, 0); // Ensure division in align_units comes out evenly
+            let align_units = size / align_s;
+            let fill_ty = match align_s {
+                1 => Type::array(&Type::i8(cx), align_units),
+                2 => Type::array(&Type::i16(cx), align_units),
+                4 => Type::array(&Type::i32(cx), align_units),
+                8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
+                                 Type::array(&Type::i64(cx), align_units),
+                a if a.count_ones() == 1 => Type::array(&Type::vector(&Type::i32(cx), a / 4),
+                                                              align_units),
+                _ => bug!("unsupported union alignment: {}", align)
+            };
+            match name {
+                None => {
+                    TypeContext::direct(Type::struct_(cx, &[fill_ty], un.packed))
+                }
+                Some(name) => {
+                    let mut llty = Type::named_struct(cx, name);
+                    llty.set_struct_body(&[fill_ty], un.packed);
+                    TypeContext::direct(llty)
+                }
+            }
+        }
         General(ity, ref sts) => {
             // We need a representation that has:
             // * The alignment of the most-aligned field
@@ -762,7 +830,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
             (BranchKind::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, range_assert)))
         }
-        Univariant(..) => {
+        Univariant(..) | UntaggedUnion(..) => {
             // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
             (BranchKind::Single, None)
         }
@@ -773,7 +841,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
     match *r {
         CEnum(ity, _, _) => ity.is_signed(),
         General(ity, _) => ity.is_signed(),
-        Univariant(..) => false,
+        Univariant(..) | UntaggedUnion(..) => false,
         RawNullablePointer { .. } => false,
         StructWrappedNullablePointer { .. } => false,
     }
@@ -794,7 +862,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
             load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1),
                        range_assert)
         }
-        Univariant(..) => C_u8(bcx.ccx(), 0),
+        Univariant(..) | UntaggedUnion(..) => C_u8(bcx.ccx(), 0),
         RawNullablePointer { nndiscr, nnty, .. } =>  {
             let cmp = if nndiscr == Disr(0) { IntEQ } else { IntNE };
             let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@@ -856,8 +924,8 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
         General(ity, _) => {
             C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
         }
-        Univariant(..) => {
-            bug!("no cases for univariants or structs")
+        Univariant(..) | UntaggedUnion(..) => {
+            bug!("no cases for univariants, structs or unions")
         }
         RawNullablePointer { .. } |
         StructWrappedNullablePointer { .. } => {
@@ -884,6 +952,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
         Univariant(_) => {
             assert_eq!(discr, Disr(0));
         }
+        UntaggedUnion(..) => {
+            assert_eq!(discr, Disr(0));
+        }
         RawNullablePointer { nndiscr, nnty, ..} => {
             if discr != nndiscr {
                 let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@@ -939,6 +1010,11 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         General(_, ref cases) => {
             struct_field_ptr(bcx, &cases[discr.0 as usize], val, ix + 1, true)
         }
+        UntaggedUnion(ref un) => {
+            let ty = type_of::in_memory_type_of(bcx.ccx(), un.fields[ix]);
+            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            bcx.pointercast(val.value, ty.ptr_to())
+        }
         RawNullablePointer { nndiscr, ref nullfields, .. } |
         StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
             // The unit-like case might have a nonzero number of unit-like fields.
@@ -1100,6 +1176,9 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
             contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
             C_struct(ccx, &contents[..], false)
         }
+        UntaggedUnion(..) => {
+            unimplemented_unions!();
+        }
         Univariant(ref st) => {
             assert_eq!(discr, Disr(0));
             let contents = build_const_struct(ccx, st, vals);
@@ -1211,6 +1290,7 @@ pub fn const_get_field(r: &Repr, val: ValueRef, _discr: Disr,
     match *r {
         CEnum(..) => bug!("element access in C-like enum const"),
         Univariant(..) => const_struct_field(val, ix),
+        UntaggedUnion(..) => const_struct_field(val, 0),
         General(..) => const_struct_field(val, ix + 1),
         RawNullablePointer { .. } => {
             assert_eq!(ix, 0);
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index f30880ac9beb5..bd67a215d65eb 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1302,6 +1302,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     ]
                 }
             }
+            adt::UntaggedUnion(..) => {
+                unimplemented_unions!();
+            }
             adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
                 // As far as debuginfo is concerned, the pointer this enum
                 // represents is still wrapped in a struct. This is to make the
@@ -1616,7 +1619,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         },
         adt::RawNullablePointer { .. }           |
         adt::StructWrappedNullablePointer { .. } |
-        adt::Univariant(..)                      => None,
+        adt::Univariant(..) | adt::UntaggedUnion(..) => None,
         adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
     };
 
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
new file mode 100644
index 0000000000000..474c8b4b18103
--- /dev/null
+++ b/src/test/run-pass/union-basic.rs
@@ -0,0 +1,47 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::mem::{size_of, align_of, zeroed};
+
+union U {
+    a: u8,
+}
+
+union U64 {
+    a: u64,
+}
+
+union W {
+    a: u8,
+    b: u64,
+}
+
+fn main() {
+    assert_eq!(size_of::(), 1);
+    assert_eq!(size_of::(), 8);
+    assert_eq!(size_of::(), 8);
+    assert_eq!(align_of::(), 1);
+    assert_eq!(align_of::(), align_of::());
+    assert_eq!(align_of::(), align_of::());
+
+    let u = U { a: 10 };
+    assert_eq!(u.a, 10);
+    let U { a } = u;
+    assert_eq!(a, 10);
+
+    let mut w: W = unsafe { zeroed() };
+    assert_eq!(w.a, 0);
+    assert_eq!(w.b, 0);
+    // w.a = 1;
+    // assert_eq!(w.a, 0);
+    // assert_eq!(w.b, 0);
+}

From f3b41c18a8dfbcfec4b2a9e8d9e6a921189e3eea Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 18:31:47 +0300
Subject: [PATCH 504/768] Check fields in union patters/expressions

Make parsing of union items backward compatible
Add some tests
---
 src/librustc_typeck/check/_match.rs           | 49 ++++++++-------
 src/librustc_typeck/check/mod.rs              | 31 +++++-----
 src/libsyntax/parse/parser.rs                 |  4 +-
 src/test/compile-fail/issue-17800.rs          |  2 +-
 src/test/compile-fail/issue-19922.rs          |  2 +-
 src/test/compile-fail/issue-4736.rs           |  2 +-
 src/test/compile-fail/numeric-fields.rs       |  2 +-
 .../struct-fields-hints-no-dupe.rs            |  2 +-
 src/test/compile-fail/struct-fields-hints.rs  |  2 +-
 .../compile-fail/struct-fields-too-many.rs    |  2 +-
 .../compile-fail/suggest-private-fields.rs    |  8 +--
 src/test/compile-fail/union-empty.rs          | 15 +++++
 src/test/compile-fail/union-fields.rs         | 34 ++++++++++
 src/test/run-pass/union-backcomp.rs           | 23 +++++++
 src/test/run-pass/union-basic.rs              |  8 +++
 src/test/run-pass/union-drop.rs               | 26 ++++++++
 src/test/run-pass/union-pat-refutability.rs   | 62 +++++++++++++++++++
 17 files changed, 227 insertions(+), 47 deletions(-)
 create mode 100644 src/test/compile-fail/union-empty.rs
 create mode 100644 src/test/compile-fail/union-fields.rs
 create mode 100644 src/test/run-pass/union-backcomp.rs
 create mode 100644 src/test/run-pass/union-drop.rs
 create mode 100644 src/test/run-pass/union-pat-refutability.rs

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5fdfa19190bdb..5c19fa2a66cfc 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -11,7 +11,6 @@
 use hir::def::Def;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use hir::pat_util::EnumerateAndAdjustIterator;
-use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
 use check::{FnCtxt, Expectation};
 use lint;
@@ -509,11 +508,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
-        let substs = match pat_ty.sty {
-            ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs,
-            _ => span_bug!(pat.span, "struct variant is not an ADT")
-        };
-        self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
+        self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
     }
 
     fn check_pat_path(&self,
@@ -658,19 +653,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// `path` is the AST path item naming the type of this struct.
-    /// `fields` is the field patterns of the struct pattern.
-    /// `struct_fields` describes the type of each field of the struct.
-    /// `struct_id` is the ID of the struct.
-    /// `etc` is true if the pattern said '...' and false otherwise.
-    pub fn check_struct_pat_fields(&self,
-                                   span: Span,
-                                   fields: &'gcx [Spanned],
-                                   variant: ty::VariantDef<'tcx>,
-                                   substs: &Substs<'tcx>,
-                                   etc: bool) {
+    fn check_struct_pat_fields(&self,
+                               adt_ty: Ty<'tcx>,
+                               span: Span,
+                               variant: ty::VariantDef<'tcx>,
+                               fields: &'gcx [Spanned],
+                               etc: bool) {
         let tcx = self.tcx;
 
+        let (substs, kind_name) = match adt_ty.sty {
+            ty::TyEnum(_, substs) => (substs, "variant"),
+            ty::TyStruct(_, substs) => (substs, "struct"),
+            ty::TyUnion(_, substs) => (substs, "union"),
+            _ => span_bug!(span, "struct pattern is not an ADT")
+        };
+
         // Index the struct fields' types.
         let field_map = variant.fields
             .iter()
@@ -700,11 +697,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .map(|f| self.field_ty(span, f, substs))
                         .unwrap_or_else(|| {
                             struct_span_err!(tcx.sess, span, E0026,
-                                             "struct `{}` does not have a field named `{}`",
+                                             "{} `{}` does not have a field named `{}`",
+                                             kind_name,
                                              tcx.item_path_str(variant.did),
                                              field.name)
                                 .span_label(span,
-                                            &format!("struct `{}` does not have field `{}`",
+                                            &format!("{} `{}` does not have field `{}`",
+                                                     kind_name,
                                                      tcx.item_path_str(variant.did),
                                                      field.name))
                                 .emit();
@@ -717,8 +716,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_pat(&field.pat, field_ty);
         }
 
-        // Report an error if not all the fields were specified.
-        if !etc {
+        // Report an error if incorrect number of the fields were specified.
+        if kind_name == "union" {
+            if fields.len() > 1 {
+                tcx.sess.span_err(span, "union patterns can have at most one field");
+            }
+            if fields.is_empty() && !etc {
+                tcx.sess.span_err(span, "union patterns without `..` \
+                                         should have at least one field");
+            }
+        } else if !etc {
             for field in variant.fields
                 .iter()
                 .filter(|field| !used_fields.contains_key(&field.name)) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e2954cecc9c46..f8ee9efee7a5a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3109,17 +3109,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             ty: Ty<'tcx>,
                             variant: ty::VariantDef<'tcx>,
                             field: &hir::Field,
-                            skip_fields: &[hir::Field]) {
+                            skip_fields: &[hir::Field],
+                            kind_name: &str) {
         let mut err = self.type_error_struct_with_diag(
             field.name.span,
             |actual| if let ty::TyEnum(..) = ty.sty {
                 struct_span_err!(self.tcx.sess, field.name.span, E0559,
-                                 "struct variant `{}::{}` has no field named `{}`",
-                                 actual, variant.name.as_str(), field.name.node)
+                                 "{} `{}::{}` has no field named `{}`",
+                                 kind_name, actual, variant.name.as_str(), field.name.node)
             } else {
                 struct_span_err!(self.tcx.sess, field.name.span, E0560,
-                                 "structure `{}` has no field named `{}`",
-                                 actual, field.name.node)
+                                 "{} `{}` has no field named `{}`",
+                                 kind_name, actual, field.name.node)
             },
             ty);
         // prevent all specified fields from being suggested
@@ -3135,8 +3136,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 ast_fields: &'gcx [hir::Field],
                                 check_completeness: bool) {
         let tcx = self.tcx;
-        let substs = match adt_ty.sty {
-            ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs,
+        let (substs, kind_name) = match adt_ty.sty {
+            ty::TyEnum(_, substs) => (substs, "variant"),
+            ty::TyStruct(_, substs) => (substs, "struct"),
+            ty::TyUnion(_, substs) => (substs, "union"),
             _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
         };
 
@@ -3175,7 +3178,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                     err.emit();
                 } else {
-                    self.report_unknown_field(adt_ty, variant, field, ast_fields);
+                    self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name);
                 }
             }
 
@@ -3184,11 +3187,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_expr_coercable_to_type(&field.expr, expected_field_type);
         }
 
-            // Make sure the programmer specified all the fields.
-        if check_completeness &&
-            !error_happened &&
-            !remaining_fields.is_empty()
-        {
+        // Make sure the programmer specified correct number of fields.
+        if kind_name == "union" {
+            if ast_fields.len() != 1 {
+                tcx.sess.span_err(span, "union expressions should have exactly one field");
+            }
+        } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
             span_err!(tcx.sess, span, E0063,
                       "missing field{} {} in initializer of `{}`",
                       if remaining_fields.len() == 1 {""} else {"s"},
@@ -3198,7 +3202,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                       .join(", "),
                       adt_ty);
         }
-
     }
 
     fn check_struct_fields_on_error(&self,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 290a59cf1e591..ec9dc1bae5ad9 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5957,8 +5957,10 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return Ok(Some(item));
         }
-        if self.eat_keyword(keywords::Union) {
+        if self.check_keyword(keywords::Union) &&
+                self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
             // UNION ITEM
+            self.bump();
             let (ident, item_, extra_attrs) = self.parse_item_union()?;
             let last_span = self.last_span;
             let item = self.mk_item(lo,
diff --git a/src/test/compile-fail/issue-17800.rs b/src/test/compile-fail/issue-17800.rs
index 58d580a5c1a1c..d5f1614c14d2d 100644
--- a/src/test/compile-fail/issue-17800.rs
+++ b/src/test/compile-fail/issue-17800.rs
@@ -18,7 +18,7 @@ enum MyOption {
 fn main() {
     match MyOption::MySome(42) {
         MyOption::MySome { x: 42 } => (),
-        //~^ ERROR struct `MyOption::MySome` does not have a field named `x`
+        //~^ ERROR variant `MyOption::MySome` does not have a field named `x`
         //~| ERROR pattern does not mention field `0`
         _ => (),
     }
diff --git a/src/test/compile-fail/issue-19922.rs b/src/test/compile-fail/issue-19922.rs
index e3ced3028098b..a8350fe0986c0 100644
--- a/src/test/compile-fail/issue-19922.rs
+++ b/src/test/compile-fail/issue-19922.rs
@@ -14,5 +14,5 @@ enum Homura {
 
 fn main() {
     let homura = Homura::Akemi { kaname: () };
-    //~^ ERROR struct variant `Homura::Akemi` has no field named `kaname`
+    //~^ ERROR variant `Homura::Akemi` has no field named `kaname`
 }
diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs
index a8a1b1482fc08..c93e75042dd17 100644
--- a/src/test/compile-fail/issue-4736.rs
+++ b/src/test/compile-fail/issue-4736.rs
@@ -13,5 +13,5 @@
 struct NonCopyable(());
 
 fn main() {
-    let z = NonCopyable{ p: () }; //~ ERROR structure `NonCopyable` has no field named `p`
+    let z = NonCopyable{ p: () }; //~ ERROR struct `NonCopyable` has no field named `p`
 }
diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs
index 480d2dcddddd4..c4aff9471b8a1 100644
--- a/src/test/compile-fail/numeric-fields.rs
+++ b/src/test/compile-fail/numeric-fields.rs
@@ -13,7 +13,7 @@
 struct S(u8, u16);
 
 fn main() {
-    let s = S{0b1: 10, 0: 11}; //~ ERROR structure `S` has no field named `0b1`
+    let s = S{0b1: 10, 0: 11}; //~ ERROR struct `S` has no field named `0b1`
     match s {
         S{0: a, 0x1: b, ..} => {} //~ ERROR does not have a field named `0x1`
     }
diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
index 8df9ffd6cc73f..5f1f8ca856f9c 100644
--- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs
+++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
@@ -17,7 +17,7 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR structure `A` has no field named `bar`
+        bar : 42,//~ ERROR struct `A` has no field named `bar`
         //~^ HELP did you mean `barr`?
         car : 9,
     };
diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs
index 37001f1e60a0f..4ba1fd2f7bb33 100644
--- a/src/test/compile-fail/struct-fields-hints.rs
+++ b/src/test/compile-fail/struct-fields-hints.rs
@@ -17,7 +17,7 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR structure `A` has no field named `bar`
+        bar : 42,//~ ERROR struct `A` has no field named `bar`
         //~^ HELP did you mean `car`?
     };
 }
diff --git a/src/test/compile-fail/struct-fields-too-many.rs b/src/test/compile-fail/struct-fields-too-many.rs
index 9244a9d4f9d0f..5d16573f2f1e3 100644
--- a/src/test/compile-fail/struct-fields-too-many.rs
+++ b/src/test/compile-fail/struct-fields-too-many.rs
@@ -15,6 +15,6 @@ struct BuildData {
 fn main() {
     let foo = BuildData {
         foo: 0,
-        bar: 0 //~ ERROR structure `BuildData` has no field named `bar`
+        bar: 0 //~ ERROR struct `BuildData` has no field named `bar`
     };
 }
diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs
index 9c61f618e690f..41bd00a518c5c 100644
--- a/src/test/compile-fail/suggest-private-fields.rs
+++ b/src/test/compile-fail/suggest-private-fields.rs
@@ -22,16 +22,16 @@ struct A {
 fn main () {
     // external crate struct
     let k = B {
-        aa: 20, //~ ERROR structure `xc::B` has no field named `aa`
+        aa: 20, //~ ERROR struct `xc::B` has no field named `aa`
         //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR structure `xc::B` has no field named `bb`
+        bb: 20, //~ ERROR struct `xc::B` has no field named `bb`
         //~^ HELP did you mean `a`?
     };
     // local crate struct
     let l = A {
-        aa: 20, //~ ERROR structure `A` has no field named `aa`
+        aa: 20, //~ ERROR struct `A` has no field named `aa`
         //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR structure `A` has no field named `bb`
+        bb: 20, //~ ERROR struct `A` has no field named `bb`
         //~^ HELP did you mean `b`?
     };
 }
diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union-empty.rs
new file mode 100644
index 0000000000000..ce5bbf60fee25
--- /dev/null
+++ b/src/test/compile-fail/union-empty.rs
@@ -0,0 +1,15 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {} //~ ERROR unions cannot have zero fields
+
+fn main() {}
diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union-fields.rs
new file mode 100644
index 0000000000000..2bd1b8a7b32c2
--- /dev/null
+++ b/src/test/compile-fail/union-fields.rs
@@ -0,0 +1,34 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u16,
+}
+
+fn main() {
+    let u = U {}; //~ ERROR union expressions should have exactly one field
+    let u = U { a: 0 }; // OK
+    let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field
+    let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field
+                                    //~^ ERROR union `U` has no field named `c`
+    let u = U { ..u }; //~ ERROR union expressions should have exactly one field
+                       //~^ ERROR functional record update syntax requires a struct
+
+    let U {} = u; //~ ERROR union patterns without `..` should have at least one field
+    let U { a } = u; // OK
+    let U { a, b } = u; //~ ERROR union patterns can have at most one field
+    let U { a, b, c } = u; //~ ERROR union patterns can have at most one field
+                           //~^ ERROR union `U` does not have a field named `c`
+    let U { .. } = u; // OK
+    let U { a, .. } = u; // OK
+}
diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union-backcomp.rs
new file mode 100644
index 0000000000000..c1210dd621210
--- /dev/null
+++ b/src/test/run-pass/union-backcomp.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0  or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(untagged_unions)]
+
+fn main() {
+    let union = 10;
+
+    union;
+
+    union as u8;
+
+    union U {
+        a: u8,
+    }
+}
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index 474c8b4b18103..dee86b232b485 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -25,6 +25,12 @@ union W {
     b: u64,
 }
 
+#[repr(C)]
+union Y {
+    f1: u16,
+    f2: [u8; 4],
+}
+
 fn main() {
     assert_eq!(size_of::(), 1);
     assert_eq!(size_of::(), 8);
@@ -32,6 +38,8 @@ fn main() {
     assert_eq!(align_of::(), 1);
     assert_eq!(align_of::(), align_of::());
     assert_eq!(align_of::(), align_of::());
+    assert_eq!(size_of::(), 4);
+    assert_eq!(align_of::(), 2);
 
     let u = U { a: 10 };
     assert_eq!(u.a, 10);
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs
new file mode 100644
index 0000000000000..467403ff2e126
--- /dev/null
+++ b/src/test/run-pass/union-drop.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// Drop works for union itself.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+impl Drop for U {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    // 'unions are not fully implemented', src/librustc_trans/glue.rs:567
+    // let u = U { a: 1 };
+}
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs
new file mode 100644
index 0000000000000..6b39eed7ac942
--- /dev/null
+++ b/src/test/run-pass/union-pat-refutability.rs
@@ -0,0 +1,62 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[repr(u32)]
+enum Tag { I, F }
+
+#[repr(C)]
+union U {
+    i: i32,
+    f: f32,
+}
+
+#[repr(C)]
+struct Value {
+    tag: Tag,
+    u: U,
+}
+
+fn is_zero(v: Value) -> bool {
+    unsafe {
+        match v {
+            Value { tag: Tag::I, u: U { i: 0 } } => true,
+            Value { tag: Tag::F, u: U { f: 0.0 } } => true,
+            _ => false,
+        }
+    }
+}
+
+union W {
+    a: u8,
+    b: u8,
+}
+
+fn refut(w: W) {
+    match w {
+        W { a: 10 } => {
+            panic!();
+        }
+        W { b } => {
+            assert_eq!(b, 11);
+        }
+    }
+}
+
+fn main() {
+    // ICE
+    // let v = Value { tag: Tag::I, u: U { i: 1 } };
+    // assert_eq!(is_zero(v), false);
+
+    // ICE
+    // let w = W { a: 11 };
+    // refut(w);
+}

From e88d4ca0e1bb7c3b0a446788ea0c010aaea65ffc Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 20:12:28 +0300
Subject: [PATCH 505/768] Make accesses to union fields unsafe

---
 src/librustc/middle/effect.rs               | 24 +++++++++++++++++----
 src/test/compile-fail/union-unsafe.rs       | 23 ++++++++++++++++++++
 src/test/run-pass/union-basic.rs            | 20 ++++++++++-------
 src/test/run-pass/union-pat-refutability.rs | 14 ++++++------
 4 files changed, 63 insertions(+), 18 deletions(-)
 create mode 100644 src/test/compile-fail/union-unsafe.rs

diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 250ad80f5af6c..e52eba68da198 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -13,15 +13,14 @@
 use self::RootUnsafeContext::*;
 
 use dep_graph::DepNode;
-use hir::def::Def;
 use ty::{self, Ty, TyCtxt};
 use ty::MethodCall;
 
 use syntax::ast;
 use syntax_pos::Span;
-use hir;
-use hir::intravisit;
-use hir::intravisit::{FnKind, Visitor};
+use hir::{self, PatKind};
+use hir::def::Def;
+use hir::intravisit::{self, FnKind, Visitor};
 
 #[derive(Copy, Clone)]
 struct UnsafeContext {
@@ -178,11 +177,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                     self.require_unsafe(expr.span, "use of mutable static");
                 }
             }
+            hir::ExprField(ref base_expr, field) => {
+                if let ty::TyUnion(..) = self.tcx.expr_ty_adjusted(base_expr).sty {
+                    self.require_unsafe(field.span, "access to union field");
+                }
+            }
             _ => {}
         }
 
         intravisit::walk_expr(self, expr);
     }
+
+    fn visit_pat(&mut self, pat: &hir::Pat) {
+        if let PatKind::Struct(_, ref fields, _) = pat.node {
+            if let ty::TyUnion(..) = self.tcx.pat_ty(pat).sty {
+                for field in fields {
+                    self.require_unsafe(field.span, "matching on union field");
+                }
+            }
+        }
+
+        intravisit::walk_pat(self, pat);
+    }
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union-unsafe.rs
new file mode 100644
index 0000000000000..762ac5d875137
--- /dev/null
+++ b/src/test/compile-fail/union-unsafe.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0  or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+fn main() {
+    let u = U { a: 10 }; // OK
+    let a = u.a; //~ ERROR access to union field requires unsafe function or block
+    let U { a } = u; //~ ERROR matching on union field requires unsafe function or block
+    if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block
+    let U { .. } = u; // OK
+}
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index dee86b232b485..afbfe5bf92be7 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -42,14 +42,18 @@ fn main() {
     assert_eq!(align_of::(), 2);
 
     let u = U { a: 10 };
-    assert_eq!(u.a, 10);
-    let U { a } = u;
-    assert_eq!(a, 10);
+    unsafe {
+        assert_eq!(u.a, 10);
+        let U { a } = u;
+        assert_eq!(a, 10);
+    }
 
     let mut w: W = unsafe { zeroed() };
-    assert_eq!(w.a, 0);
-    assert_eq!(w.b, 0);
-    // w.a = 1;
-    // assert_eq!(w.a, 0);
-    // assert_eq!(w.b, 0);
+    unsafe {
+        assert_eq!(w.a, 0);
+        assert_eq!(w.b, 0);
+        // w.a = 1;
+        // assert_eq!(w.a, 0);
+        // assert_eq!(w.b, 0);
+    }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs
index 6b39eed7ac942..a57c1103a9b4a 100644
--- a/src/test/run-pass/union-pat-refutability.rs
+++ b/src/test/run-pass/union-pat-refutability.rs
@@ -41,12 +41,14 @@ union W {
 }
 
 fn refut(w: W) {
-    match w {
-        W { a: 10 } => {
-            panic!();
-        }
-        W { b } => {
-            assert_eq!(b, 11);
+    unsafe {
+        match w {
+            W { a: 10 } => {
+                panic!();
+            }
+            W { b } => {
+                assert_eq!(b, 11);
+            }
         }
     }
 }

From bea0b15935a8cb5811eb80e3220e9ab786feb782 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 19 Aug 2016 19:20:30 +0300
Subject: [PATCH 506/768] Implement drop translation and add lint for unions
 with drop fields

Fix some typeck bugs blocking drop tests
---
 src/librustc_lint/builtin.rs                  | 33 ++++++++++++++
 src/librustc_lint/lib.rs                      |  1 +
 src/librustc_trans/glue.rs                    | 17 ++++---
 src/librustc_typeck/check/mod.rs              |  9 ++--
 src/librustc_typeck/collect.rs                |  3 +-
 .../union-with-drop-fields-lint.rs            | 40 +++++++++++++++++
 src/test/run-pass/union-drop.rs               | 45 +++++++++++++++++--
 7 files changed, 134 insertions(+), 14 deletions(-)
 create mode 100644 src/test/compile-fail/union-with-drop-fields-lint.rs

diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index b55cad58e2fe4..1702c1c0edc9a 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1164,3 +1164,36 @@ impl LateLintPass for UnstableFeatures {
         }
     }
 }
+
+/// Lint for unions that contain fields with possibly non-trivial destructors.
+pub struct UnionsWithDropFields;
+
+declare_lint! {
+    UNIONS_WITH_DROP_FIELDS,
+    Warn,
+    "use of unions that contain fields with possibly non-trivial drop code"
+}
+
+impl LintPass for UnionsWithDropFields {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(UNIONS_WITH_DROP_FIELDS)
+    }
+}
+
+impl LateLintPass for UnionsWithDropFields {
+    fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
+        if let hir::ItemUnion(ref vdata, _) = item.node {
+            let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
+            for field in vdata.fields() {
+                let field_ty = ctx.tcx.node_id_to_type(field.id);
+                if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
+                    ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
+                                  field.span,
+                                  "union contains a field with possibly non-trivial drop code, \
+                                   drop code of union fields is ignored when dropping the union");
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 0f0e9cfb35773..c3b752d605f97 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -128,6 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                  InvalidNoMangleItems,
                  PluginAsLibrary,
                  MutableTransmutes,
+                 UnionsWithDropFields,
                  );
 
     add_builtin_with_new!(sess,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 5da9ef3646e6b..0d62a63b89fc9 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -267,7 +267,8 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
-                                 v0: ValueRef)
+                                 v0: ValueRef,
+                                 shallow_drop: bool)
                                  -> Block<'blk, 'tcx>
 {
     debug!("trans_struct_drop t: {}", t);
@@ -286,7 +287,9 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Issue #23611: schedule cleanup of contents, re-inspecting the
     // discriminant (if any) in case of variant swap in drop code.
-    bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
+    if !shallow_drop {
+        bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
+    }
 
     let (sized_args, unsized_args);
     let args: &[ValueRef] = if type_is_sized(tcx, t) {
@@ -470,9 +473,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                 trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
             }
         }
-        ty::TyUnion(..) => {
-            unimplemented_unions!();
-        }
         ty::TyTrait(..) => {
             // No support in vtable for distinguishing destroying with
             // versus without calling Drop::drop. Assert caller is
@@ -491,6 +491,13 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                 if def.dtor_kind().is_present() && !skip_dtor => {
             trans_struct_drop(bcx, t, v0)
         }
+        ty::TyUnion(def, _) => {
+            if def.dtor_kind().is_present() && !skip_dtor {
+                trans_struct_drop(bcx, t, v0, true)
+            } else {
+                bcx
+            }
+        }
         _ => {
             if bcx.fcx.type_needs_drop(t) {
                 drop_structural_ty(bcx, v0, t)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f8ee9efee7a5a..f4fea5542b3de 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3235,11 +3235,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 Some((type_did, self.tcx.expect_variant_def(def)))
             }
             Def::TyAlias(did) => {
-                if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did)
-                                                             .map(|scheme| &scheme.ty.sty) {
-                    Some((did, adt.struct_variant()))
-                } else {
-                    None
+                match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) {
+                    Some(&ty::TyStruct(adt, _)) |
+                    Some(&ty::TyUnion(adt, _)) => Some((did, adt.struct_variant())),
+                    _ => None,
                 }
             }
             _ => None
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a100c919d6f4e..31f28b3803d66 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1450,7 +1450,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
                     ItemTy(_, ref generics) |
                     ItemEnum(_, ref generics) |
-                    ItemStruct(_, ref generics) => {
+                    ItemStruct(_, ref generics) |
+                    ItemUnion(_, ref generics) => {
                         allow_defaults = true;
                         generics
                     }
diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union-with-drop-fields-lint.rs
new file mode 100644
index 0000000000000..87a72efbe08e5
--- /dev/null
+++ b/src/test/compile-fail/union-with-drop-fields-lint.rs
@@ -0,0 +1,40 @@
+// 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.
+
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+#![deny(unions_with_drop_fields)]
+
+union U {
+    a: u8, // OK
+}
+
+union W {
+    a: String, //~ ERROR union contains a field with possibly non-trivial drop code
+    b: String, // OK, only one field is reported
+}
+
+struct S(String);
+
+// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
+union Y {
+    a: S, //~ ERROR union contains a field with possibly non-trivial drop code
+}
+
+// We don't know if `T` is trivially-destructable or not until trans
+union J {
+    a: T, //~ ERROR union contains a field with possibly non-trivial drop code
+}
+
+union H {
+    a: T, // OK, `T` is `Copy`, no destructor
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs
index 467403ff2e126..2ca68dc3b6e39 100644
--- a/src/test/run-pass/union-drop.rs
+++ b/src/test/run-pass/union-drop.rs
@@ -12,15 +12,54 @@
 
 #![feature(untagged_unions)]
 
+struct S;
+
 union U {
     a: u8
 }
 
+union W {
+    a: S,
+}
+
+union Y {
+    a: S,
+}
+
+impl Drop for S {
+    fn drop(&mut self) {
+        unsafe { CHECK += 10; }
+    }
+}
+
 impl Drop for U {
-    fn drop(&mut self) {}
+    fn drop(&mut self) {
+        unsafe { CHECK += 1; }
+    }
 }
 
+impl Drop for W {
+    fn drop(&mut self) {
+        unsafe { CHECK += 1; }
+    }
+}
+
+static mut CHECK: u8 = 0;
+
 fn main() {
-    // 'unions are not fully implemented', src/librustc_trans/glue.rs:567
-    // let u = U { a: 1 };
+    unsafe {
+        assert_eq!(CHECK, 0);
+        {
+            let u = U { a: 1 };
+        }
+        assert_eq!(CHECK, 1); // 1, dtor of U is called
+        {
+            let w = W { a: S };
+        }
+        assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called
+        {
+            let y = Y { a: S };
+        }
+        assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called
+    }
 }

From 0cb19389b060c4d34c8e0654aabce8d39304ccca Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 19 Aug 2016 19:20:30 +0300
Subject: [PATCH 507/768] Fix buggy field access translation

---
 src/librustc/mir/repr.rs                     |  7 +++++--
 src/librustc/mir/tcx.rs                      |  2 +-
 src/librustc/mir/visit.rs                    |  3 ++-
 src/librustc_mir/build/expr/as_rvalue.rs     |  9 ++++++---
 src/librustc_mir/transform/deaggregator.rs   |  4 ++--
 src/librustc_mir/transform/qualify_consts.rs |  2 +-
 src/librustc_trans/mir/constant.rs           |  2 +-
 src/librustc_trans/mir/rvalue.rs             |  9 +++++----
 src/test/run-pass/union-basic.rs             |  6 +++---
 src/test/run-pass/union-pat-refutability.rs  | 10 ++++------
 10 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 8145c0aae3f74..a2abaa5e12f55 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -962,7 +962,10 @@ pub enum CastKind {
 pub enum AggregateKind<'tcx> {
     Vec,
     Tuple,
-    Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>),
+    /// The second field is variant number (discriminant), it's equal to 0
+    /// for struct and union expressions. The fourth field is active field
+    /// number and is present only for union expressions.
+    Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>, Option),
     Closure(DefId, ClosureSubsts<'tcx>),
 }
 
@@ -1069,7 +1072,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         }
                     }
 
-                    Adt(adt_def, variant, substs) => {
+                    Adt(adt_def, variant, substs, _) => {
                         let variant_def = &adt_def.variants[variant];
 
                         ppaux::parameterized(fmt, substs, variant_def.did,
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 76e5f8598c1c5..a0ccc72aa1fce 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -187,7 +187,7 @@ impl<'tcx> Rvalue<'tcx> {
                             ops.iter().map(|op| op.ty(mir, tcx)).collect()
                         ))
                     }
-                    AggregateKind::Adt(def, _, substs) => {
+                    AggregateKind::Adt(def, _, substs, _) => {
                         Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs))
                     }
                     AggregateKind::Closure(did, substs) => {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 2771880735c27..c2d0b2c686e77 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -536,7 +536,8 @@ macro_rules! make_mir_visitor {
                             }
                             AggregateKind::Adt(_adt_def,
                                                _variant_index,
-                                               ref $($mutability)* substs) => {
+                                               ref $($mutability)* substs,
+                                               _active_field_index) => {
                                 self.visit_substs(substs);
                             }
                             AggregateKind::Closure(ref $($mutability)* def_id,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index dafc53d3c1542..6ea1fb5036065 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -181,6 +181,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Adt {
                 adt_def, variant_index, substs, fields, base
             } => { // see (*) above
+                let is_union = adt_def.adt_kind() == ty::AdtKind::Union;
+                let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
+
                 // first process the set of fields that were provided
                 // (evaluating them in order given by user)
                 let fields_map: FnvHashMap<_, _> =
@@ -204,11 +207,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         })
                         .collect()
                 } else {
-                    field_names.iter().map(|n| fields_map[n].clone()).collect()
+                    field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
                 };
 
-                block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs),
-                                            fields))
+                let adt = AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
+                block.and(Rvalue::Aggregate(adt, fields))
             }
             ExprKind::Assign { .. } |
             ExprKind::AssignOp { .. } => {
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index cb3010a5cf43d..77af02c18c60e 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
                 _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
             };
             let (adt_def, variant, substs) = match agg_kind {
-                &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs),
+                &AggregateKind::Adt(adt_def, variant, substs, None) => (adt_def, variant, substs),
                 _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
             };
             let n = bb.statements.len();
@@ -120,7 +120,7 @@ fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
             _ => continue,
         };
         let (adt_def, variant) = match kind {
-            &AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant),
+            &AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
             _ => continue,
         };
         if operands.len() == 0 {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2fc90ab27a085..6c6a5f7fc74b0 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -705,7 +705,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             }
 
             Rvalue::Aggregate(ref kind, _) => {
-                if let AggregateKind::Adt(def, _, _) = *kind {
+                if let AggregateKind::Adt(def, _, _, _) = *kind {
                     if def.has_dtor() {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index ade266a580e78..15dc7bb4421c1 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -547,7 +547,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                                         self.monomorphize(&substs));
                 }
 
-                let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
+                let val = if let mir::AggregateKind::Adt(adt_def, index, _, _) = *kind {
                     let repr = adt::represent_type(self.ccx, dest_ty);
                     let disr = Disr::from(adt_def.variants[index].disr_val);
                     adt::trans_const(self.ccx, &repr, disr, &fields)
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 13484cb7a4ece..21b019d7e24df 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -110,9 +110,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
-                    mir::AggregateKind::Adt(adt_def, index, _) => {
+                    mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
                         let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
-                        let disr = Disr::from(adt_def.variants[index].disr_val);
+                        let disr = Disr::from(adt_def.variants[variant_index].disr_val);
                         bcx.with_block(|bcx| {
                             adt::trans_set_discr(bcx, &repr, dest.llval, Disr::from(disr));
                         });
@@ -121,8 +121,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             // Do not generate stores and GEPis for zero-sized fields.
                             if !common::type_is_zero_size(bcx.ccx(), op.ty) {
                                 let val = adt::MaybeSizedValue::sized(dest.llval);
-                                let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr,
-                                                                            val, disr, i);
+                                let field_index = active_field_index.unwrap_or(i);
+                                let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr, val,
+                                                                            disr, field_index);
                                 self.store_operand(&bcx, lldest_i, op);
                             }
                         }
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index afbfe5bf92be7..a00bd73115a1d 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -48,12 +48,12 @@ fn main() {
         assert_eq!(a, 10);
     }
 
-    let mut w: W = unsafe { zeroed() };
+    let mut w = W { b: 0 };
     unsafe {
         assert_eq!(w.a, 0);
         assert_eq!(w.b, 0);
         // w.a = 1;
-        // assert_eq!(w.a, 0);
-        // assert_eq!(w.b, 0);
+        assert_eq!(w.a, 0);
+        assert_eq!(w.b, 0);
     }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs
index a57c1103a9b4a..e6144f35f1d54 100644
--- a/src/test/run-pass/union-pat-refutability.rs
+++ b/src/test/run-pass/union-pat-refutability.rs
@@ -54,11 +54,9 @@ fn refut(w: W) {
 }
 
 fn main() {
-    // ICE
-    // let v = Value { tag: Tag::I, u: U { i: 1 } };
-    // assert_eq!(is_zero(v), false);
+    let v = Value { tag: Tag::I, u: U { i: 1 } };
+    assert_eq!(is_zero(v), false);
 
-    // ICE
-    // let w = W { a: 11 };
-    // refut(w);
+    let w = W { a: 11 };
+    refut(w);
 }

From 2dc2fc5fc528aab7ba138f1a351df6f846dfec1d Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 22 Aug 2016 15:17:05 +0300
Subject: [PATCH 508/768] Fix rebase

---
 src/librustc_metadata/encoder.rs | 33 +++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e82742004c39f..35f5eba4160d9 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1029,6 +1029,33 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                                               def_to_u64(ctor_did));
                 }
             }
+            hir::ItemUnion(..) => {
+                let def = ecx.tcx.lookup_adt_def(def_id);
+                let variant = def.struct_variant();
+
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'U');
+                self.encode_bounds_and_type_for_item(item.id);
+
+                encode_item_variances(self.rbml_w, ecx, item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                self.encode_visibility(vis);
+                self.encode_repr_attrs(&item.attrs);
+
+                /* Encode def_ids for each field and method
+                for methods, write all the stuff get_trait_method
+                needs to know*/
+                self.encode_struct_fields(variant);
+
+                encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
+                self.encode_mir(item.id);
+
+                // Encode inherent implementations for self union.
+                encode_inherent_implementations(ecx, self.rbml_w, def_id);
+            }
             hir::ItemDefaultImpl(unsafety, _) => {
                 encode_def_id_and_key(ecx, self.rbml_w, def_id);
                 encode_family(self.rbml_w, 'd');
@@ -1180,7 +1207,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                 self.encode_addl_struct_info(def_id, struct_def.id(), item);
             }
             hir::ItemUnion(..) => {
-                unimplemented_unions!();
+                self.encode_addl_union_info(def_id);
             }
             hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
                 self.encode_addl_impl_info(def_id, item.id, ast_items);
@@ -1217,6 +1244,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
         }
     }
 
+    fn encode_addl_union_info(&mut self, def_id: DefId) {
+        self.encode_fields(def_id);
+    }
+
     fn encode_addl_impl_info(&mut self,
                              def_id: DefId,
                              impl_id: ast::NodeId,

From d9b332bd69770cb716233b6998b11d345f6f184b Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 22 Aug 2016 19:56:14 +0300
Subject: [PATCH 509/768] Translate union constants

Fix alignment for packed unions
Add some missing privacy test
Get rid of `unimplemented_unions` macro
---
 src/librustc_const_eval/eval.rs              |  7 +-
 src/librustc_privacy/lib.rs                  |  5 +-
 src/librustc_trans/adt.rs                    | 23 +++++-
 src/librustc_trans/debuginfo/metadata.rs     |  9 ++-
 src/libsyntax/diagnostics/macros.rs          |  7 --
 src/libsyntax/feature_gate.rs                |  2 +-
 src/test/compile-fail/union-const-eval.rs    | 26 +++++++
 src/test/compile-fail/union-const-pat.rs     | 25 +++++++
 src/test/compile-fail/union-field-privacy.rs | 21 ++++++
 src/test/run-pass/union-const-trans.rs       | 27 +++++++
 src/test/run-pass/union-packed.rs            | 74 ++++++++++++++++++++
 11 files changed, 206 insertions(+), 20 deletions(-)
 create mode 100644 src/test/compile-fail/union-const-eval.rs
 create mode 100644 src/test/compile-fail/union-const-pat.rs
 create mode 100644 src/test/compile-fail/union-field-privacy.rs
 create mode 100644 src/test/run-pass/union-const-trans.rs
 create mode 100644 src/test/run-pass/union-packed.rs

diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 81fe19812ca47..114b5e1331de2 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -258,8 +258,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 format!("floating point constants cannot be used in patterns"));
         }
         ty::TyEnum(adt_def, _) |
-        ty::TyStruct(adt_def, _) |
-        ty::TyUnion(adt_def, _) => {
+        ty::TyStruct(adt_def, _) => {
             if !tcx.has_attr(adt_def.did, "structural_match") {
                 tcx.sess.add_lint(
                     lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
@@ -272,6 +271,10 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             tcx.item_path_str(adt_def.did)));
             }
         }
+        ty::TyUnion(..) => {
+            // Matching on union fields is unsafe, we can't hide it in constants
+            tcx.sess.span_err(span, "cannot use unions in constant patterns");
+        }
         _ => { }
     }
     let pat = match expr.node {
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 25601b6bfec7f..6b291c6930722 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -385,8 +385,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
     fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
         if def.adt_kind() != ty::AdtKind::Enum &&
            !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
-            struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
-                      field.name, self.tcx.item_path_str(def.did))
+            let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" };
+            struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
+                      field.name, kind_descr, self.tcx.item_path_str(def.did))
                 .span_label(span, &format!("field `{}` is private", field.name))
                 .emit();
         }
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index abbb9a5d4dbe5..7fd02ab82a3f8 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -516,7 +516,7 @@ fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     Union {
         min_size: min_size,
-        align: align,
+        align: if packed { 1 } else { align },
         packed: packed,
         fields: tys.to_vec(),
     }
@@ -1176,8 +1176,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
             contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
             C_struct(ccx, &contents[..], false)
         }
-        UntaggedUnion(..) => {
-            unimplemented_unions!();
+        UntaggedUnion(ref un) => {
+            assert_eq!(discr, Disr(0));
+            let contents = build_const_union(ccx, un, vals[0]);
+            C_struct(ccx, &contents, un.packed)
         }
         Univariant(ref st) => {
             assert_eq!(discr, Disr(0));
@@ -1272,6 +1274,21 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     cfields
 }
 
+fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                               un: &Union<'tcx>,
+                               field_val: ValueRef)
+                               -> Vec {
+    let mut cfields = vec![field_val];
+
+    let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
+    let size = roundup(un.min_size, un.align);
+    if offset != size {
+        cfields.push(padding(ccx, size - offset));
+    }
+
+    cfields
+}
+
 fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
     C_undef(Type::array(&Type::i8(ccx), size))
 }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index bd67a215d65eb..00493b018c10e 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -786,7 +786,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     usage_site_span).finalize(cx)
         }
         ty::TyUnion(..) => {
-            unimplemented_unions!();
+            unimplemented!();
         }
         ty::TyTuple(ref elements) => {
             prepare_tuple_metadata(cx,
@@ -1302,9 +1302,6 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     ]
                 }
             }
-            adt::UntaggedUnion(..) => {
-                unimplemented_unions!();
-            }
             adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
                 // As far as debuginfo is concerned, the pointer this enum
                 // represents is still wrapped in a struct. This is to make the
@@ -1421,7 +1418,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     }
                 ]
             },
-            adt::CEnum(..) => span_bug!(self.span, "This should be unreachable.")
+            adt::CEnum(..) | adt::UntaggedUnion(..) => {
+                span_bug!(self.span, "This should be unreachable.")
+            }
         }
     }
 }
diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs
index e2a7ec0a33de1..25e0428248df4 100644
--- a/src/libsyntax/diagnostics/macros.rs
+++ b/src/libsyntax/diagnostics/macros.rs
@@ -107,13 +107,6 @@ macro_rules! help {
     })
 }
 
-#[macro_export]
-macro_rules! unimplemented_unions {
-    () => ({
-        panic!("unions are not fully implemented");
-    })
-}
-
 #[macro_export]
 macro_rules! register_diagnostics {
     ($($code:tt),*) => (
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b40124bd7741a..287d33cc3e5b2 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -959,7 +959,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
             ast::ItemKind::Union(..) => {
                 gate_feature_post!(&self, untagged_unions,
                                    i.span,
-                                   "unions are unstable and not fully implemented");
+                                   "unions are unstable and possibly buggy");
             }
 
             ast::ItemKind::DefaultImpl(..) => {
diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union-const-eval.rs
new file mode 100644
index 0000000000000..b2bf173c59c86
--- /dev/null
+++ b/src/test/compile-fail/union-const-eval.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: usize,
+    b: usize,
+}
+
+const C: U = U { a: 10 };
+
+fn main() {
+    unsafe {
+        let a: [u8; C.a]; // OK
+        let b: [u8; C.b]; //~ ERROR constant evaluation error
+                          //~^ NOTE nonexistent struct field
+    }
+}
diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union-const-pat.rs
new file mode 100644
index 0000000000000..3d168980ed246
--- /dev/null
+++ b/src/test/compile-fail/union-const-pat.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: usize,
+    b: usize,
+}
+
+const C: U = U { a: 10 };
+
+fn main() {
+    match C {
+        C => {} //~ ERROR cannot use unions in constant patterns
+        _ => {}
+    }
+}
diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/compile-fail/union-field-privacy.rs
new file mode 100644
index 0000000000000..d1f2bbbc3d03c
--- /dev/null
+++ b/src/test/compile-fail/union-field-privacy.rs
@@ -0,0 +1,21 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        a: u8
+    }
+}
+
+fn main() {
+    let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
+}
diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union-const-trans.rs
new file mode 100644
index 0000000000000..bdae1a0eaf88f
--- /dev/null
+++ b/src/test/run-pass/union-const-trans.rs
@@ -0,0 +1,27 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u64,
+    b: u64,
+}
+
+const C: U = U { b: 10 };
+
+fn main() {
+    unsafe {
+        let a = C.a;
+        let b = C.b;
+        assert_eq!(a, 10);
+        assert_eq!(b, 10);
+     }
+}
diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union-packed.rs
new file mode 100644
index 0000000000000..b1650ae3a7c15
--- /dev/null
+++ b/src/test/run-pass/union-packed.rs
@@ -0,0 +1,74 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::mem::{size_of, size_of_val, align_of, align_of_val};
+
+struct S {
+    a: u16,
+    b: [u8; 3],
+}
+
+#[repr(packed)]
+struct Sp {
+    a: u16,
+    b: [u8; 3],
+}
+
+union U {
+    a: u16,
+    b: [u8; 3],
+}
+
+#[repr(packed)]
+union Up {
+    a: u16,
+    b: [u8; 3],
+}
+
+const CS: S = S { a: 0, b: [0, 0, 0] };
+const CSP: Sp = Sp { a: 0, b: [0, 0, 0] };
+const CU: U = U { b: [0, 0, 0] };
+const CUP: Up = Up { b: [0, 0, 0] };
+
+fn main() {
+    let s = S { a: 0, b: [0, 0, 0] };
+    assert_eq!(size_of::(), 6);
+    assert_eq!(size_of_val(&s), 6);
+    assert_eq!(size_of_val(&CS), 6);
+    assert_eq!(align_of::(), 2);
+    assert_eq!(align_of_val(&s), 2);
+    assert_eq!(align_of_val(&CS), 2);
+
+    let sp = Sp { a: 0, b: [0, 0, 0] };
+    assert_eq!(size_of::(), 5);
+    assert_eq!(size_of_val(&sp), 5);
+    assert_eq!(size_of_val(&CSP), 5);
+    assert_eq!(align_of::(), 1);
+    assert_eq!(align_of_val(&sp), 1);
+    assert_eq!(align_of_val(&CSP), 1);
+
+    let u = U { b: [0, 0, 0] };
+    assert_eq!(size_of::(), 4);
+    assert_eq!(size_of_val(&u), 4);
+    assert_eq!(size_of_val(&CU), 4);
+    assert_eq!(align_of::(), 2);
+    assert_eq!(align_of_val(&u), 2);
+    assert_eq!(align_of_val(&CU), 2);
+
+    let up = Up { b: [0, 0, 0] };
+    assert_eq!(size_of::(), 3);
+    assert_eq!(size_of_val(&up), 3);
+    assert_eq!(size_of_val(&CUP), 3);
+    assert_eq!(align_of::(), 1);
+    assert_eq!(align_of_val(&up), 1);
+    assert_eq!(align_of_val(&CUP), 1);
+}

From 079c390d5089735b5eaa8b06ddb3beedcddbee7d Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 22 Aug 2016 21:11:22 +0300
Subject: [PATCH 510/768] Generate debuginfo for unions

---
 src/librustc_trans/debuginfo/metadata.rs | 106 ++++++++++++++++++++++-
 src/test/debuginfo/union-smoke.rs        |  49 +++++++++++
 2 files changed, 153 insertions(+), 2 deletions(-)
 create mode 100644 src/test/debuginfo/union-smoke.rs

diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 00493b018c10e..bdfeee37625e8 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -786,7 +786,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     usage_site_span).finalize(cx)
         }
         ty::TyUnion(..) => {
-            unimplemented!();
+            prepare_union_metadata(cx,
+                                   t,
+                                   unique_type_id,
+                                   usage_site_span).finalize(cx)
         }
         ty::TyTuple(ref elements) => {
             prepare_tuple_metadata(cx,
@@ -1038,6 +1041,7 @@ enum MemberDescriptionFactory<'tcx> {
     StructMDF(StructMemberDescriptionFactory<'tcx>),
     TupleMDF(TupleMemberDescriptionFactory<'tcx>),
     EnumMDF(EnumMemberDescriptionFactory<'tcx>),
+    UnionMDF(UnionMemberDescriptionFactory<'tcx>),
     VariantMDF(VariantMemberDescriptionFactory<'tcx>)
 }
 
@@ -1054,6 +1058,9 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
             EnumMDF(ref this) => {
                 this.create_member_descriptions(cx)
             }
+            UnionMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
             VariantMDF(ref this) => {
                 this.create_member_descriptions(cx)
             }
@@ -1154,7 +1161,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     )
 }
 
-
 //=-----------------------------------------------------------------------------
 // Tuples
 //=-----------------------------------------------------------------------------
@@ -1209,6 +1215,66 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     )
 }
 
+//=-----------------------------------------------------------------------------
+// Unions
+//=-----------------------------------------------------------------------------
+
+struct UnionMemberDescriptionFactory<'tcx> {
+    variant: ty::VariantDef<'tcx>,
+    substs: &'tcx Substs<'tcx>,
+    span: Span,
+}
+
+impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
+                                      -> Vec {
+        self.variant.fields.iter().map(|field| {
+            let fty = monomorphize::field_ty(cx.tcx(), self.substs, field);
+            MemberDescription {
+                name: field.name.to_string(),
+                llvm_type: type_of::type_of(cx, fty),
+                type_metadata: type_metadata(cx, fty, self.span),
+                offset: FixedMemberOffset { bytes: 0 },
+                flags: FLAGS_NONE,
+            }
+        }).collect()
+    }
+}
+
+fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                                    union_type: Ty<'tcx>,
+                                    unique_type_id: UniqueTypeId,
+                                    span: Span)
+                                    -> RecursiveTypeDescription<'tcx> {
+    let union_name = compute_debuginfo_type_name(cx, union_type, false);
+    let union_llvm_type = type_of::in_memory_type_of(cx, union_type);
+
+    let (union_def_id, variant, substs) = match union_type.sty {
+        ty::TyUnion(def, substs) => (def.did, def.struct_variant(), substs),
+        _ => bug!("prepare_union_metadata on a non-union")
+    };
+
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id);
+
+    let union_metadata_stub = create_union_stub(cx,
+                                                union_llvm_type,
+                                                &union_name,
+                                                unique_type_id,
+                                                containing_scope);
+
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        union_type,
+        unique_type_id,
+        union_metadata_stub,
+        union_llvm_type,
+        UnionMDF(UnionMemberDescriptionFactory {
+            variant: variant,
+            substs: substs,
+            span: span,
+        })
+    )
+}
 
 //=-----------------------------------------------------------------------------
 // Enums
@@ -1798,6 +1864,42 @@ fn create_struct_stub(cx: &CrateContext,
     return metadata_stub;
 }
 
+fn create_union_stub(cx: &CrateContext,
+                     union_llvm_type: Type,
+                     union_type_name: &str,
+                     unique_type_id: UniqueTypeId,
+                     containing_scope: DIScope)
+                   -> DICompositeType {
+    let (union_size, union_align) = size_and_align_of(cx, union_llvm_type);
+
+    let unique_type_id_str = debug_context(cx).type_map
+                                              .borrow()
+                                              .get_unique_type_id_as_string(unique_type_id);
+    let name = CString::new(union_type_name).unwrap();
+    let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap();
+    let metadata_stub = unsafe {
+        // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
+        // pointer will lead to hard to trace and debug LLVM assertions
+        // later on in llvm/lib/IR/Value.cpp.
+        let empty_array = create_DIArray(DIB(cx), &[]);
+
+        llvm::LLVMRustDIBuilderCreateUnionType(
+            DIB(cx),
+            containing_scope,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            bytes_to_bits(union_size),
+            bytes_to_bits(union_align),
+            0, // Flags
+            empty_array,
+            0, // RuntimeLang
+            unique_type_id.as_ptr())
+    };
+
+    return metadata_stub;
+}
+
 /// Creates debug information for the given global variable.
 ///
 /// Adds the created metadata nodes directly to the crate's IR.
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
new file mode 100644
index 0000000000000..11ee5031ca771
--- /dev/null
+++ b/src/test/debuginfo/union-smoke.rs
@@ -0,0 +1,49 @@
+// 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.
+
+// min-lldb-version: 310
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:print u
+// gdb-check:$1 = {a = 11 '\v', b = 11}
+// gdb-command:print union_smoke::SU
+// gdb-check:$2 = {a = 10 '\n', b = 10}
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+// lldb-command:print a
+// lldb-check:[...]$0 = {a = 11 '\v', b = 11}
+// lldb-command:print union_smoke::SU
+// lldb-check:[...]$1 = {a = 10 '\n', b = 10}
+
+#![allow(unused)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+static SU: U = U { a: 10 };
+
+fn main() {
+    let u = U { b: 11 };
+
+    zzz(); // #break
+}
+
+fn zzz() {()}

From 59ccb7b6dbaf3a590cf3a234661aa7dcc2188aed Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Wed, 24 Aug 2016 21:10:19 +0300
Subject: [PATCH 511/768] Support deriving some traits for unions

---
 src/libsyntax_ext/deriving/generic/mod.rs | 11 +++++++-
 src/test/compile-fail/union-derive.rs     | 30 ++++++++++++++++++++++
 src/test/run-pass/union-derive.rs         | 31 +++++++++++++++++++++++
 3 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 src/test/compile-fail/union-derive.rs
 create mode 100644 src/test/run-pass/union-derive.rs

diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 5c636d43a7142..b37d533298399 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -410,9 +410,18 @@ impl<'a> TraitDef<'a> {
                     ast::ItemKind::Enum(ref enum_def, ref generics) => {
                         self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics)
                     }
+                    ast::ItemKind::Union(ref struct_def, ref generics) => {
+                        if self.supports_unions {
+                            self.expand_struct_def(cx, &struct_def, item.ident, generics)
+                        } else {
+                            cx.span_err(mitem.span,
+                                        "this trait cannot be derived for unions");
+                            return;
+                        }
+                    }
                     _ => {
                         cx.span_err(mitem.span,
-                                    "`derive` may only be applied to structs and enums");
+                                    "`derive` may only be applied to structs, enums and unions");
                         return;
                     }
                 };
diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union-derive.rs
new file mode 100644
index 0000000000000..0f78e96f640c7
--- /dev/null
+++ b/src/test/compile-fail/union-derive.rs
@@ -0,0 +1,30 @@
+// 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.
+
+// Most traits cannot be derived for unions.
+
+#![feature(untagged_unions)]
+
+#[derive(
+    Clone, //~ ERROR this trait cannot be derived for unions
+    PartialEq, //~ ERROR this trait cannot be derived for unions
+    Eq, //~ ERROR this trait cannot be derived for unions
+    PartialOrd, //~ ERROR this trait cannot be derived for unions
+    Ord, //~ ERROR this trait cannot be derived for unions
+    Hash, //~ ERROR this trait cannot be derived for unions
+    Default, //~ ERROR this trait cannot be derived for unions
+    Debug, //~ ERROR this trait cannot be derived for unions
+)]
+union U {
+    a: u8,
+    b: u16,
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union-derive.rs
new file mode 100644
index 0000000000000..b71c23990a474
--- /dev/null
+++ b/src/test/run-pass/union-derive.rs
@@ -0,0 +1,31 @@
+// 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.
+
+// Some traits can be derived for unions.
+
+#![feature(untagged_unions)]
+
+#[derive(
+    Copy,
+)]
+union U {
+    a: u8,
+    b: u16,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self { *self }
+}
+
+fn main() {
+    let u = U { b: 0 };
+    let u1 = u;
+    let u2 = u.clone();
+}

From 5f975e969b46278669940aa60e5aea50ba588531 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 16:54:58 +0300
Subject: [PATCH 512/768] Support unions in borrow checker

Add some more tests
---
 src/librustc_borrowck/borrowck/fragments.rs   |  4 +
 .../borrowck/gather_loans/restrictions.rs     | 30 +++++-
 src/librustc_borrowck/borrowck/mod.rs         |  5 -
 src/librustc_borrowck/borrowck/move_data.rs   | 57 ++++++++++-
 src/test/compile-fail/union-borrow-nested.rs  | 44 +++++++++
 src/test/compile-fail/union-borrow.rs         | 97 +++++++++++++++++++
 src/test/compile-fail/union-move-assign.rs    | 42 ++++++++
 src/test/compile-fail/union-move.rs           | 96 ++++++++++++++++++
 src/test/compile-fail/union-uninitialized.rs  | 30 ++++++
 src/test/run-pass/union-basic.rs              |  6 +-
 src/test/run-pass/union-drop-assign.rs        | 44 +++++++++
 src/test/run-pass/union-transmute.rs          | 40 ++++++++
 12 files changed, 484 insertions(+), 11 deletions(-)
 create mode 100644 src/test/compile-fail/union-borrow-nested.rs
 create mode 100644 src/test/compile-fail/union-borrow.rs
 create mode 100644 src/test/compile-fail/union-move-assign.rs
 create mode 100644 src/test/compile-fail/union-move.rs
 create mode 100644 src/test/compile-fail/union-uninitialized.rs
 create mode 100644 src/test/run-pass/union-drop-assign.rs
 create mode 100644 src/test/run-pass/union-transmute.rs

diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index a8993724e6706..86f396d8982b0 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -461,6 +461,10 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
             }
         }
 
+        (&ty::TyUnion(..), None) => {
+            // Do nothing, all union fields are moved/assigned together.
+        }
+
         (&ty::TyEnum(def, _), ref enum_variant_info) => {
             let variant = match *enum_variant_info {
                 Some((vid, ref _lp2)) => def.variant_with_id(vid),
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index d08f792b30c14..6193157fa7b36 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                 self.restrict(cmt_base)
             }
 
-            Categorization::Interior(cmt_base, i) => {
+            Categorization::Interior(cmt_base, interior) => {
                 // R-Field
                 //
                 // Overwriting the base would not change the type of
@@ -99,8 +99,34 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                     Categorization::Downcast(_, variant_id) => Some(variant_id),
                     _ => None
                 };
+                let interior = interior.cleaned();
+                let base_ty = cmt_base.ty;
                 let result = self.restrict(cmt_base);
-                self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
+                if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
+                    match result {
+                        RestrictionResult::Safe => RestrictionResult::Safe,
+                        RestrictionResult::SafeIf(base_lp, mut base_vec) => {
+                            for field in &adt_def.struct_variant().fields {
+                                let field = InteriorKind::InteriorField(mc::NamedField(field.name));
+                                let field_ty = if field == interior {
+                                    cmt.ty
+                                } else {
+                                    self.bccx.tcx.types.err // Doesn't matter
+                                };
+                                let sibling_lp_kind = LpExtend(base_lp.clone(), cmt.mutbl,
+                                                               LpInterior(opt_variant_id, field));
+                                let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
+                                base_vec.push(sibling_lp);
+                            }
+
+                            let lp = new_lp(LpExtend(base_lp, cmt.mutbl,
+                                                     LpInterior(opt_variant_id, interior)));
+                            RestrictionResult::SafeIf(lp, base_vec)
+                        }
+                    }
+                } else {
+                    self.extend(result, &cmt, LpInterior(opt_variant_id, interior))
+                }
             }
 
             Categorization::StaticItem => {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 67152ed04ec1d..f5e20285e0c1b 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -477,8 +477,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
                     base.common(&base2).map(|x| {
                         let xd = x.depth();
                         if base.depth() == xd && base2.depth() == xd {
-                            assert_eq!(base.ty, base2.ty);
-                            assert_eq!(self.ty, other.ty);
                             LoanPath {
                                 kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
                                 ty: self.ty,
@@ -495,7 +493,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
             (_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&other),
             (&LpVar(id), &LpVar(id2)) => {
                 if id == id2 {
-                    assert_eq!(self.ty, other.ty);
                     Some(LoanPath { kind: LpVar(id), ty: self.ty })
                 } else {
                     None
@@ -503,7 +500,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
             }
             (&LpUpvar(id), &LpUpvar(id2)) => {
                 if id == id2 {
-                    assert_eq!(self.ty, other.ty);
                     Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
                 } else {
                     None
@@ -1136,7 +1132,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 out.push(')');
             }
 
-
             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
                 match fname {
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index c9822a4fee749..b13291b8419d4 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -21,7 +21,8 @@ use rustc::middle::dataflow::DataFlowOperator;
 use rustc::middle::dataflow::KillFrom;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::expr_use_visitor::MutateMode;
-use rustc::ty::TyCtxt;
+use rustc::middle::mem_categorization as mc;
+use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
 use std::cell::RefCell;
@@ -364,6 +365,32 @@ impl<'a, 'tcx> MoveData<'tcx> {
                     lp: Rc>,
                     id: ast::NodeId,
                     kind: MoveKind) {
+        // Moving one union field automatically moves all its fields.
+        if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
+            if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty {
+                for field in &adt_def.struct_variant().fields {
+                    let field = InteriorKind::InteriorField(mc::NamedField(field.name));
+                    let field_ty = if field == interior {
+                        lp.ty
+                    } else {
+                        tcx.types.err // Doesn't matter
+                    };
+                    let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
+                                                   LpInterior(opt_variant_id, field));
+                    let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
+                    self.add_move_helper(tcx, sibling_lp, id, kind);
+                }
+                return;
+            }
+        }
+
+        self.add_move_helper(tcx, lp.clone(), id, kind);
+    }
+
+    fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                       lp: Rc>,
+                       id: ast::NodeId,
+                       kind: MoveKind) {
         debug!("add_move(lp={:?}, id={}, kind={:?})",
                lp,
                id,
@@ -393,6 +420,34 @@ impl<'a, 'tcx> MoveData<'tcx> {
                           span: Span,
                           assignee_id: ast::NodeId,
                           mode: euv::MutateMode) {
+        // Assigning to one union field automatically assigns to all its fields.
+        if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
+            if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty {
+                for field in &adt_def.struct_variant().fields {
+                    let field = InteriorKind::InteriorField(mc::NamedField(field.name));
+                    let field_ty = if field == interior {
+                        lp.ty
+                    } else {
+                        tcx.types.err // Doesn't matter
+                    };
+                    let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
+                                                   LpInterior(opt_variant_id, field));
+                    let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
+                    self.add_assignment_helper(tcx, sibling_lp, assign_id, span, assignee_id, mode);
+                }
+                return;
+            }
+        }
+
+        self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
+    }
+
+    pub fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 lp: Rc>,
+                                 assign_id: ast::NodeId,
+                                 span: Span,
+                                 assignee_id: ast::NodeId,
+                                 mode: euv::MutateMode) {
         debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
                lp, assign_id, assignee_id);
 
diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/union-borrow-nested.rs
new file mode 100644
index 0000000000000..19975d79b60be
--- /dev/null
+++ b/src/test/compile-fail/union-borrow-nested.rs
@@ -0,0 +1,44 @@
+// 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.
+
+// ignore-tidy-linelength
+
+#![feature(untagged_unions)]
+
+#[derive(Clone, Copy)]
+struct S {
+    a: u8,
+    b: u16,
+}
+
+union U {
+    s: S,
+    c: u32,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self { *self }
+}
+impl Copy for U {}
+
+fn main() {
+    unsafe {
+        {
+            let mut u = U { s: S { a: 0, b: 1 } };
+            let ra = &mut u.s.a;
+            let b = u.s.b; // OK
+        }
+        {
+            let mut u = U { s: S { a: 0, b: 1 } };
+            let ra = &mut u.s.a;
+            let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/union-borrow.rs
new file mode 100644
index 0000000000000..e8989a3c2d499
--- /dev/null
+++ b/src/test/compile-fail/union-borrow.rs
@@ -0,0 +1,97 @@
+// 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.
+
+// ignore-tidy-linelength
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self { *self }
+}
+impl Copy for U {}
+
+fn main() {
+    unsafe {
+        let mut u = U { b: 0 };
+        // Imm borrow, same field
+        {
+            let ra = &u.a;
+            let ra2 = &u.a; // OK
+        }
+        {
+            let ra = &u.a;
+            let a = u.a; // OK
+        }
+        {
+            let ra = &u.a;
+            let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
+        }
+        {
+            let ra = &u.a;
+            u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
+        }
+        // Imm borrow, other field
+        {
+            let ra = &u.a;
+            let rb = &u.b; // OK
+        }
+        {
+            let ra = &u.a;
+            let b = u.b; // OK
+        }
+        {
+            let ra = &u.a;
+            let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
+        }
+        {
+            let ra = &u.a;
+            u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
+        }
+        // Mut borrow, same field
+        {
+            let rma = &mut u.a;
+            let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
+        }
+        {
+            let ra = &mut u.a;
+            let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
+        }
+        {
+            let rma = &mut u.a;
+            let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
+        }
+        {
+            let rma = &mut u.a;
+            u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
+        }
+        // Mut borrow, other field
+        {
+            let rma = &mut u.a;
+            let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
+        }
+        {
+            let ra = &mut u.a;
+            let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
+        }
+        {
+            let rma = &mut u.a;
+            let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
+        }
+        {
+            let rma = &mut u.a;
+            u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/union-move-assign.rs
new file mode 100644
index 0000000000000..d4d7bc6b0f7c5
--- /dev/null
+++ b/src/test/compile-fail/union-move-assign.rs
@@ -0,0 +1,42 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+// Non-copy
+struct A;
+struct B;
+
+union U {
+    a: A,
+    b: B,
+}
+
+fn main() {
+    unsafe {
+        {
+            let mut u = U { a: A };
+            let a = u.a;
+            let a = u.a; //~ ERROR use of moved value: `u.a`
+        }
+        {
+            let mut u = U { a: A };
+            let a = u.a;
+            u.a = A;
+            let a = u.a; // OK
+        }
+        {
+            let mut u = U { a: A };
+            let a = u.a;
+            u.b = B;
+            let a = u.a; // OK
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/union-move.rs
new file mode 100644
index 0000000000000..5320244cf43b3
--- /dev/null
+++ b/src/test/compile-fail/union-move.rs
@@ -0,0 +1,96 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[derive(Clone, Copy)]
+struct Copy;
+struct NonCopy;
+
+union Unn {
+    n1: NonCopy,
+    n2: NonCopy,
+}
+union Ucc {
+    c1: Copy,
+    c2: Copy,
+}
+union Ucn {
+    c: Copy,
+    n: NonCopy,
+}
+
+fn main() {
+    unsafe {
+        // 2 NonCopy
+        {
+            let mut u = Unn { n1: NonCopy };
+            let a = u.n1;
+            let a = u.n1; //~ ERROR use of moved value: `u.n1`
+        }
+        {
+            let mut u = Unn { n1: NonCopy };
+            let a = u.n1;
+            let a = u; //~ ERROR use of partially moved value: `u`
+        }
+        {
+            let mut u = Unn { n1: NonCopy };
+            let a = u.n1;
+            let a = u.n2; //~ ERROR use of moved value: `u.n2`
+        }
+        // 2 Copy
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u.c1; // OK
+        }
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u; // OK
+        }
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u.c2; // OK
+        }
+        // 1 Copy, 1 NonCopy
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u.c; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u.n; //~ ERROR use of moved value: `u.n`
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u.c; //~ ERROR use of moved value: `u.c`
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u.n; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u; //~ ERROR use of partially moved value: `u`
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/union-uninitialized.rs
new file mode 100644
index 0000000000000..36e062f8464e9
--- /dev/null
+++ b/src/test/compile-fail/union-uninitialized.rs
@@ -0,0 +1,30 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+struct S {
+    a: u8,
+}
+
+union U {
+    a: u8,
+}
+
+fn main() {
+    unsafe {
+        let mut s: S;
+        let mut u: U;
+        s.a = 0;
+        u.a = 0;
+        let sa = s.a; //~ ERROR use of possibly uninitialized variable: `s.a`
+        let ua = u.a; //~ ERROR use of possibly uninitialized variable: `u.a`
+    }
+}
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index a00bd73115a1d..1651aa901b966 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -52,8 +52,8 @@ fn main() {
     unsafe {
         assert_eq!(w.a, 0);
         assert_eq!(w.b, 0);
-        // w.a = 1;
-        assert_eq!(w.a, 0);
-        assert_eq!(w.b, 0);
+        w.a = 1;
+        assert_eq!(w.a, 1);
+        assert_eq!(w.b, 1);
     }
 }
diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union-drop-assign.rs
new file mode 100644
index 0000000000000..0da68e43f32a1
--- /dev/null
+++ b/src/test/run-pass/union-drop-assign.rs
@@ -0,0 +1,44 @@
+// 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.
+
+// Drop works for union itself.
+
+#![feature(untagged_unions)]
+
+struct S;
+
+union U {
+    a: S
+}
+
+impl Drop for S {
+    fn drop(&mut self) {
+        unsafe { CHECK += 10; }
+    }
+}
+
+impl Drop for U {
+    fn drop(&mut self) {
+        unsafe { CHECK += 1; }
+    }
+}
+
+static mut CHECK: u8 = 0;
+
+fn main() {
+    unsafe {
+        let mut u = U { a: S };
+        assert_eq!(CHECK, 0);
+        u = U { a: S };
+        assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped
+        u.a = S;
+        assert_eq!(CHECK, 11); // union field is assigned, field is dropped
+    }
+}
diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union-transmute.rs
new file mode 100644
index 0000000000000..4eb66268ab8ea
--- /dev/null
+++ b/src/test/run-pass/union-transmute.rs
@@ -0,0 +1,40 @@
+// 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.
+
+#![feature(core_float)]
+#![feature(float_extras)]
+#![feature(untagged_unions)]
+
+extern crate core;
+use core::num::Float;
+
+union U {
+    a: (u8, u8),
+    b: u16,
+}
+
+union W {
+    a: u32,
+    b: f32,
+}
+
+fn main() {
+    unsafe {
+        let mut u = U { a: (1, 1) };
+        assert_eq!(u.b, (1 << 8) + 1);
+        u.b = (2 << 8) + 2;
+        assert_eq!(u.a, (2, 2));
+
+        let mut w = W { a: 0b0_11111111_00000000000000000000000 };
+        assert_eq!(w.b, f32::infinity());
+        w.b = f32::neg_infinity();
+        assert_eq!(w.a, 0b1_11111111_00000000000000000000000);
+    }
+}

From e67c2282afa3c527da49618b928280564e92868f Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 513/768] Fix rebase, fix some tests

---
 src/librustc_trans/adt.rs                      |  4 ++--
 src/librustc_trans/debuginfo/mod.rs            |  2 +-
 src/librustc_trans/glue.rs                     |  2 +-
 src/test/compile-fail/deriving-non-type.rs     | 18 +++++++++---------
 src/test/debuginfo/union-smoke.rs              | 17 +++++++++--------
 .../incremental/struct_change_field_name.rs    |  2 +-
 6 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 7fd02ab82a3f8..15a9d58c9b574 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -749,12 +749,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             };
             match name {
                 None => {
-                    TypeContext::direct(Type::struct_(cx, &[fill_ty], un.packed))
+                    Type::struct_(cx, &[fill_ty], un.packed)
                 }
                 Some(name) => {
                     let mut llty = Type::named_struct(cx, name);
                     llty.set_struct_body(&[fill_ty], un.packed);
-                    TypeContext::direct(llty)
+                    llty
                 }
             }
         }
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index a3a7a79fb58be..20a33498475a2 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -421,7 +421,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 // Only "class" methods are generally understood by LLVM,
                 // so avoid methods on other types (e.g. `<*mut T>::null`).
                 match impl_self_ty.sty {
-                    ty::TyStruct(..) | ty::TyEnum(..) => {
+                    ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => {
                         Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
                     }
                     _ => None
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 0d62a63b89fc9..bb77db8fd6947 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -489,7 +489,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
         }
         ty::TyStruct(def, _) | ty::TyEnum(def, _)
                 if def.dtor_kind().is_present() && !skip_dtor => {
-            trans_struct_drop(bcx, t, v0)
+            trans_struct_drop(bcx, t, v0, false)
         }
         ty::TyUnion(def, _) => {
             if def.dtor_kind().is_present() && !skip_dtor {
diff --git a/src/test/compile-fail/deriving-non-type.rs b/src/test/compile-fail/deriving-non-type.rs
index 5b215f3ccd961..84dd22435b888 100644
--- a/src/test/compile-fail/deriving-non-type.rs
+++ b/src/test/compile-fail/deriving-non-type.rs
@@ -12,29 +12,29 @@
 
 struct S;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 trait T { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 impl S { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 impl T for S { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 static s: usize = 0;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 const c: usize = 0;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 mod m { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 extern "C" { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 type A = usize;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 fn main() { }
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
index 11ee5031ca771..17dea300ff9d6 100644
--- a/src/test/debuginfo/union-smoke.rs
+++ b/src/test/debuginfo/union-smoke.rs
@@ -16,17 +16,17 @@
 
 // gdb-command:run
 // gdb-command:print u
-// gdb-check:$1 = {a = 11 '\v', b = 11}
+// gdb-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514}
 // gdb-command:print union_smoke::SU
-// gdb-check:$2 = {a = 10 '\n', b = 10}
+// gdb-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257}
 
 // === LLDB TESTS ==================================================================================
 
 // lldb-command:run
 // lldb-command:print a
-// lldb-check:[...]$0 = {a = 11 '\v', b = 11}
+// lldb-check:[...]$0 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514}
 // lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = {a = 10 '\n', b = 10}
+// lldb-check:[...]$1 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257}
 
 #![allow(unused)]
 #![feature(omit_gdb_pretty_printer_section)]
@@ -34,14 +34,15 @@
 #![feature(untagged_unions)]
 
 union U {
-    a: u8,
-    b: u64,
+    a: (u8, u8),
+    b: u16,
 }
 
-static SU: U = U { a: 10 };
+static mut SU: U = U { a: (1, 1) };
 
 fn main() {
-    let u = U { b: 11 };
+    let u = U { b: (2 << 8) + 2 };
+    unsafe { SU = U { a: (1, 1) } }
 
     zzz(); // #break
 }
diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs
index ba469c62002e4..c27294442e7a4 100644
--- a/src/test/incremental/struct_change_field_name.rs
+++ b/src/test/incremental/struct_change_field_name.rs
@@ -37,7 +37,7 @@ pub struct Y {
 #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
-    //[cfail2]~^ ERROR structure `X` has no field named `x`
+    //[cfail2]~^ ERROR struct `X` has no field named `x`
     x.x as u32
     //[cfail2]~^ ERROR attempted access of field `x`
 }

From 93067ca089ea570e4e2bdfc456958c81a4d1e092 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 514/768] Address comments and add requested tests

---
 src/librustc/middle/expr_use_visitor.rs       | 43 +++++-----
 src/librustc/ty/mod.rs                        |  2 +-
 .../borrowck/gather_loans/restrictions.rs     |  1 +
 src/librustc_borrowck/borrowck/move_data.rs   | 12 +--
 src/librustc_privacy/lib.rs                   | 23 +++---
 src/librustc_trans/glue.rs                    |  8 +-
 src/librustc_typeck/check/_match.rs           |  9 +--
 src/rt/rust_test_helpers.c                    | 21 +++++
 .../borrowck-union-borrow-nested.rs}          |  0
 .../borrowck-union-borrow.rs}                 |  0
 .../borrowck-union-move-assign.rs}            |  0
 .../borrowck-union-move.rs}                   |  0
 .../borrowck-union-uninitialized.rs}          |  0
 .../privacy/union-field-privacy-1.rs          | 30 +++++++
 .../privacy/union-field-privacy-2.rs          | 28 +++++++
 .../{ => union}/union-const-eval.rs           |  0
 .../{ => union}/union-const-pat.rs            |  0
 src/test/compile-fail/union/union-copy.rs     | 26 ++++++
 .../compile-fail/{ => union}/union-derive.rs  |  0
 .../compile-fail/{ => union}/union-empty.rs   |  0
 .../compile-fail/union/union-feature-gate.rs  | 15 ++++
 .../compile-fail/{ => union}/union-fields.rs  | 11 +--
 src/test/compile-fail/union/union-generic.rs  | 24 ++++++
 .../{ => union}/union-nonrepresentable.rs     |  0
 src/test/compile-fail/union/union-repr-c.rs   | 29 +++++++
 .../compile-fail/union/union-suggest-field.rs | 29 +++++++
 .../compile-fail/{ => union}/union-unsafe.rs  |  7 +-
 .../compile-fail/{ => union}/union-unsized.rs |  6 ++
 .../union-with-drop-fields-lint.rs            |  0
 .../run-pass/{ => union}/auxiliary/union.rs   |  0
 .../run-pass/{ => union}/union-backcomp.rs    |  4 +
 src/test/run-pass/{ => union}/union-basic.rs  |  0
 src/test/run-pass/union/union-c-interop.rs    | 47 +++++++++++
 .../run-pass/{ => union}/union-const-trans.rs |  0
 src/test/run-pass/{ => union}/union-derive.rs |  0
 .../run-pass/{ => union}/union-drop-assign.rs |  0
 src/test/run-pass/{ => union}/union-drop.rs   |  0
 src/test/run-pass/union/union-generic.rs      | 43 ++++++++++
 .../union/union-inherent-method.rs}           | 13 +--
 src/test/run-pass/union/union-macro.rs        | 33 ++++++++
 src/test/run-pass/union/union-overwrite.rs    | 80 +++++++++++++++++++
 src/test/run-pass/{ => union}/union-packed.rs | 30 +++++++
 .../{ => union}/union-pat-refutability.rs     |  0
 src/test/run-pass/union/union-trait-impl.rs   | 27 +++++++
 .../run-pass/{ => union}/union-transmute.rs   |  0
 .../union/union-with-drop-fields-lint.rs      | 42 ++++++++++
 src/test/run-pass/{ => union}/union-xcrate.rs |  0
 47 files changed, 582 insertions(+), 61 deletions(-)
 rename src/test/compile-fail/{union-borrow-nested.rs => borrowck/borrowck-union-borrow-nested.rs} (100%)
 rename src/test/compile-fail/{union-borrow.rs => borrowck/borrowck-union-borrow.rs} (100%)
 rename src/test/compile-fail/{union-move-assign.rs => borrowck/borrowck-union-move-assign.rs} (100%)
 rename src/test/compile-fail/{union-move.rs => borrowck/borrowck-union-move.rs} (100%)
 rename src/test/compile-fail/{union-uninitialized.rs => borrowck/borrowck-union-uninitialized.rs} (100%)
 create mode 100644 src/test/compile-fail/privacy/union-field-privacy-1.rs
 create mode 100644 src/test/compile-fail/privacy/union-field-privacy-2.rs
 rename src/test/compile-fail/{ => union}/union-const-eval.rs (100%)
 rename src/test/compile-fail/{ => union}/union-const-pat.rs (100%)
 create mode 100644 src/test/compile-fail/union/union-copy.rs
 rename src/test/compile-fail/{ => union}/union-derive.rs (100%)
 rename src/test/compile-fail/{ => union}/union-empty.rs (100%)
 create mode 100644 src/test/compile-fail/union/union-feature-gate.rs
 rename src/test/compile-fail/{ => union}/union-fields.rs (72%)
 create mode 100644 src/test/compile-fail/union/union-generic.rs
 rename src/test/compile-fail/{ => union}/union-nonrepresentable.rs (100%)
 create mode 100644 src/test/compile-fail/union/union-repr-c.rs
 create mode 100644 src/test/compile-fail/union/union-suggest-field.rs
 rename src/test/compile-fail/{ => union}/union-unsafe.rs (77%)
 rename src/test/compile-fail/{ => union}/union-unsized.rs (83%)
 rename src/test/compile-fail/{ => union}/union-with-drop-fields-lint.rs (100%)
 rename src/test/run-pass/{ => union}/auxiliary/union.rs (100%)
 rename src/test/run-pass/{ => union}/union-backcomp.rs (95%)
 rename src/test/run-pass/{ => union}/union-basic.rs (100%)
 create mode 100644 src/test/run-pass/union/union-c-interop.rs
 rename src/test/run-pass/{ => union}/union-const-trans.rs (100%)
 rename src/test/run-pass/{ => union}/union-derive.rs (100%)
 rename src/test/run-pass/{ => union}/union-drop-assign.rs (100%)
 rename src/test/run-pass/{ => union}/union-drop.rs (100%)
 create mode 100644 src/test/run-pass/union/union-generic.rs
 rename src/test/{compile-fail/union-field-privacy.rs => run-pass/union/union-inherent-method.rs} (78%)
 create mode 100644 src/test/run-pass/union/union-macro.rs
 create mode 100644 src/test/run-pass/union/union-overwrite.rs
 rename src/test/run-pass/{ => union}/union-packed.rs (81%)
 rename src/test/run-pass/{ => union}/union-pat-refutability.rs (100%)
 create mode 100644 src/test/run-pass/union/union-trait-impl.rs
 rename src/test/run-pass/{ => union}/union-transmute.rs (100%)
 create mode 100644 src/test/run-pass/union/union-with-drop-fields-lint.rs
 rename src/test/run-pass/{ => union}/union-xcrate.rs (100%)

diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index a6835802f1cf9..541aeeb7d8dd7 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -671,31 +671,28 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
         // Select just those fields of the `with`
         // expression that will actually be used
-        match with_cmt.ty.sty {
-            ty::TyStruct(def, substs) => {
-                // Consume those fields of the with expression that are needed.
-                for with_field in &def.struct_variant().fields {
-                    if !contains_field_named(with_field, fields) {
-                        let cmt_field = self.mc.cat_field(
-                            &*with_expr,
-                            with_cmt.clone(),
-                            with_field.name,
-                            with_field.ty(self.tcx(), substs)
-                        );
-                        self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
-                    }
+        if let ty::TyStruct(def, substs) = with_cmt.ty.sty {
+            // Consume those fields of the with expression that are needed.
+            for with_field in &def.struct_variant().fields {
+                if !contains_field_named(with_field, fields) {
+                    let cmt_field = self.mc.cat_field(
+                        &*with_expr,
+                        with_cmt.clone(),
+                        with_field.name,
+                        with_field.ty(self.tcx(), substs)
+                    );
+                    self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
                 }
             }
-            _ => {
-                // the base expression should always evaluate to a
-                // struct; however, when EUV is run during typeck, it
-                // may not. This will generate an error earlier in typeck,
-                // so we can just ignore it.
-                if !self.tcx().sess.has_errors() {
-                    span_bug!(
-                        with_expr.span,
-                        "with expression doesn't evaluate to a struct");
-                }
+        } else {
+            // the base expression should always evaluate to a
+            // struct; however, when EUV is run during typeck, it
+            // may not. This will generate an error earlier in typeck,
+            // so we can just ignore it.
+            if !self.tcx().sess.has_errors() {
+                span_bug!(
+                    with_expr.span,
+                    "with expression doesn't evaluate to a struct");
             }
         }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index ee2188e8e112c..e88f72f2d84bc 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1423,7 +1423,7 @@ bitflags! {
         const IS_PHANTOM_DATA     = 1 << 3,
         const IS_SIMD             = 1 << 4,
         const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_UNION            = 1 << 7,
+        const IS_UNION            = 1 << 6,
     }
 }
 
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index 6193157fa7b36..c08dc9330b8fd 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -102,6 +102,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                 let interior = interior.cleaned();
                 let base_ty = cmt_base.ty;
                 let result = self.restrict(cmt_base);
+                // Borrowing one union field automatically borrows all its fields.
                 if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
                     match result {
                         RestrictionResult::Safe => RestrictionResult::Safe,
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index b13291b8419d4..236a1a2835c2a 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -442,12 +442,12 @@ impl<'a, 'tcx> MoveData<'tcx> {
         self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
     }
 
-    pub fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 lp: Rc>,
-                                 assign_id: ast::NodeId,
-                                 span: Span,
-                                 assignee_id: ast::NodeId,
-                                 mode: euv::MutateMode) {
+    fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             lp: Rc>,
+                             assign_id: ast::NodeId,
+                             span: Span,
+                             assignee_id: ast::NodeId,
+                             mode: euv::MutateMode) {
         debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
                lp, assign_id, assignee_id);
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 6b291c6930722..179863c16fff2 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -429,19 +429,24 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 let method = self.tcx.tables.borrow().method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
-            hir::ExprStruct(_, ref fields, _) => {
+            hir::ExprStruct(_, ref expr_fields, _) => {
                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
-                // (i.e. `all_fields - fields`), just check them all.
-                for field in variant.fields.iter() {
-                    let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) {
-                        f.span
-                    } else {
-                        expr.span
-                    };
-                    self.check_field(span, adt, field);
+                // (i.e. `all_fields - fields`), just check them all,
+                // unless the ADT is a union, then unmentioned fields
+                // are not checked.
+                if adt.adt_kind() == ty::AdtKind::Union {
+                    for expr_field in expr_fields {
+                        self.check_field(expr.span, adt, variant.field_named(expr_field.name.node));
+                    }
+                } else {
+                    for field in &variant.fields {
+                        let expr_field = expr_fields.iter().find(|f| f.name.node == field.name);
+                        let span = if let Some(f) = expr_field { f.span } else { expr.span };
+                        self.check_field(span, adt, field);
+                    }
                 }
             }
             hir::ExprPath(..) => {
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index bb77db8fd6947..34c92f334d0ac 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -265,13 +265,13 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     fcx.finish(bcx, DebugLoc::None);
 }
 
-fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
                                  v0: ValueRef,
                                  shallow_drop: bool)
                                  -> Block<'blk, 'tcx>
 {
-    debug!("trans_struct_drop t: {}", t);
+    debug!("trans_custom_dtor t: {}", t);
     let tcx = bcx.tcx();
     let mut bcx = bcx;
 
@@ -489,11 +489,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
         }
         ty::TyStruct(def, _) | ty::TyEnum(def, _)
                 if def.dtor_kind().is_present() && !skip_dtor => {
-            trans_struct_drop(bcx, t, v0, false)
+            trans_custom_dtor(bcx, t, v0, false)
         }
         ty::TyUnion(def, _) => {
             if def.dtor_kind().is_present() && !skip_dtor {
-                trans_struct_drop(bcx, t, v0, true)
+                trans_custom_dtor(bcx, t, v0, true)
             } else {
                 bcx
             }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5c19fa2a66cfc..12fce4b928e08 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -718,12 +718,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Report an error if incorrect number of the fields were specified.
         if kind_name == "union" {
-            if fields.len() > 1 {
-                tcx.sess.span_err(span, "union patterns can have at most one field");
+            if fields.len() != 1 {
+                tcx.sess.span_err(span, "union patterns should have exactly one field");
             }
-            if fields.is_empty() && !etc {
-                tcx.sess.span_err(span, "union patterns without `..` \
-                                         should have at least one field");
+            if etc {
+                tcx.sess.span_err(span, "`..` cannot be used in union patterns");
             }
         } else if !etc {
             for field in variant.fields
diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c
index d2ebdcca80cf0..7a04d377608d4 100644
--- a/src/rt/rust_test_helpers.c
+++ b/src/rt/rust_test_helpers.c
@@ -247,3 +247,24 @@ double rust_interesting_average(uint64_t n, ...) {
 int32_t rust_int8_to_int32(int8_t x) {
     return (int32_t)x;
 }
+
+typedef union LARGE_INTEGER {
+  struct {
+    uint32_t LowPart;
+    uint32_t HighPart;
+  };
+  struct {
+    uint32_t LowPart;
+    uint32_t HighPart;
+  } u;
+  uint64_t QuadPart;
+} LARGE_INTEGER;
+
+LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) {
+    li.LowPart += 1;
+    li.HighPart += 1;
+    li.u.LowPart += 1;
+    li.u.HighPart += 1;
+    li.QuadPart += 1;
+    return li;
+}
diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs
similarity index 100%
rename from src/test/compile-fail/union-borrow-nested.rs
rename to src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs
diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
similarity index 100%
rename from src/test/compile-fail/union-borrow.rs
rename to src/test/compile-fail/borrowck/borrowck-union-borrow.rs
diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs
similarity index 100%
rename from src/test/compile-fail/union-move-assign.rs
rename to src/test/compile-fail/borrowck/borrowck-union-move-assign.rs
diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/borrowck/borrowck-union-move.rs
similarity index 100%
rename from src/test/compile-fail/union-move.rs
rename to src/test/compile-fail/borrowck/borrowck-union-move.rs
diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs
similarity index 100%
rename from src/test/compile-fail/union-uninitialized.rs
rename to src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs
diff --git a/src/test/compile-fail/privacy/union-field-privacy-1.rs b/src/test/compile-fail/privacy/union-field-privacy-1.rs
new file mode 100644
index 0000000000000..4924fabafb0a0
--- /dev/null
+++ b/src/test/compile-fail/privacy/union-field-privacy-1.rs
@@ -0,0 +1,30 @@
+// 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.
+
+#![feature(pub_restricted)]
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        pub a: u8,
+        pub(super) b: u8,
+        c: u8,
+    }
+}
+
+fn main() {
+    let u = m::U { a: 0 }; // OK
+    let u = m::U { b: 0 }; // OK
+    let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private
+
+    let m::U { a } = u; // OK
+    let m::U { b } = u; // OK
+    let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private
+}
diff --git a/src/test/compile-fail/privacy/union-field-privacy-2.rs b/src/test/compile-fail/privacy/union-field-privacy-2.rs
new file mode 100644
index 0000000000000..7151538f41256
--- /dev/null
+++ b/src/test/compile-fail/privacy/union-field-privacy-2.rs
@@ -0,0 +1,28 @@
+// 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.
+
+#![feature(pub_restricted)]
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        pub a: u8,
+        pub(super) b: u8,
+        c: u8,
+    }
+}
+
+fn main() {
+    let u = m::U { a: 10 };
+
+    let a = u.a; // OK
+    let b = u.b; // OK
+    let c = u.c; //~ ERROR field `c` of struct `m::U` is private
+}
diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union/union-const-eval.rs
similarity index 100%
rename from src/test/compile-fail/union-const-eval.rs
rename to src/test/compile-fail/union/union-const-eval.rs
diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union/union-const-pat.rs
similarity index 100%
rename from src/test/compile-fail/union-const-pat.rs
rename to src/test/compile-fail/union/union-const-pat.rs
diff --git a/src/test/compile-fail/union/union-copy.rs b/src/test/compile-fail/union/union-copy.rs
new file mode 100644
index 0000000000000..6e08ae0074d48
--- /dev/null
+++ b/src/test/compile-fail/union/union-copy.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+union W {
+    a: String
+}
+
+impl Clone for U { fn clone(&self) { panic!(); } }
+impl Clone for W { fn clone(&self) { panic!(); } }
+impl Copy for U {} // OK
+impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type
+
+fn main() {}
diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union/union-derive.rs
similarity index 100%
rename from src/test/compile-fail/union-derive.rs
rename to src/test/compile-fail/union/union-derive.rs
diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union/union-empty.rs
similarity index 100%
rename from src/test/compile-fail/union-empty.rs
rename to src/test/compile-fail/union/union-empty.rs
diff --git a/src/test/compile-fail/union/union-feature-gate.rs b/src/test/compile-fail/union/union-feature-gate.rs
new file mode 100644
index 0000000000000..abfc4d909218b
--- /dev/null
+++ b/src/test/compile-fail/union/union-feature-gate.rs
@@ -0,0 +1,15 @@
+// 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.
+
+union U { //~ ERROR unions are unstable and possibly buggy
+    a: u8,
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union/union-fields.rs
similarity index 72%
rename from src/test/compile-fail/union-fields.rs
rename to src/test/compile-fail/union/union-fields.rs
index 2bd1b8a7b32c2..a1721dda7decb 100644
--- a/src/test/compile-fail/union-fields.rs
+++ b/src/test/compile-fail/union/union-fields.rs
@@ -24,11 +24,12 @@ fn main() {
     let u = U { ..u }; //~ ERROR union expressions should have exactly one field
                        //~^ ERROR functional record update syntax requires a struct
 
-    let U {} = u; //~ ERROR union patterns without `..` should have at least one field
+    let U {} = u; //~ ERROR union patterns should have exactly one field
     let U { a } = u; // OK
-    let U { a, b } = u; //~ ERROR union patterns can have at most one field
-    let U { a, b, c } = u; //~ ERROR union patterns can have at most one field
+    let U { a, b } = u; //~ ERROR union patterns should have exactly one field
+    let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field
                            //~^ ERROR union `U` does not have a field named `c`
-    let U { .. } = u; // OK
-    let U { a, .. } = u; // OK
+    let U { .. } = u; //~ ERROR union patterns should have exactly one field
+                      //~^ ERROR `..` cannot be used in union patterns
+    let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns
 }
diff --git a/src/test/compile-fail/union/union-generic.rs b/src/test/compile-fail/union/union-generic.rs
new file mode 100644
index 0000000000000..e6586b0fb7f6a
--- /dev/null
+++ b/src/test/compile-fail/union/union-generic.rs
@@ -0,0 +1,24 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::rc::Rc;
+
+union U {
+    a: T
+}
+
+fn main() {
+    let u = U { a: Rc::new(0u32) };
+    //~^ ERROR  the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied
+    let u = U::> { a: Default::default() };
+    //~^ ERROR  the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied
+}
diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union/union-nonrepresentable.rs
similarity index 100%
rename from src/test/compile-fail/union-nonrepresentable.rs
rename to src/test/compile-fail/union/union-nonrepresentable.rs
diff --git a/src/test/compile-fail/union/union-repr-c.rs b/src/test/compile-fail/union/union-repr-c.rs
new file mode 100644
index 0000000000000..d7dfb126c9324
--- /dev/null
+++ b/src/test/compile-fail/union/union-repr-c.rs
@@ -0,0 +1,29 @@
+// 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.
+
+#![feature(untagged_unions)]
+#![allow(unused)]
+#![deny(improper_ctypes)]
+
+#[repr(C)]
+union U {
+    a: u8,
+}
+
+union W {
+    a: u8,
+}
+
+extern "C" {
+    static FOREIGN1: U; // OK
+    static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs
new file mode 100644
index 0000000000000..b05e9b6e27334
--- /dev/null
+++ b/src/test/compile-fail/union/union-suggest-field.rs
@@ -0,0 +1,29 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    principal: u8,
+}
+
+impl U {
+    fn calculate(&self) {}
+}
+
+fn main() {
+    let u = U { principle: 0 }; //~ ERROR union `U` has no field named `principle`
+                                //~^ HELP did you mean `principal`?
+    let w = u.principial; //~ ERROR attempted access of field `principial` on type `U`
+                          //~^ HELP did you mean `principal`?
+
+    let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
+                         //~^ HELP maybe a `()` to call it is missing?
+}
diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union/union-unsafe.rs
similarity index 77%
rename from src/test/compile-fail/union-unsafe.rs
rename to src/test/compile-fail/union/union-unsafe.rs
index 762ac5d875137..97e1ec2cba865 100644
--- a/src/test/compile-fail/union-unsafe.rs
+++ b/src/test/compile-fail/union/union-unsafe.rs
@@ -15,9 +15,10 @@ union U {
 }
 
 fn main() {
-    let u = U { a: 10 }; // OK
+    let mut u = U { a: 10 }; // OK
     let a = u.a; //~ ERROR access to union field requires unsafe function or block
+    u.a = 11; //~ ERROR access to union field requires unsafe function or block
     let U { a } = u; //~ ERROR matching on union field requires unsafe function or block
-    if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block
-    let U { .. } = u; // OK
+    if let U { a: 12 } = u {} //~ ERROR matching on union field requires unsafe function or block
+    // let U { .. } = u; // OK
 }
diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs
similarity index 83%
rename from src/test/compile-fail/union-unsized.rs
rename to src/test/compile-fail/union/union-unsized.rs
index 381122406d71f..a238eaf052508 100644
--- a/src/test/compile-fail/union-unsized.rs
+++ b/src/test/compile-fail/union/union-unsized.rs
@@ -12,6 +12,12 @@
 
 union U {
     a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+    b: u8,
+}
+
+union W {
+    a: u8,
+    b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union/union-with-drop-fields-lint.rs
similarity index 100%
rename from src/test/compile-fail/union-with-drop-fields-lint.rs
rename to src/test/compile-fail/union/union-with-drop-fields-lint.rs
diff --git a/src/test/run-pass/auxiliary/union.rs b/src/test/run-pass/union/auxiliary/union.rs
similarity index 100%
rename from src/test/run-pass/auxiliary/union.rs
rename to src/test/run-pass/union/auxiliary/union.rs
diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union/union-backcomp.rs
similarity index 95%
rename from src/test/run-pass/union-backcomp.rs
rename to src/test/run-pass/union/union-backcomp.rs
index c1210dd621210..9394b618ddf25 100644
--- a/src/test/run-pass/union-backcomp.rs
+++ b/src/test/run-pass/union/union-backcomp.rs
@@ -10,7 +10,11 @@
 
 #![feature(untagged_unions)]
 
+fn union() {}
+
 fn main() {
+    union();
+
     let union = 10;
 
     union;
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union/union-basic.rs
similarity index 100%
rename from src/test/run-pass/union-basic.rs
rename to src/test/run-pass/union/union-basic.rs
diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs
new file mode 100644
index 0000000000000..a9f97620ebd46
--- /dev/null
+++ b/src/test/run-pass/union/union-c-interop.rs
@@ -0,0 +1,47 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[derive(Copy)]
+#[repr(C)]
+struct LARGE_INTEGER_U {
+    LowPart: u32,
+    HighPart: u32,
+}
+
+#[derive(Copy)]
+#[repr(C)]
+union LARGE_INTEGER {
+  __unnamed__: LARGE_INTEGER_U,
+  u: LARGE_INTEGER_U,
+  QuadPart: u64,
+}
+
+impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } }
+impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } }
+
+#[link(name = "rust_test_helpers")]
+extern "C" {
+    fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER;
+}
+
+fn main() {
+    unsafe {
+        let mut li = LARGE_INTEGER { QuadPart: 0 };
+        let li_c = increment_all_parts(li);
+        li.__unnamed__.LowPart += 1;
+        li.__unnamed__.HighPart += 1;
+        li.u.LowPart += 1;
+        li.u.HighPart += 1;
+        li.QuadPart += 1;
+        assert_eq!(li.QuadPart, li_c.QuadPart);
+    }
+}
diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union/union-const-trans.rs
similarity index 100%
rename from src/test/run-pass/union-const-trans.rs
rename to src/test/run-pass/union/union-const-trans.rs
diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union/union-derive.rs
similarity index 100%
rename from src/test/run-pass/union-derive.rs
rename to src/test/run-pass/union/union-derive.rs
diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union/union-drop-assign.rs
similarity index 100%
rename from src/test/run-pass/union-drop-assign.rs
rename to src/test/run-pass/union/union-drop-assign.rs
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union/union-drop.rs
similarity index 100%
rename from src/test/run-pass/union-drop.rs
rename to src/test/run-pass/union/union-drop.rs
diff --git a/src/test/run-pass/union/union-generic.rs b/src/test/run-pass/union/union-generic.rs
new file mode 100644
index 0000000000000..9293805edbf83
--- /dev/null
+++ b/src/test/run-pass/union/union-generic.rs
@@ -0,0 +1,43 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union MaybeItem {
+    elem: T::Item,
+    none: (),
+}
+
+union U {
+    a: A,
+    b: B,
+}
+
+unsafe fn union_transmute(a: A) -> B {
+    U { a: a }.b
+}
+
+fn main() {
+    unsafe {
+        let u = U::> { a: String::from("abcd") };
+
+        assert_eq!(u.b.len(), 4);
+        assert_eq!(u.b[0], b'a');
+
+        let b = union_transmute::<(u8, u8), u16>((1, 1));
+        assert_eq!(b, (1 << 8) + 1);
+
+        let v: Vec = vec![1, 2, 3];
+        let mut i = v.iter();
+        i.next();
+        let mi = MaybeItem::> { elem: i.next().unwrap() };
+        assert_eq!(*mi.elem, 2);
+    }
+}
diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/run-pass/union/union-inherent-method.rs
similarity index 78%
rename from src/test/compile-fail/union-field-privacy.rs
rename to src/test/run-pass/union/union-inherent-method.rs
index d1f2bbbc3d03c..adea27bd25462 100644
--- a/src/test/compile-fail/union-field-privacy.rs
+++ b/src/test/run-pass/union/union-inherent-method.rs
@@ -10,12 +10,15 @@
 
 #![feature(untagged_unions)]
 
-mod m {
-    pub union U {
-        a: u8
-    }
+union U {
+    a: u8,
+}
+
+impl U {
+    fn method(&self) -> u8 { unsafe { self.a } }
 }
 
 fn main() {
-    let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
+    let u = U { a: 10 };
+    assert_eq!(u.method(), 10);
 }
diff --git a/src/test/run-pass/union/union-macro.rs b/src/test/run-pass/union/union-macro.rs
new file mode 100644
index 0000000000000..a23fbc3be9e2c
--- /dev/null
+++ b/src/test/run-pass/union/union-macro.rs
@@ -0,0 +1,33 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+macro_rules! duplicate {
+   ($i: item) => {
+        mod m1 {
+            $i
+        }
+        mod m2 {
+            $i
+        }
+   }
+}
+
+duplicate! {
+    pub union U {
+        pub a: u8
+    }
+}
+
+fn main() {
+    let u1 = m1::U { a: 0 };
+    let u2 = m2::U { a: 0 };
+}
diff --git a/src/test/run-pass/union/union-overwrite.rs b/src/test/run-pass/union/union-overwrite.rs
new file mode 100644
index 0000000000000..9389a6237bca6
--- /dev/null
+++ b/src/test/run-pass/union/union-overwrite.rs
@@ -0,0 +1,80 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[repr(C)]
+struct Pair(T, U);
+#[repr(C)]
+struct Triple(T, T, T);
+
+#[repr(C)]
+union U {
+    a: Pair,
+    b: B,
+}
+
+#[repr(C)]
+union W {
+    a: A,
+    b: B,
+}
+
+#[cfg(target_endian = "little")]
+unsafe fn check() {
+    let mut u = U:: { b: 0xDE_DE };
+    u.a.0 = 0xBE;
+    assert_eq!(u.b, 0xDE_BE);
+
+    let mut u = U:: { b: 0xDEAD_DEAD };
+    u.a.0 = 0xBEEF;
+    assert_eq!(u.b, 0xDEAD_BEEF);
+
+    let mut u = U:: { b: 0xDEADBEEF_DEADBEEF };
+    u.a.0 = 0xBAADF00D;
+    assert_eq!(u.b, 0xDEADBEEF_BAADF00D);
+
+    let mut w = W::, u8>, u32> { b: 0xDEAD_DEAD };
+    w.a.0 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0xDE00_0000);
+
+    let mut w = W::>, u32> { b: 0xDEAD_DEAD };
+    w.a.1 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0x0000_00AD);
+}
+
+#[cfg(target_endian = "big")]
+unsafe fn check() {
+    let mut u = U:: { b: 0xDE_DE };
+    u.a.0 = 0xBE;
+    assert_eq!(u.b, 0xBE_DE);
+
+    let mut u = U:: { b: 0xDEAD_DEAD };
+    u.a.0 = 0xBEEF;
+    assert_eq!(u.b, 0xBEEF_DEAD);
+
+    let mut u = U:: { b: 0xDEADBEEF_DEADBEEF };
+    u.a.0 = 0xBAADF00D;
+    assert_eq!(u.b, 0xBAADF00D_DEADBEEF);
+
+    let mut w = W::, u8>, u32> { b: 0xDEAD_DEAD };
+    w.a.0 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0x0000_00AD);
+
+    let mut w = W::>, u32> { b: 0xDEAD_DEAD };
+    w.a.1 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0xDE00_0000);
+}
+
+fn main() {
+    unsafe {
+        check();
+    }
+}
diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union/union-packed.rs
similarity index 81%
rename from src/test/run-pass/union-packed.rs
rename to src/test/run-pass/union/union-packed.rs
index b1650ae3a7c15..6a61280823e50 100644
--- a/src/test/run-pass/union-packed.rs
+++ b/src/test/run-pass/union/union-packed.rs
@@ -71,4 +71,34 @@ fn main() {
     assert_eq!(align_of::(), 1);
     assert_eq!(align_of_val(&up), 1);
     assert_eq!(align_of_val(&CUP), 1);
+
+    hybrid::check_hybrid();
+}
+
+mod hybrid {
+    use std::mem::size_of;
+
+    #[repr(packed)]
+    struct S1 {
+        a: u16,
+        b: u8,
+    }
+
+    #[repr(packed)]
+    union U {
+        s: S1,
+        c: u16,
+    }
+
+    #[repr(packed)]
+    struct S2 {
+        d: u8,
+        u: U,
+    }
+
+    pub fn check_hybrid() {
+        assert_eq!(size_of::(), 3);
+        assert_eq!(size_of::(), 3);
+        assert_eq!(size_of::(), 4);
+    }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union/union-pat-refutability.rs
similarity index 100%
rename from src/test/run-pass/union-pat-refutability.rs
rename to src/test/run-pass/union/union-pat-refutability.rs
diff --git a/src/test/run-pass/union/union-trait-impl.rs b/src/test/run-pass/union/union-trait-impl.rs
new file mode 100644
index 0000000000000..a5a2be0133aba
--- /dev/null
+++ b/src/test/run-pass/union/union-trait-impl.rs
@@ -0,0 +1,27 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::fmt;
+
+union U {
+    a: u8
+}
+
+impl fmt::Display for U {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        unsafe { write!(f, "Oh hai {}", self.a) }
+    }
+}
+
+fn main() {
+    assert_eq!(U { a: 2 }.to_string(), "Oh hai 2");
+}
diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs
similarity index 100%
rename from src/test/run-pass/union-transmute.rs
rename to src/test/run-pass/union/union-transmute.rs
diff --git a/src/test/run-pass/union/union-with-drop-fields-lint.rs b/src/test/run-pass/union/union-with-drop-fields-lint.rs
new file mode 100644
index 0000000000000..5a1424830d074
--- /dev/null
+++ b/src/test/run-pass/union/union-with-drop-fields-lint.rs
@@ -0,0 +1,42 @@
+// 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.
+
+// ignore-pretty
+
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+#![allow(unions_with_drop_fields)]
+
+union U {
+    a: u8, // OK
+}
+
+union W {
+    a: String, // OK
+    b: String, // OK
+}
+
+struct S(String);
+
+// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
+union Y {
+    a: S, // OK
+}
+
+// We don't know if `T` is trivially-destructable or not until trans
+union J {
+    a: T, // OK
+}
+
+union H {
+    a: T, // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-xcrate.rs b/src/test/run-pass/union/union-xcrate.rs
similarity index 100%
rename from src/test/run-pass/union-xcrate.rs
rename to src/test/run-pass/union/union-xcrate.rs

From 436cfe56534b405786816d4bbcccd11ed7571981 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 515/768] Fix type encoding/decoding for unions

Fix union debuginfo test on lldb
---
 src/librustc_metadata/decoder.rs           |  2 +-
 src/librustc_metadata/tydecode.rs          |  8 ++++
 src/librustc_metadata/tyencode.rs          |  2 +-
 src/test/debuginfo/union-smoke.rs          |  6 +--
 src/test/run-pass/union/auxiliary/union.rs |  2 +-
 src/test/run-pass/union/union-basic.rs     | 55 +++++++++++++---------
 src/test/run-pass/union/union-xcrate.rs    | 21 ---------
 7 files changed, 46 insertions(+), 50 deletions(-)
 delete mode 100644 src/test/run-pass/union/union-xcrate.rs

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 8775f58d0b22b..aeb95e5670d6a 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -291,7 +291,7 @@ fn maybe_item_name(item: rbml::Doc) -> Option {
 
 fn family_to_variant_kind<'tcx>(family: Family) -> Option {
     match family {
-        Struct(VariantKind::Struct) | Variant(VariantKind::Struct) =>
+        Struct(VariantKind::Struct) | Variant(VariantKind::Struct) | Union =>
             Some(ty::VariantKind::Struct),
         Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
             Some(ty::VariantKind::Tuple),
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index f51299226fe7d..55ff4817683de 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -472,6 +472,14 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 let def = self.tcx.lookup_adt_def(did);
                 return self.tcx.mk_struct(def, substs);
             }
+            'U' => {
+                assert_eq!(self.next(), '[');
+                let did = self.parse_def();
+                let substs = self.parse_substs();
+                assert_eq!(self.next(), ']');
+                let def = self.tcx.lookup_adt_def(did);
+                return self.tcx.mk_union(def, substs);
+            }
             'k' => {
                 assert_eq!(self.next(), '[');
                 let did = self.parse_def();
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index b334a21c07c7a..bef3cf3a1940f 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -171,7 +171,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
             write!(w, "]");
         }
         ty::TyUnion(def, substs) => {
-            write!(w, "u[{}|", (cx.ds)(cx.tcx, def.did));
+            write!(w, "U[{}|", (cx.ds)(cx.tcx, def.did));
             enc_substs(w, cx, substs);
             write!(w, "]");
         }
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
index 17dea300ff9d6..319927c979bf8 100644
--- a/src/test/debuginfo/union-smoke.rs
+++ b/src/test/debuginfo/union-smoke.rs
@@ -23,10 +23,10 @@
 // === LLDB TESTS ==================================================================================
 
 // lldb-command:run
-// lldb-command:print a
-// lldb-check:[...]$0 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514}
+// lldb-command:print u
+// lldb-check:[...]$0 = { a = ('\x02', '\x02') b = 514 }
 // lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257}
+// lldb-check:[...]$1 = 257
 
 #![allow(unused)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/run-pass/union/auxiliary/union.rs b/src/test/run-pass/union/auxiliary/union.rs
index dc0ca7c81c009..0231e38a729b7 100644
--- a/src/test/run-pass/union/auxiliary/union.rs
+++ b/src/test/run-pass/union/auxiliary/union.rs
@@ -12,5 +12,5 @@
 
 pub union U {
     pub a: u8,
-    b: u16,
+    pub b: u16,
 }
diff --git a/src/test/run-pass/union/union-basic.rs b/src/test/run-pass/union/union-basic.rs
index 1651aa901b966..d23af4b41b73f 100644
--- a/src/test/run-pass/union/union-basic.rs
+++ b/src/test/run-pass/union/union-basic.rs
@@ -8,47 +8,51 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// aux-build:union.rs
+
 #![feature(untagged_unions)]
 
+extern crate union;
 use std::mem::{size_of, align_of, zeroed};
 
 union U {
     a: u8,
+    b: u16
 }
 
-union U64 {
-    a: u64,
-}
+fn local() {
+    assert_eq!(size_of::(), 2);
+    assert_eq!(align_of::(), 2);
 
-union W {
-    a: u8,
-    b: u64,
-}
+    let u = U { a: 10 };
+    unsafe {
+        assert_eq!(u.a, 10);
+        let U { a } = u;
+        assert_eq!(a, 10);
+    }
 
-#[repr(C)]
-union Y {
-    f1: u16,
-    f2: [u8; 4],
+    let mut w = U { b: 0 };
+    unsafe {
+        assert_eq!(w.a, 0);
+        assert_eq!(w.b, 0);
+        w.a = 1;
+        assert_eq!(w.a, 1);
+        assert_eq!(w.b, 1);
+    }
 }
 
-fn main() {
-    assert_eq!(size_of::(), 1);
-    assert_eq!(size_of::(), 8);
-    assert_eq!(size_of::(), 8);
-    assert_eq!(align_of::(), 1);
-    assert_eq!(align_of::(), align_of::());
-    assert_eq!(align_of::(), align_of::());
-    assert_eq!(size_of::(), 4);
-    assert_eq!(align_of::(), 2);
+fn xcrate() {
+    assert_eq!(size_of::(), 2);
+    assert_eq!(align_of::(), 2);
 
-    let u = U { a: 10 };
+    let u = union::U { a: 10 };
     unsafe {
         assert_eq!(u.a, 10);
-        let U { a } = u;
+        let union::U { a } = u;
         assert_eq!(a, 10);
     }
 
-    let mut w = W { b: 0 };
+    let mut w = union::U { b: 0 };
     unsafe {
         assert_eq!(w.a, 0);
         assert_eq!(w.b, 0);
@@ -57,3 +61,8 @@ fn main() {
         assert_eq!(w.b, 1);
     }
 }
+
+fn main() {
+    local();
+    xcrate();
+}
diff --git a/src/test/run-pass/union/union-xcrate.rs b/src/test/run-pass/union/union-xcrate.rs
deleted file mode 100644
index 2a76c96ef25f5..0000000000000
--- a/src/test/run-pass/union/union-xcrate.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-// aux-build:union.rs
-
-// #![feature(untagged_unions)]
-
-extern crate union;
-
-type A = union::U;
-
-fn main() {
-    assert_eq!(std::mem::size_of::(), 8);
-}

From 9d9c029a6674787d600e0ea40baa9ca55eb87103 Mon Sep 17 00:00:00 2001
From: Cobrand 
Date: Sat, 3 Sep 2016 12:41:02 +0200
Subject: [PATCH 516/768] doc: Contributing.md: mention of `make tidy`

---
 CONTRIBUTING.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4e6cd6c9782a9..4c0f93c3703a5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -151,6 +151,10 @@ Some common make targets are:
   command above as we only build the stage1 compiler, not the entire thing).
   You can also leave off the `-rpass` to run all stage1 test types.
 - `make check-stage1-coretest` - Run stage1 tests in `libcore`.
+- `make tidy` - Check that the source code is in compliance with Rust's style
+  guidelines. There is no official document describing Rust's full guidelines 
+  as of yet, but basic rules like 4 spaces for indentation and no more than 99
+  characters in a single line should be kept in mind when writing code.
 
 ## Pull Requests
 
@@ -177,6 +181,15 @@ you’re adding something to the standard library, try
 
 This will not rebuild the compiler, but will run the tests.
 
+Please make sure your pull request is in compliance with Rust's style
+guidelines by running
+
+    $ make tidy
+
+Make this check before every pull request (and every new commit in a pull
+request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
+before every push to make sure you never forget to make this check.
+
 All pull requests are reviewed by another person. We have a bot,
 @rust-highfive, that will automatically assign a random person to review your
 request.

From 92aa7e42524ec0ce374a4463b8cff9a05b81af6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Marie?= 
Date: Sat, 3 Sep 2016 14:06:38 +0200
Subject: [PATCH 517/768] Use libraries from local-rust-root directory in
 configure when using --enable-local-rebuild

When using --enable-local-rebuild configure options, the configure
script will test rustc version. But when running it, it will not use the
libraries in the local-rust-root directory.

So use `LD_LIBRARY_PATH` environment variable to correct it.
---
 configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index bcc1faea3b5d8..97e7ca6eaabff 100755
--- a/configure
+++ b/configure
@@ -901,7 +901,7 @@ then
     fi
 
     CMD="${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF}"
-    LRV=`$CMD --version`
+    LRV=`LD_LIBRARY_PATH=${CFG_LOCAL_RUST_ROOT}/lib $CMD --version`
     if [ $? -ne 0 ]
     then
         step_msg "failure while running $CMD --version"

From 72da8b82c14772980956a808e93ed6258c5691ba Mon Sep 17 00:00:00 2001
From: Joseph Dunne 
Date: Fri, 2 Sep 2016 11:15:56 +0100
Subject: [PATCH 518/768] Add rustc version info (git hash + date) to dist
 tarball

fixes #32444
---
 mk/dist.mk            | 1 +
 src/bootstrap/dist.rs | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/mk/dist.mk b/mk/dist.mk
index e81371037ac2b..cb0bca01e6c4a 100644
--- a/mk/dist.mk
+++ b/mk/dist.mk
@@ -76,6 +76,7 @@ tmp/dist/$$(SRC_PKG_NAME)-image: $(PKG_FILES)
 	@$(call E, making src image)
 	$(Q)rm -Rf tmp/dist/$(SRC_PKG_NAME)-image
 	$(Q)mkdir -p tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust
+	$(Q)echo "$(CFG_VERSION)" > tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust/version
 	$(Q)tar \
          -C $(S) \
          -f - \
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 9d18901eb0002..31b7db168b48f 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -388,6 +388,9 @@ pub fn rust_src(build: &Build) {
     // Rename directory, so that root folder of tarball has the correct name
     t!(fs::rename(&dst_src, &plain_dst_src));
 
+    // Create the version file
+    write_file(&plain_dst_src.join("version"), build.version.as_bytes());
+
     // Create plain source tarball
     let mut cmd = Command::new("tar");
     cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name))))
@@ -431,3 +434,8 @@ fn sanitize_sh(path: &Path) -> String {
         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
     }
 }
+
+fn write_file(path: &Path, data: &[u8]) {
+    let mut vf = t!(fs::File::create(path));
+    t!(vf.write_all(data));
+}

From 216cf9c124f8f8dd3c8d7e99ad6e6821a02edcae Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Sat, 3 Sep 2016 16:15:22 +0200
Subject: [PATCH 519/768] Add missing urls

---
 src/libcollections/btree/map.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index 79840df1677ea..624083a8eaf35 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -56,8 +56,12 @@ use self::Entry::*;
 /// however, performance is excellent.
 ///
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
-/// any other key, as determined by the `Ord` trait, changes while it is in the map. This is
-/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
+/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
+/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+///
+/// [`Ord`]: ../../std/cmp/trait.Ord.html
+/// [`Cell`]: ../../std/cell/struct.Cell.html
+/// [`RefCell`]: ../../std/cell/struct.RefCell.html
 ///
 /// # Examples
 ///
@@ -2020,7 +2024,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
         self.key
     }
 
-    /// Sets the value of the entry with the VacantEntry's key,
+    /// Sets the value of the entry with the `VacantEntry`'s key,
     /// and returns a mutable reference to it.
     ///
     /// # Examples
@@ -2192,7 +2196,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
         self.handle.into_kv_mut().1
     }
 
-    /// Sets the value of the entry with the OccupiedEntry's key,
+    /// Sets the value of the entry with the `OccupiedEntry`'s key,
     /// and returns the entry's old value.
     ///
     /// # Examples

From 4ec715becfeb4426a36245f9147a8ba4d4448df7 Mon Sep 17 00:00:00 2001
From: Alex Crichton 
Date: Sat, 3 Sep 2016 10:23:40 -0700
Subject: [PATCH 520/768] Add back feature accidentally removed

This feature was accidentally removed in
https://github.com/rust-lang/rust/pull/35957.
---
 src/libsyntax/feature_gate.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 683d5277359e8..57db15f7947f2 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -305,6 +305,7 @@ declare_features! (
     (removed, struct_inherit, "1.0.0", None),
     (removed, test_removed_feature, "1.0.0", None),
     (removed, visible_private_types, "1.0.0", None),
+    (removed, unsafe_no_drop_flag, "1.0.0", None),
 );
 
 declare_features! (

From 5652b62a6b1531d95c10c6d62ea57d5af95cd8d7 Mon Sep 17 00:00:00 2001
From: Corey Farwell 
Date: Fri, 19 Aug 2016 21:43:21 -0400
Subject: [PATCH 521/768] Indicate where `core::result::IntoIter` is created.

---
 src/libcore/result.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 49eb5619bc6ba..94b6d5fa0031a 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -902,7 +902,13 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
-/// An iterator over the value in a `Ok` variant of a `Result`.
+/// An iterator over the value in a `Ok` variant of a `Result`. This struct is
+/// created by the [`into_iter`] method on [`Result`][`Result`] (provided by
+/// the [`IntoIterator`] trait).
+///
+/// [`Result`]: enum.Result.html
+/// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter
+/// [`IntoIterator`]: ../iter/trait.IntoIterator.html
 #[derive(Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter { inner: Option }

From fe8438d4a2c96295dcee95af415b9762c84ec6c6 Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Sat, 3 Sep 2016 15:29:16 -0700
Subject: [PATCH 522/768] Fix "field is never used" warning to take unions into
 account

Rather than saying "struct or union" or adding logic to determine the
type of the item, just change the message to "field is never used",
dropping the "struct".

Update tests accordingly.
---
 src/librustc/middle/dead.rs               |  2 +-
 src/test/compile-fail/lint-dead-code-4.rs | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 0b1d9e8d8f69e..80d45def960d4 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -548,7 +548,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
     fn visit_struct_field(&mut self, field: &hir::StructField) {
         if self.should_warn_about_field(&field) {
             self.warn_dead_code(field.id, field.span,
-                                field.name, "struct field");
+                                field.name, "field");
         }
 
         intravisit::walk_struct_field(self, field);
diff --git a/src/test/compile-fail/lint-dead-code-4.rs b/src/test/compile-fail/lint-dead-code-4.rs
index 20cd13c1875d6..3df089fc20048 100644
--- a/src/test/compile-fail/lint-dead-code-4.rs
+++ b/src/test/compile-fail/lint-dead-code-4.rs
@@ -14,7 +14,7 @@
 
 struct Foo {
     x: usize,
-    b: bool, //~ ERROR: struct field is never used
+    b: bool, //~ ERROR: field is never used
 }
 
 fn field_read(f: Foo) -> usize {
@@ -46,8 +46,8 @@ enum IJK {
     I, //~ ERROR variant is never used
     J {
         a: String,
-        b: i32, //~ ERROR struct field is never used
-        c: i32, //~ ERROR struct field is never used
+        b: i32, //~ ERROR field is never used
+        c: i32, //~ ERROR field is never used
     },
     K //~ ERROR variant is never used
 
@@ -68,9 +68,9 @@ fn field_match_in_patterns(b: XYZ) -> String {
 }
 
 struct Bar {
-    x: usize, //~ ERROR: struct field is never used
+    x: usize, //~ ERROR: field is never used
     b: bool,
-    c: bool, //~ ERROR: struct field is never used
+    c: bool, //~ ERROR: field is never used
     _guard: ()
 }
 

From 7c53eb97df4dc39c88e452d67b4f51d5bca336f6 Mon Sep 17 00:00:00 2001
From: ggomez 
Date: Mon, 29 Aug 2016 16:27:04 +0200
Subject: [PATCH 523/768] Add librustc metadata error codes to global check

---
 src/librustc_driver/lib.rs           | 1 +
 src/librustc_metadata/diagnostics.rs | 6 +++---
 src/librustc_metadata/lib.rs         | 2 ++
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 4e87c931cc19d..401069666301e 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -1134,6 +1134,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
+    all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
 
     Registry::new(&all_errors)
 }
diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs
index 3218930746683..01c7d7fc79d58 100644
--- a/src/librustc_metadata/diagnostics.rs
+++ b/src/librustc_metadata/diagnostics.rs
@@ -21,7 +21,7 @@ A link name was given with an empty name. Erroneous code example:
 The rust compiler cannot link to an external library if you don't give it its
 name. Example:
 
-```
+```ignore
 #[link(name = "some_lib")] extern {} // ok!
 ```
 "##,
@@ -72,7 +72,7 @@ A link was used without a name parameter. Erroneous code example:
 Please add the name parameter to allow the rust compiler to find the library
 you want. Example:
 
-```
+```ignore
 #[link(kind = "dylib", name = "some_lib")] extern {} // ok!
 ```
 "##,
@@ -121,7 +121,7 @@ macro_rules! get_pimientos {
 
 // In your crate:
 #[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
-extern crate some_crate;               // `get_pimientos` macros from some_crate.
+extern crate some_crate;               // `get_pimientos` macros from some_crate
 ```
 
 If you would like to import all exported macros, write `macro_use` with no
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index a96fa8a006d89..d27c0c0315354 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -63,3 +63,5 @@ pub mod index;
 pub mod loader;
 pub mod macro_import;
 pub mod tls_context;
+
+__build_diagnostic_array! { librustc_metadata, DIAGNOSTICS }

From 1eda14e4c9f8a315086cfa5986156cf693a2e92f Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Thu, 25 Aug 2016 13:06:38 +0200
Subject: [PATCH 524/768] E0060 and E0061 improvement

---
 src/librustc_typeck/check/mod.rs              | 20 ++++++++++---------
 src/test/compile-fail/E0060.rs                |  3 +--
 src/test/compile-fail/E0061.rs                | 10 ++++++++--
 src/test/compile-fail/issue-18819.rs          |  4 ++--
 src/test/compile-fail/issue-3044.rs           |  2 +-
 src/test/compile-fail/issue-4935.rs           |  1 -
 src/test/compile-fail/method-call-err-msg.rs  |  3 +--
 src/test/compile-fail/not-enough-arguments.rs |  4 ++--
 src/test/compile-fail/overloaded-calls-bad.rs |  2 --
 src/test/compile-fail/variadic-ffi-3.rs       |  8 ++++----
 10 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3d51da02b874d..0d2129b2cb418 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2481,16 +2481,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     if arg_count == 1 {" was"} else {"s were"}),
                 error_code);
 
-            err.span_label(sp, &format!("expected {}{} parameter{}",
-                                        if variadic {"at least "} else {""},
-                                        expected_count,
-                                        if expected_count == 1 {""} else {"s"}));
-
             let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::>();
-            if input_types.len() > 0 {
-                err.note(&format!("the following parameter type{} expected: {}",
-                        if expected_count == 1 {" was"} else {"s were"},
-                        input_types.join(", ")));
+            if input_types.len() > 1 {
+                err.note("the following parameter types were expected:");
+                err.note(&input_types.join(", "));
+            } else if input_types.len() > 0 {
+                err.note(&format!("the following parameter type was expected: {}",
+                                  input_types[0]));
+            } else {
+                err.span_label(sp, &format!("expected {}{} parameter{}",
+                                            if variadic {"at least "} else {""},
+                                            expected_count,
+                                            if expected_count == 1 {""} else {"s"}));
             }
             err.emit();
         }
diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs
index e1f2618c180f6..5182a2bf5a0a9 100644
--- a/src/test/compile-fail/E0060.rs
+++ b/src/test/compile-fail/E0060.rs
@@ -15,6 +15,5 @@ extern "C" {
 fn main() {
     unsafe { printf(); }
     //~^ ERROR E0060
-    //~| NOTE expected at least 1 parameter
-    //~| NOTE the following parameter type was expected
+    //~| NOTE the following parameter type was expected: *const u8
 }
diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs
index ca04b059dc7f6..4c7c0dfd44c51 100644
--- a/src/test/compile-fail/E0061.rs
+++ b/src/test/compile-fail/E0061.rs
@@ -10,9 +10,15 @@
 
 fn f(a: u16, b: &str) {}
 
+fn f2(a: u16) {}
+
 fn main() {
     f(0);
     //~^ ERROR E0061
-    //~| NOTE expected 2 parameters
-    //~| NOTE the following parameter types were expected
+    //~| NOTE the following parameter types were expected:
+    //~| NOTE u16, &str
+
+    f2();
+    //~^ ERROR E0061
+    //~| NOTE the following parameter type was expected: u16
 }
diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs
index cf650460c3de1..8035d798e32de 100644
--- a/src/test/compile-fail/issue-18819.rs
+++ b/src/test/compile-fail/issue-18819.rs
@@ -25,6 +25,6 @@ fn print_x(_: &Foo, extra: &str) {
 fn main() {
     print_x(X);
     //~^ ERROR this function takes 2 parameters but 1 parameter was supplied
-    //~| NOTE the following parameter types were expected: &Foo, &str
-    //~| NOTE expected 2 parameters
+    //~| NOTE the following parameter types were expected:
+    //~| NOTE &Foo, &str
 }
diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs
index d19e3b2c7b0a8..b934cbe4b5d87 100644
--- a/src/test/compile-fail/issue-3044.rs
+++ b/src/test/compile-fail/issue-3044.rs
@@ -15,6 +15,6 @@ fn main() {
     });
     //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied
     //~| NOTE the following parameter types were expected
-    //~| NOTE expected 2 parameters
+    //~| NOTE _, _
     // the first error is, um, non-ideal.
 }
diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs
index 58a84f3490b3c..08707a187dfd1 100644
--- a/src/test/compile-fail/issue-4935.rs
+++ b/src/test/compile-fail/issue-4935.rs
@@ -14,4 +14,3 @@ fn foo(a: usize) {}
 fn main() { foo(5, 6) }
 //~^ ERROR this function takes 1 parameter but 2 parameters were supplied
 //~| NOTE the following parameter type was expected
-//~| NOTE expected 1 parameter
diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs
index bcf676dbede6f..b7e0c5b81d918 100644
--- a/src/test/compile-fail/method-call-err-msg.rs
+++ b/src/test/compile-fail/method-call-err-msg.rs
@@ -23,10 +23,9 @@ fn main() {
      //~^ NOTE expected 0 parameters
      .one()     //~ ERROR this function takes 1 parameter but 0 parameters were supplied
      //~^ NOTE the following parameter type was expected
-     //~| NOTE expected 1 parameter
      .two(0);   //~ ERROR this function takes 2 parameters but 1 parameter was supplied
      //~^ NOTE the following parameter types were expected
-     //~| NOTE expected 2 parameters
+     //~| NOTE isize, isize
 
     let y = Foo;
     y.zero()
diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs
index f2f61fcaeec16..660d48da4dbc9 100644
--- a/src/test/compile-fail/not-enough-arguments.rs
+++ b/src/test/compile-fail/not-enough-arguments.rs
@@ -19,6 +19,6 @@ fn foo(a: isize, b: isize, c: isize, d:isize) {
 fn main() {
   foo(1, 2, 3);
   //~^ ERROR this function takes 4 parameters but 3
-  //~| NOTE the following parameter types were expected
-  //~| NOTE expected 4 parameters
+  //~| NOTE the following parameter types were expected:
+  //~| NOTE isize, isize, isize, isize
 }
diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs
index 1825ec61f1ed7..0aa9af3c8dad4 100644
--- a/src/test/compile-fail/overloaded-calls-bad.rs
+++ b/src/test/compile-fail/overloaded-calls-bad.rs
@@ -42,9 +42,7 @@ fn main() {
     let ans = s();
     //~^ ERROR this function takes 1 parameter but 0 parameters were supplied
     //~| NOTE the following parameter type was expected
-    //~| NOTE expected 1 parameter
     let ans = s("burma", "shave");
     //~^ ERROR this function takes 1 parameter but 2 parameters were supplied
     //~| NOTE the following parameter type was expected
-    //~| NOTE expected 1 parameter
 }
diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs
index cc9a7c84eded4..334b8bb08aea5 100644
--- a/src/test/compile-fail/variadic-ffi-3.rs
+++ b/src/test/compile-fail/variadic-ffi-3.rs
@@ -17,11 +17,11 @@ extern "C" fn bar(f: isize, x: u8) {}
 fn main() {
     unsafe {
         foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied
-        //~^ NOTE the following parameter types were expected
-        //~| NOTE expected at least 2 parameters
+               //~^ NOTE the following parameter types were expected:
+               //~| NOTE isize, u8
         foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied
-        //~^ NOTE the following parameter types were expected
-        //~| NOTE expected at least 2 parameters
+        //~^ NOTE the following parameter types were expected:
+        //~| NOTE isize, u8
 
         let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
         //~^ ERROR: mismatched types

From b66410043a8d2f352b8261f93c4227d48292df72 Mon Sep 17 00:00:00 2001
From: Jake Goldsborough 
Date: Sat, 3 Sep 2016 20:22:12 -0700
Subject: [PATCH 525/768] adding a check to bootstrap script and a check to the
 rust config script

---
 src/bootstrap/bootstrap.py | 9 +++++++++
 src/bootstrap/config.rs    | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 17a7c9ca66a26..3f4a18ab1247d 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -236,6 +236,15 @@ def rustc(self):
             return config + '/bin/rustc' + self.exe_suffix()
         return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix())
 
+    def nodejs(self):
+        config = self.get_toml('nodejs')
+        if config:
+            return config
+        if os.path.exists(os.path.join(self.bin_root(), "bin/nodejs")):
+            return os.path.join(self.bin_root(), "bin/nodejs" + self.exe_suffix())
+        elif os.path.exists(os.path.join(self.bin_root(), "bin/node")):
+            return os.path.join(self.bin_root(), "bin/node" + self.exe_suffix())
+
     def get_string(self, line):
         start = line.find('"')
         end = start + 1 + line[start+1:].find('"')
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 682a6f74126a8..5a7ae4f6973d5 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -67,6 +67,7 @@ pub struct Config {
     pub target: Vec,
     pub rustc: Option,
     pub cargo: Option,
+    pub nodejs: Option,
     pub local_rebuild: bool,
 
     // libstd features
@@ -111,6 +112,7 @@ struct Build {
     host: Vec,
     target: Vec,
     cargo: Option,
+    nodejs: Option,
     rustc: Option,
     compiler_docs: Option,
     docs: Option,
@@ -215,6 +217,7 @@ impl Config {
         }
         config.rustc = build.rustc.map(PathBuf::from);
         config.cargo = build.cargo.map(PathBuf::from);
+        config.nodejs = build.nodejs.map(PathBuf::from);
         set(&mut config.compiler_docs, build.compiler_docs);
         set(&mut config.docs, build.docs);
 

From ca5dfd0c975c80697dcc2a3bcbfc9d3106609fb1 Mon Sep 17 00:00:00 2001
From: Keunhong Lee 
Date: Sun, 4 Sep 2016 03:22:56 +0000
Subject: [PATCH 526/768] Allow CompilerControllers to access
 rustc_plugin::registry::Registry structure.

---
 src/librustc_driver/driver.rs   | 13 +++++++++----
 src/librustc_driver/test.rs     |  2 +-
 src/librustc_plugin/registry.rs |  4 ++--
 src/librustdoc/core.rs          |  2 +-
 src/librustdoc/test.rs          |  2 +-
 5 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 94092be4922b5..35284a88bd326 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -97,7 +97,7 @@ pub fn compile_input(sess: &Session,
             }
         };
 
-        let krate = {
+        let (krate, registry) = {
             let mut compile_state = CompileState::state_after_parse(input,
                                                                     sess,
                                                                     outdir,
@@ -109,14 +109,14 @@ pub fn compile_input(sess: &Session,
                                     compile_state,
                                     Ok(()));
 
-            compile_state.krate.unwrap()
+            (compile_state.krate.unwrap(), compile_state.registry)
         };
 
         let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
         let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input);
         let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
             phase_2_configure_and_expand(
-                sess, &cstore, krate, &crate_name, addl_plugins, control.make_glob_map,
+                sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
                 |expanded_crate| {
                     let mut state = CompileState::state_after_expand(
                         input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
@@ -329,6 +329,7 @@ pub struct CompileState<'a, 'b, 'ast: 'a, 'tcx: 'b> where 'ast: 'tcx {
     pub input: &'a Input,
     pub session: &'ast Session,
     pub krate: Option,
+    pub registry: Option>,
     pub cstore: Option<&'a CStore>,
     pub crate_name: Option<&'a str>,
     pub output_filenames: Option<&'a OutputFilenames>,
@@ -357,6 +358,7 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> {
             out_file: None,
             arenas: None,
             krate: None,
+            registry: None,
             cstore: None,
             crate_name: None,
             output_filenames: None,
@@ -379,6 +381,8 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> {
                          cstore: &'a CStore)
                          -> CompileState<'a, 'b, 'ast, 'tcx> {
         CompileState {
+            // Initialize the registry before moving `krate`
+            registry: Some(Registry::new(&session, krate.span)),
             krate: Some(krate),
             cstore: Some(cstore),
             out_file: out_file.as_ref().map(|s| &**s),
@@ -545,6 +549,7 @@ pub struct ExpansionResult<'a> {
 pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                            cstore: &CStore,
                                            mut krate: ast::Crate,
+                                           registry: Option,
                                            crate_name: &'a str,
                                            addl_plugins: Option>,
                                            make_glob_map: MakeGlobMap,
@@ -592,7 +597,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                    addl_plugins.take().unwrap())
     });
 
-    let mut registry = Registry::new(sess, &krate);
+    let mut registry = registry.unwrap_or(Registry::new(sess, krate.span));
 
     time(time_passes, "plugin registration", || {
         if sess.features.borrow().rustc_diagnostic_macros {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 460a6e68a5c5a..2d04b8d1362f2 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -115,7 +115,7 @@ fn test_env(source_string: &str,
     let krate = driver::phase_1_parse_input(&sess, krate_config, &input).unwrap();
     let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
         driver::phase_2_configure_and_expand(
-            &sess, &cstore, krate, "test", None, MakeGlobMap::No, |_| Ok(()),
+            &sess, &cstore, krate, None, "test", None, MakeGlobMap::No, |_| Ok(()),
         ).expect("phase 2 aborted")
     };
     let _ignore = dep_graph.in_ignore();
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 5ae6584aed425..6fa42e7bcd775 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -69,11 +69,11 @@ pub struct Registry<'a> {
 
 impl<'a> Registry<'a> {
     #[doc(hidden)]
-    pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
+    pub fn new(sess: &'a Session, krate_span: Span) -> Registry<'a> {
         Registry {
             sess: sess,
             args_hidden: None,
-            krate_span: krate.span,
+            krate_span: krate_span,
             syntax_exts: vec!(),
             early_lint_passes: vec!(),
             late_lint_passes: vec!(),
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 26f792a1fdf99..0c236434cc705 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -146,7 +146,7 @@ pub fn run_core(search_paths: SearchPaths,
 
     let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
         driver::phase_2_configure_and_expand(
-            &sess, &cstore, krate, &name, None, resolve::MakeGlobMap::No, |_| Ok(()),
+            &sess, &cstore, krate, None, &name, None, resolve::MakeGlobMap::No, |_| Ok(()),
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index beed1dc9f9e71..e4dd41d7e4c3e 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -94,7 +94,7 @@ pub fn run(input: &str,
     let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
     let driver::ExpansionResult { defs, mut hir_forest, .. } = {
         phase_2_configure_and_expand(
-            &sess, &cstore, krate, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
+            &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 

From 6f7e51e49b7d74f8112cf048fcbd377d0db7c326 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 527/768] Replace `_, _, _` with `..`

---
 src/librustc/hir/def.rs                            |  2 +-
 src/librustc/hir/intravisit.rs                     |  6 +++---
 src/librustc/hir/pat_util.rs                       |  2 +-
 src/librustc/infer/error_reporting.rs              |  4 ++--
 src/librustc/infer/mod.rs                          |  2 +-
 src/librustc/lib.rs                                |  1 +
 src/librustc/middle/dead.rs                        |  4 ++--
 src/librustc/middle/effect.rs                      |  4 ++--
 src/librustc/middle/expr_use_visitor.rs            |  2 +-
 src/librustc/middle/reachable.rs                   | 14 +++++++-------
 src/librustc/middle/resolve_lifetime.rs            |  8 ++++----
 src/librustc/middle/stability.rs                   |  6 +++---
 src/librustc/ty/mod.rs                             | 10 +++++-----
 src/librustc_borrowck/borrowck/mir/mod.rs          |  4 ++--
 src/librustc_borrowck/borrowck/mod.rs              |  2 +-
 src/librustc_borrowck/lib.rs                       |  1 +
 src/librustc_const_eval/eval.rs                    |  2 +-
 src/librustc_const_eval/lib.rs                     |  2 +-
 src/librustc_lint/bad_style.rs                     |  4 ++--
 src/librustc_lint/builtin.rs                       | 12 ++++++------
 src/librustc_lint/lib.rs                           |  1 +
 src/librustc_metadata/encoder.rs                   |  8 ++++----
 src/librustc_metadata/lib.rs                       |  1 +
 src/librustc_mir/hair/cx/mod.rs                    |  2 +-
 src/librustc_mir/lib.rs                            |  1 +
 src/librustc_mir/transform/qualify_consts.rs       |  2 +-
 src/librustc_passes/ast_validation.rs              | 10 +++++-----
 src/librustc_passes/consts.rs                      |  2 +-
 src/librustc_passes/lib.rs                         |  1 +
 src/librustc_privacy/lib.rs                        | 13 +++++++------
 src/librustc_resolve/build_reduced_graph.rs        |  4 ++--
 src/librustc_resolve/lib.rs                        |  5 +++--
 src/librustc_save_analysis/dump_visitor.rs         |  2 +-
 src/librustc_save_analysis/lib.rs                  |  7 ++++---
 src/librustc_trans/collector.rs                    |  4 ++--
 src/librustc_trans/lib.rs                          |  1 +
 src/librustc_typeck/astconv.rs                     |  2 +-
 src/librustc_typeck/check/mod.rs                   |  8 ++++----
 src/librustc_typeck/check/wfcheck.rs               |  4 ++--
 src/librustc_typeck/coherence/mod.rs               | 10 +++++-----
 src/librustc_typeck/coherence/orphan.rs            |  4 ++--
 src/librustc_typeck/coherence/overlap.rs           |  2 +-
 src/librustc_typeck/coherence/unsafety.rs          |  2 +-
 src/librustc_typeck/collect.rs                     | 10 +++++-----
 src/librustc_typeck/lib.rs                         |  5 +++--
 src/libstd/lib.rs                                  |  1 +
 src/libstd/sys/windows/fs.rs                       |  2 +-
 src/libsyntax/ast.rs                               |  2 +-
 .../auxiliary/macro_crate_test.rs                  |  5 +++--
 .../auxiliary/macro_crate_test.rs                  |  7 ++++---
 50 files changed, 117 insertions(+), 103 deletions(-)

diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index aa0eac37ecff1..71bc2693abd27 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -124,7 +124,7 @@ impl Def {
             Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
             Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
             Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
-            Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
+            Def::Local(id, _) | Def::Upvar(id, ..) => {
                 id
             }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 62157b1ca3681..81b1be53615d6 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -49,8 +49,8 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn attrs(&self) -> &'a [Attribute] {
         match *self {
-            FnKind::ItemFn(_, _, _, _, _, _, attrs) => attrs,
-            FnKind::Method(_, _, _, attrs) => attrs,
+            FnKind::ItemFn(.., attrs) => attrs,
+            FnKind::Method(.., attrs) => attrs,
             FnKind::Closure(attrs) => attrs,
         }
     }
@@ -622,7 +622,7 @@ pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declarat
 
 pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
     match function_kind {
-        FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+        FnKind::ItemFn(_, generics, ..) => {
             visitor.visit_generics(generics);
         }
         FnKind::Method(_, sig, _, _) => {
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 593d10ef4f7c4..abb6084002448 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -62,7 +62,7 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
                 _ => false
             }
         }
-        PatKind::Vec(_, _, _) => true,
+        PatKind::Vec(..) => true,
         _ => false
     }
 }
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index efce0c8354bac..753dd01d87eea 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1787,7 +1787,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     let method_id_opt = match tcx.map.find(parent) {
         Some(node) => match node {
             ast_map::NodeItem(item) => match item.node {
-                hir::ItemFn(_, _, _, _, ref gen, _) => {
+                hir::ItemFn(.., ref gen, _) => {
                     taken.extend_from_slice(&gen.lifetimes);
                     None
                 },
@@ -1811,7 +1811,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         if let Some(node) = tcx.map.find(parent) {
             match node {
                 ast_map::NodeItem(item) => match item.node {
-                    hir::ItemImpl(_, _, ref gen, _, _, _) => {
+                    hir::ItemImpl(_, _, ref gen, ..) => {
                         taken.extend_from_slice(&gen.lifetimes);
                     }
                     _ => ()
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index b6114f293ad3a..bc5ca76c3f857 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -248,7 +248,7 @@ impl TypeOrigin {
             &TypeOrigin::RelateOutputImplTypes(_) => {
                 "trait type parameters matches those specified on the impl"
             }
-            &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
+            &TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types",
             &TypeOrigin::IfExpression(_) => "if and else have compatible types",
             &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
             &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 1e4b2e9116fd2..f70349d0ee08b 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -30,6 +30,7 @@
 #![feature(conservative_impl_trait)]
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(enumset)]
 #![feature(libc)]
 #![feature(nonzero)]
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 0b1d9e8d8f69e..8cb362c1625a5 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -344,7 +344,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
                 self.worklist.extend(enum_def.variants.iter()
                                                       .map(|variant| variant.node.data.id()));
             }
-            hir::ItemTrait(_, _, _, ref trait_items) => {
+            hir::ItemTrait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     match trait_item.node {
                         hir::ConstTraitItem(_, Some(_)) |
@@ -357,7 +357,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
+            hir::ItemImpl(.., ref opt_trait, _, ref impl_items) => {
                 for impl_item in impl_items {
                     if opt_trait.is_some() ||
                             has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index e52eba68da198..66c55eb1f3e5f 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 block: &'v hir::Block, span: Span, id: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
-            FnKind::ItemFn(_, _, unsafety, _, _, _, _) =>
+            FnKind::ItemFn(_, _, unsafety, ..) =>
                 (true, unsafety == hir::Unsafety::Unsafe),
             FnKind::Method(_, sig, _, _) =>
                 (true, sig.unsafety == hir::Unsafety::Unsafe),
@@ -143,7 +143,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, expr: &hir::Expr) {
         match expr.node {
-            hir::ExprMethodCall(_, _, _) => {
+            hir::ExprMethodCall(..) => {
                 let method_call = MethodCall::expr(expr.id);
                 let base_type = self.tcx.tables.borrow().method_map[&method_call].ty;
                 debug!("effect: method call case, base type is {:?}",
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 541aeeb7d8dd7..66c8a8ac0d37b 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -544,7 +544,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 self.consume_expr(&count);
             }
 
-            hir::ExprClosure(_, _, _, fn_decl_span) => {
+            hir::ExprClosure(.., fn_decl_span) => {
                 self.walk_captures(expr, fn_decl_span)
             }
 
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 0625504af88ea..beffaff1e5b8a 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -46,8 +46,8 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
     }
 
     match item.node {
-        hir::ItemImpl(_, _, ref generics, _, _, _) |
-        hir::ItemFn(_, _, _, _, ref generics, _) => {
+        hir::ItemImpl(_, _, ref generics, ..) |
+        hir::ItemFn(.., ref generics, _) => {
             generics_require_inlining(generics)
         }
         _ => false,
@@ -187,7 +187,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                             // does too.
                             let impl_node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
                             match self.tcx.map.expect_item(impl_node_id).node {
-                                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                                hir::ItemImpl(_, _, ref generics, ..) => {
                                     generics_require_inlining(generics)
                                 }
                                 _ => false
@@ -226,7 +226,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             // If we are building an executable, only explicitly extern
             // types need to be exported.
             if let ast_map::NodeItem(item) = *node {
-                let reachable = if let hir::ItemFn(_, _, _, abi, _, _) = item.node {
+                let reachable = if let hir::ItemFn(.., abi, _, _) = item.node {
                     abi != Abi::Rust
                 } else {
                     false
@@ -248,7 +248,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         match *node {
             ast_map::NodeItem(item) => {
                 match item.node {
-                    hir::ItemFn(_, _, _, _, _, ref search_block) => {
+                    hir::ItemFn(.., ref search_block) => {
                         if item_might_be_inlined(&item) {
                             intravisit::walk_block(self, &search_block)
                         }
@@ -265,7 +265,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     // inherently and their children are already in the
                     // worklist, as determined by the privacy pass
                     hir::ItemExternCrate(_) | hir::ItemUse(_) |
-                    hir::ItemTy(..) | hir::ItemStatic(_, _, _) |
+                    hir::ItemTy(..) | hir::ItemStatic(..) |
                     hir::ItemMod(..) | hir::ItemForeignMod(..) |
                     hir::ItemImpl(..) | hir::ItemTrait(..) |
                     hir::ItemStruct(..) | hir::ItemEnum(..) |
@@ -329,7 +329,7 @@ struct CollectPrivateImplItemsVisitor<'a> {
 impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
     fn visit_item(&mut self, item: &hir::Item) {
         // We need only trait impls here, not inherent impls, and only non-exported ones
-        if let hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) = item.node {
+        if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node {
             if !self.access_levels.is_reachable(item.id) {
                 for impl_item in impl_items {
                     self.worklist.push(impl_item.id);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 4d1eed612cfd5..b6faf834b26f7 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -158,7 +158,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
                 hir::ItemStruct(_, ref generics) |
                 hir::ItemUnion(_, ref generics) |
                 hir::ItemTrait(_, ref generics, _, _) |
-                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                hir::ItemImpl(_, _, ref generics, ..) => {
                     // These kinds of items have only early bound lifetime parameters.
                     let lifetimes = &generics.lifetimes;
                     let start = if let hir::ItemTrait(..) = item.node {
@@ -204,7 +204,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
     fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
                 b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
         match fk {
-            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+            FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
                     this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)
                 })
@@ -499,7 +499,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                  fn_id: ast::NodeId) {
 
         match fk {
-            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+            FnKind::ItemFn(_, generics, ..) => {
                 intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(generics);
             }
@@ -584,7 +584,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
             match parent.node {
                 hir::ItemTrait(_, ref generics, _, _) |
-                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                hir::ItemImpl(_, _, ref generics, ..) => {
                     start += generics.lifetimes.len() + generics.ty_params.len();
                 }
                 _ => {}
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index aea1ee8d82401..9fc83557fa44b 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -252,11 +252,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
             // they don't have their own stability. They still can be annotated as unstable
             // and propagate this unstability to children, but this annotation is completely
             // optional. They inherit stability from their parents when unannotated.
-            hir::ItemImpl(_, _, _, None, _, _) | hir::ItemForeignMod(..) => {
+            hir::ItemImpl(.., None, _, _) | hir::ItemForeignMod(..) => {
                 self.in_trait_impl = false;
                 kind = AnnotationKind::Container;
             }
-            hir::ItemImpl(_, _, _, Some(_), _, _) => {
+            hir::ItemImpl(.., Some(_), _, _) => {
                 self.in_trait_impl = true;
             }
             hir::ItemStruct(ref sd, _) => {
@@ -528,7 +528,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // For implementations of traits, check the stability of each item
         // individually as it's possible to have a stable trait with unstable
         // items.
-        hir::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
+        hir::ItemImpl(.., Some(ref t), _, ref impl_items) => {
             let trait_did = tcx.expect_def(t.ref_id).def_id();
             let trait_items = tcx.trait_items(trait_did);
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3c450e14dea81..a9b3833b40175 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1336,7 +1336,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
             }
             Some(ast_map::NodeItem(item)) => {
                 match item.node {
-                    hir::ItemFn(_, _, _, _, _, ref body) => {
+                    hir::ItemFn(.., ref body) => {
                         // We assume this is a function.
                         let fn_def_id = tcx.map.local_def_id(id);
 
@@ -2262,7 +2262,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn provided_trait_methods(self, id: DefId) -> Vec>> {
         if let Some(id) = self.map.as_local_node_id(id) {
-            if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node {
+            if let ItemTrait(.., ref ms) = self.map.expect_item(id).node {
                 ms.iter().filter_map(|ti| {
                     if let hir::MethodTraitItem(_, Some(_)) = ti.node {
                         match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
@@ -2288,7 +2288,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn associated_consts(self, id: DefId) -> Vec>> {
         if let Some(id) = self.map.as_local_node_id(id) {
             match self.map.expect_item(id).node {
-                ItemTrait(_, _, _, ref tis) => {
+                ItemTrait(.., ref tis) => {
                     tis.iter().filter_map(|ti| {
                         if let hir::ConstTraitItem(_, _) = ti.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
@@ -2304,7 +2304,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         }
                     }).collect()
                 }
-                ItemImpl(_, _, _, _, _, ref iis) => {
+                ItemImpl(.., ref iis) => {
                     iis.iter().filter_map(|ii| {
                         if let hir::ImplItemKind::Const(_, _) = ii.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
@@ -2334,7 +2334,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             match self.map.find(id) {
                 Some(ast_map::NodeItem(item)) => {
                     match item.node {
-                        hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity),
+                        hir::ItemImpl(_, polarity, ..) => Some(polarity),
                         _ => None
                     }
                 }
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index be408e2db5c34..9c462feeaadd7 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -67,8 +67,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>(
     id: ast::NodeId,
     attributes: &[ast::Attribute]) {
     match fk {
-        FnKind::ItemFn(name, _, _, _, _, _, _) |
-        FnKind::Method(name, _, _, _) => {
+        FnKind::ItemFn(name, ..) |
+        FnKind::Method(name, ..) => {
             debug!("borrowck_mir({}) UNIMPLEMENTED", name);
         }
         FnKind::Closure(_) => {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index f5e20285e0c1b..e25adadbb2443 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -711,7 +711,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
             move_data::Captured =>
                 (match self.tcx.map.expect_expr(the_move.id).node {
-                    hir::ExprClosure(_, _, _, fn_decl_span) => fn_decl_span,
+                    hir::ExprClosure(.., fn_decl_span) => fn_decl_span,
                     ref r => bug!("Captured({}) maps to non-closure: {:?}",
                                   the_move.id, r),
                 }, " (into closure)"),
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 16fefee347269..22b590592fe16 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -19,6 +19,7 @@
 
 #![allow(non_camel_case_types)]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 114b5e1331de2..a74b8848c4d6b 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -228,7 +228,7 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
     };
 
     match fn_like.kind() {
-        FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => {
+        FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
             Some(fn_like)
         }
         FnKind::Method(_, m, _, _) => {
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index a6714c178e7cf..f926fef065ea6 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -22,7 +22,7 @@
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 
-
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 1094d0ee12bbd..84d65308f952f 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -239,7 +239,7 @@ impl LateLintPass for NonSnakeCase {
                 fk: FnKind, _: &hir::FnDecl,
                 _: &hir::Block, span: Span, id: ast::NodeId) {
         match fk {
-            FnKind::Method(name, _, _, _) => match method_context(cx, id, span) {
+            FnKind::Method(name, ..) => match method_context(cx, id, span) {
                 MethodLateContext::PlainImpl => {
                     self.check_snake_case(cx, "method", &name.as_str(), Some(span))
                 },
@@ -248,7 +248,7 @@ impl LateLintPass for NonSnakeCase {
                 },
                 _ => (),
             },
-            FnKind::ItemFn(name, _, _, _, _, _, _) => {
+            FnKind::ItemFn(name, ..) => {
                 self.check_snake_case(cx, "function", &name.as_str(), Some(span))
             },
             FnKind::Closure(_) => (),
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 1702c1c0edc9a..eb2ded45c04c5 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -203,10 +203,10 @@ impl LateLintPass for UnsafeCode {
 
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
-            hir::ItemTrait(hir::Unsafety::Unsafe, _, _, _) =>
+            hir::ItemTrait(hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
 
-            hir::ItemImpl(hir::Unsafety::Unsafe, _, _, _, _, _) =>
+            hir::ItemImpl(hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
 
             _ => return,
@@ -216,7 +216,7 @@ impl LateLintPass for UnsafeCode {
     fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
                 _: &hir::Block, span: Span, _: ast::NodeId) {
         match fk {
-            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, _, _, _, _) =>
+            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
 
             FnKind::Method(_, sig, _, _) => {
@@ -351,7 +351,7 @@ impl LateLintPass for MissingDoc {
             hir::ItemEnum(..) => "an enum",
             hir::ItemStruct(..) => "a struct",
             hir::ItemUnion(..) => "a union",
-            hir::ItemTrait(_, _, _, ref items) => {
+            hir::ItemTrait(.., ref items) => {
                 // Issue #11592, traits are always considered exported, even when private.
                 if it.vis == hir::Visibility::Inherited {
                     self.private_traits.insert(it.id);
@@ -363,7 +363,7 @@ impl LateLintPass for MissingDoc {
                 "a trait"
             },
             hir::ItemTy(..) => "a type alias",
-            hir::ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) => {
+            hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
                 // If the trait is private, add the impl items to private_traits so they don't get
                 // reported for missing docs.
                 let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
@@ -1037,7 +1037,7 @@ impl LintPass for InvalidNoMangleItems {
 impl LateLintPass for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
-            hir::ItemFn(_, _, _, _, ref generics, _) => {
+            hir::ItemFn(.., ref generics, _) => {
                 if attr::contains_name(&it.attrs, "no_mangle") {
                     if !cx.access_levels.is_reachable(it.id) {
                         let msg = format!("function {} is marked #[no_mangle], but not exported",
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index c3b752d605f97..b9817cc6ff45a 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -31,6 +31,7 @@
 #![cfg_attr(test, feature(test))]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 35f5eba4160d9..583631d2e0ab5 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1065,7 +1065,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                 let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
                 encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref);
             }
-            hir::ItemImpl(unsafety, polarity, _, _, _, _) => {
+            hir::ItemImpl(unsafety, polarity, ..) => {
                 // We need to encode information about the default methods we
                 // have inherited, so we drive self based on the impl structure.
                 let impl_items = tcx.impl_items.borrow();
@@ -1129,7 +1129,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                 encode_stability(self.rbml_w, stab);
                 encode_deprecation(self.rbml_w, depr);
             }
-            hir::ItemTrait(_, _, _, _) => {
+            hir::ItemTrait(..) => {
                 encode_def_id_and_key(ecx, self.rbml_w, def_id);
                 encode_family(self.rbml_w, 'I');
                 encode_item_variances(self.rbml_w, ecx, item.id);
@@ -1209,10 +1209,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
             hir::ItemUnion(..) => {
                 self.encode_addl_union_info(def_id);
             }
-            hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
+            hir::ItemImpl(.., ref ast_items) => {
                 self.encode_addl_impl_info(def_id, item.id, ast_items);
             }
-            hir::ItemTrait(_, _, _, ref trait_items) => {
+            hir::ItemTrait(.., ref trait_items) => {
                 self.encode_addl_trait_info(def_id, trait_items);
             }
         }
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index a3afb9d84bd30..84323d4646607 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -18,6 +18,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(box_patterns)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(enumset)]
 #![feature(question_mark)]
 #![feature(quote)]
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 1767630b81b1a..919b23ffda540 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             MirSource::Fn(id) => {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
                 match fn_like.map(|f| f.kind()) {
-                    Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
+                    Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
                     Some(FnKind::Method(_, m, _, _)) => m.constness,
                     _ => hir::Constness::NotConst
                 }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 3d01d49c53472..f580ceeee5d7f 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 
 #![feature(associated_consts)]
 #![feature(box_patterns)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 6c6a5f7fc74b0..751f25b279401 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -119,7 +119,7 @@ fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         let fn_like = FnLikeNode::from_node(tcx.map.get(node_id));
         match fn_like.map(|f| f.kind()) {
-            Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => {
+            Some(FnKind::ItemFn(_, _, _, c, ..)) => {
                 c == hir::Constness::Const
             }
             Some(FnKind::Method(_, m, _, _)) => {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index b8284f5dcf10d..6a24742426ab0 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -100,8 +100,8 @@ impl<'a> Visitor for AstValidator<'a> {
         match expr.node {
             ExprKind::While(_, _, Some(ident)) |
             ExprKind::Loop(_, Some(ident)) |
-            ExprKind::WhileLet(_, _, _, Some(ident)) |
-            ExprKind::ForLoop(_, _, _, Some(ident)) |
+            ExprKind::WhileLet(.., Some(ident)) |
+            ExprKind::ForLoop(.., Some(ident)) |
             ExprKind::Break(Some(ident)) |
             ExprKind::Continue(Some(ident)) => {
                 self.check_label(ident.node, ident.span, expr.id);
@@ -155,7 +155,7 @@ impl<'a> Visitor for AstValidator<'a> {
                         .span_err(path.span, "type or lifetime parameters in import path");
                 }
             }
-            ItemKind::Impl(_, _, _, Some(..), _, ref impl_items) => {
+            ItemKind::Impl(.., Some(..), _, ref impl_items) => {
                 self.invalid_visibility(&item.vis, item.span, None);
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, impl_item.span, None);
@@ -164,7 +164,7 @@ impl<'a> Visitor for AstValidator<'a> {
                     }
                 }
             }
-            ItemKind::Impl(_, _, _, None, _, _) => {
+            ItemKind::Impl(.., None, _, _) => {
                 self.invalid_visibility(&item.vis,
                                         item.span,
                                         Some("place qualifiers on individual impl items instead"));
@@ -185,7 +185,7 @@ impl<'a> Visitor for AstValidator<'a> {
                     }
                 }
             }
-            ItemKind::Trait(_, _, _, ref trait_items) => {
+            ItemKind::Trait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     if let TraitItemKind::Method(ref sig, _) = trait_item.node {
                         self.check_trait_fn_not_const(sig.constness);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index c3749bf4546f3..3094ff49f1f59 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -147,7 +147,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         }
 
         let mode = match fk {
-            FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _)
+            FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
                 => Mode::ConstFn,
             FnKind::Method(_, m, _, _) => {
                 if m.constness == hir::Constness::Const {
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index e59c4a6fc4186..a4657251c9ce2 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -23,6 +23,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(staged_api)]
 #![feature(rustc_private)]
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 179863c16fff2..5e374ce7c5803 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -17,6 +17,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -125,10 +126,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let inherited_item_level = match item.node {
             // Impls inherit level from their types and traits
-            hir::ItemImpl(_, _, _, None, ref ty, _) => {
+            hir::ItemImpl(.., None, ref ty, _) => {
                 self.ty_level(&ty)
             }
-            hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
+            hir::ItemImpl(.., Some(ref trait_ref), ref ty, _) => {
                 cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
             }
             hir::ItemDefaultImpl(_, ref trait_ref) => {
@@ -157,19 +158,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
+            hir::ItemImpl(.., None, _, ref impl_items) => {
                 for impl_item in impl_items {
                     if impl_item.vis == hir::Public {
                         self.update(impl_item.id, item_level);
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
+            hir::ItemImpl(.., Some(_), _, ref impl_items) => {
                 for impl_item in impl_items {
                     self.update(impl_item.id, item_level);
                 }
             }
-            hir::ItemTrait(_, _, _, ref trait_items) => {
+            hir::ItemTrait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     self.update(trait_item.id, item_level);
                 }
@@ -204,7 +205,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             hir::ItemUse(..) => {}
             // Visit everything
             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
-            hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(_, _, _, Some(..), _, _) => {
+            hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(.., Some(..), _, _) => {
                 if item_level.is_some() {
                     self.reach().visit_item(item);
                 }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 8e97870c21a5b..98ddff70462c9 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -232,7 +232,7 @@ impl<'b> Resolver<'b> {
                 let def = Def::Const(self.definitions.local_def_id(item.id));
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
-            ItemKind::Fn(_, _, _, _, _, _) => {
+            ItemKind::Fn(..) => {
                 let def = Def::Fn(self.definitions.local_def_id(item.id));
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
@@ -294,7 +294,7 @@ impl<'b> Resolver<'b> {
 
             ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
 
-            ItemKind::Trait(_, _, _, ref items) => {
+            ItemKind::Trait(.., ref items) => {
                 let def_id = self.definitions.local_def_id(item.id);
 
                 // Add all the items within to a new module.
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index db0704db33fd5..0a86eeef7c45b 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -19,6 +19,7 @@
 
 #![feature(associated_consts)]
 #![feature(borrow_state)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -599,7 +600,7 @@ impl<'a> Visitor for Resolver<'a> {
                 _: Span,
                 node_id: NodeId) {
         let rib_kind = match function_kind {
-            FnKind::ItemFn(_, generics, _, _, _, _) => {
+            FnKind::ItemFn(_, generics, ..) => {
                 self.visit_generics(generics);
                 ItemRibKind
             }
@@ -1634,7 +1635,7 @@ impl<'a> Resolver<'a> {
             ItemKind::Ty(_, ref generics) |
             ItemKind::Struct(_, ref generics) |
             ItemKind::Union(_, ref generics) |
-            ItemKind::Fn(_, _, _, _, ref generics, _) => {
+            ItemKind::Fn(.., ref generics, _) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
                                              |this| visit::walk_item(this, item));
             }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index f9a20cec42d14..329527b304e3e 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1137,7 +1137,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                     }.lower(self.tcx));
                 }
             }
-            Fn(ref decl, _, _, _, ref ty_params, ref body) =>
+            Fn(ref decl, .., ref ty_params, ref body) =>
                 self.process_fn(item, &decl, ty_params, &body),
             Static(ref typ, _, ref expr) =>
                 self.process_static_or_const_item(item, typ, expr),
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 47f3a06de1bd1..559893b26facc 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -18,6 +18,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(custom_attribute)]
+#![feature(dotdot_in_tuple_patterns)]
 #![allow(unused_attributes)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -124,7 +125,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     pub fn get_item_data(&self, item: &ast::Item) -> Option {
         match item.node {
-            ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
+            ast::ItemKind::Fn(ref decl, .., ref generics, _) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
                 filter!(self.span_utils, sub_span, item.span, None);
@@ -217,7 +218,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
                 }))
             }
-            ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => {
+            ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
                 let mut type_data = None;
                 let sub_span;
 
@@ -295,7 +296,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
                 Some(NodeItem(item)) => {
                     match item.node {
-                        hir::ItemImpl(_, _, _, _, ref ty, _) => {
+                        hir::ItemImpl(.., ref ty, _) => {
                             let mut result = String::from("<");
                             result.push_str(&rustc::hir::print::ty_to_string(&ty));
 
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 4bea5d7e87fc9..b5c922d7fda4b 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -1152,7 +1152,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 // const items only generate translation items if they are
                 // actually used somewhere. Just declaring them is insufficient.
             }
-            hir::ItemFn(_, _, _, _, ref generics, _) => {
+            hir::ItemFn(.., ref generics, _) => {
                 if !generics.is_type_parameterized() {
                     let def_id = self.scx.tcx().map.local_def_id(item.id);
 
@@ -1179,7 +1179,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 let parent_node_id = hir_map.get_parent_node(ii.id);
                 let is_impl_generic = match hir_map.expect_item(parent_node_id) {
                     &hir::Item {
-                        node: hir::ItemImpl(_, _, ref generics, _, _, _),
+                        node: hir::ItemImpl(_, _, ref generics, ..),
                         ..
                     } => {
                         generics.is_type_parameterized()
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 6ede55d5ff49a..6f5bac840a1dc 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -27,6 +27,7 @@
 #![feature(box_syntax)]
 #![feature(const_fn)]
 #![feature(custom_attribute)]
+#![feature(dotdot_in_tuple_patterns)]
 #![allow(unused_attributes)]
 #![feature(libc)]
 #![feature(quote)]
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c445455ef2bc5..5925d222b4466 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1358,7 +1358,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             // `ty::trait_items` used below requires information generated
             // by type collection, which may be in progress at this point.
             match tcx.map.expect_item(trait_id).node {
-                hir::ItemTrait(_, _, _, ref trait_items) => {
+                hir::ItemTrait(.., ref trait_items) => {
                     let item = trait_items.iter()
                                           .find(|i| i.name == assoc_name)
                                           .expect("missing associated type");
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f4fea5542b3de..36c2494a00656 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -741,7 +741,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                             it.id);
       }
       hir::ItemFn(..) => {} // entirely within check_item_body
-      hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
+      hir::ItemImpl(.., ref impl_items) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
           let impl_def_id = ccx.tcx.map.local_def_id(it.id);
           match ccx.tcx.impl_trait_ref(impl_def_id) {
@@ -808,10 +808,10 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
            ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
-      hir::ItemFn(ref decl, _, _, _, _, ref body) => {
+      hir::ItemFn(ref decl, .., ref body) => {
         check_bare_fn(ccx, &decl, &body, it.id);
       }
-      hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
+      hir::ItemImpl(.., ref impl_items) => {
         debug!("ItemImpl {} with id {}", it.name, it.id);
 
         for impl_item in impl_items {
@@ -828,7 +828,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
             }
         }
       }
-      hir::ItemTrait(_, _, _, ref trait_items) => {
+      hir::ItemTrait(.., ref trait_items) => {
         for trait_item in trait_items {
             match trait_item.node {
                 hir::ConstTraitItem(_, Some(ref expr)) => {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7dff30d03c332..8eb7d34568762 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -126,7 +126,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                     }
                 }
             }
-            hir::ItemFn(_, _, _, _, _, ref body) => {
+            hir::ItemFn(.., ref body) => {
                 self.check_item_fn(item, body);
             }
             hir::ItemStatic(..) => {
@@ -156,7 +156,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
-            hir::ItemTrait(_, _, _, ref items) => {
+            hir::ItemTrait(.., ref items) => {
                 self.check_trait(item, items);
             }
             _ => {}
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index fba145efa9507..70682bb8c8f35 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -195,7 +195,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
     // Converts an implementation in the AST to a vector of items.
     fn create_impl_from_item(&self, item: &Item) -> Vec {
         match item.node {
-            ItemImpl(_, _, _, _, _, ref impl_items) => {
+            ItemImpl(.., ref impl_items) => {
                 impl_items.iter().map(|impl_item| {
                     let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id);
                     match impl_item.node {
@@ -252,7 +252,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                         match tcx.map.find(impl_node_id) {
                             Some(hir_map::NodeItem(item)) => {
                                 let span = match item.node {
-                                    ItemImpl(_, _, _, _, ref ty, _) => {
+                                    ItemImpl(.., ref ty, _) => {
                                         ty.span
                                     },
                                     _ => item.span
@@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                 }
                 Err(CopyImplementationError::InfrigingVariant(name)) => {
                     let item = tcx.map.expect_item(impl_node_id);
-                    let span = if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
+                    let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
                         tr.path.span
                     } else {
                         span
@@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                 }
                 Err(CopyImplementationError::NotAnAdt) => {
                     let item = tcx.map.expect_item(impl_node_id);
-                    let span = if let ItemImpl(_, _, _, _, ref ty, _) = item.node {
+                    let span = if let ItemImpl(.., ref ty, _) = item.node {
                         ty.span
                     } else {
                         span
@@ -463,7 +463,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                             return;
                         } else if diff_fields.len() > 1 {
                             let item = tcx.map.expect_item(impl_node_id);
-                            let span = if let ItemImpl(_, _, _, Some(ref t), _, _) = item.node {
+                            let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
                                 t.path.span
                             } else {
                                 tcx.map.span(impl_node_id)
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 4c38475335ce8..cb424eb48e932 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -68,7 +68,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     fn check_item(&self, item: &hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
         match item.node {
-            hir::ItemImpl(_, _, _, None, ref ty, _) => {
+            hir::ItemImpl(.., None, ref ty, _) => {
                 // For inherent impls, self type must be a nominal type
                 // defined in this crate.
                 debug!("coherence2::orphan check: inherent impl {}",
@@ -222,7 +222,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, Some(_), _, _) => {
+            hir::ItemImpl(.., Some(_), _, _) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: trait impl {}",
                        self.tcx.map.node_to_string(item.id));
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index c4d925372f18d..890b6c72e6fee 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -122,7 +122,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
                     err.emit();
                 }
             }
-            hir::ItemImpl(_, _, _, Some(_), _, _) => {
+            hir::ItemImpl(.., Some(_), _, _) => {
                 let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 53ec72abac05f..cdf5478e692b2 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -81,7 +81,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
             hir::ItemDefaultImpl(unsafety, _) => {
                 self.check_unsafety_coherence(item, unsafety, hir::ImplPolarity::Positive);
             }
-            hir::ItemImpl(unsafety, polarity, _, _, _, _) => {
+            hir::ItemImpl(unsafety, polarity, ..) => {
                 self.check_unsafety_coherence(item, unsafety, polarity);
             }
             _ => { }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 55db44a2c3109..a012fd418cac6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -850,7 +850,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items);
         },
-        hir::ItemTrait(_, _, _, ref trait_items) => {
+        hir::ItemTrait(.., ref trait_items) => {
             let trait_def = trait_def_of_item(ccx, it);
             let def_id = trait_def.trait_ref.def_id;
             let _: Result<(), ErrorReported> = // any error is already reported, can ignore
@@ -1311,7 +1311,7 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt,
     };
 
     let trait_items = match item.node {
-        hir::ItemTrait(_, _, _, ref trait_items) => trait_items,
+        hir::ItemTrait(.., ref trait_items) => trait_items,
         _ => bug!("trait_node_id {} is not a trait", trait_node_id)
     };
 
@@ -1445,8 +1445,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
             NodeItem(item) => {
                 match item.node {
-                    ItemFn(_, _, _, _, ref generics, _) |
-                    ItemImpl(_, _, ref generics, _, _, _) => generics,
+                    ItemFn(.., ref generics, _) |
+                    ItemImpl(_, _, ref generics, ..) => generics,
 
                     ItemTy(_, ref generics) |
                     ItemEnum(_, ref generics) |
@@ -1651,7 +1651,7 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let no_generics = hir::Generics::empty();
     let generics = match it.node {
-        hir::ItemFn(_, _, _, _, ref generics, _) |
+        hir::ItemFn(.., ref generics, _) |
         hir::ItemTy(_, ref generics) |
         hir::ItemEnum(_, ref generics) |
         hir::ItemStruct(_, ref generics) |
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a5445b18e77f8..d2e2d578fcedb 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -76,6 +76,7 @@ This API is completely unstable and subject to change.
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
@@ -215,7 +216,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
             match tcx.map.find(main_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
-                        hir::ItemFn(_, _, _, _, ref generics, _) => {
+                        hir::ItemFn(.., ref generics, _) => {
                             if generics.is_parameterized() {
                                 struct_span_err!(ccx.tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
@@ -267,7 +268,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
             match tcx.map.find(start_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
-                        hir::ItemFn(_,_,_,_,ref ps,_)
+                        hir::ItemFn(..,ref ps,_)
                         if ps.is_parameterized() => {
                             struct_span_err!(tcx.sess, ps.span, E0132,
                                 "start function is not allowed to have type parameters")
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 44d1fbfdb70b3..4a637b5cfcff7 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -227,6 +227,7 @@
 #![feature(const_fn)]
 #![feature(core_float)]
 #![feature(core_intrinsics)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(dropck_parametricity)]
 #![feature(float_extras)]
 #![feature(float_from_str_radix)]
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index fe448cdd78feb..90a16853d56dd 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -200,7 +200,7 @@ impl OpenOptions {
         const ERROR_INVALID_PARAMETER: i32 = 87;
 
         match (self.read, self.write, self.append, self.access_mode) {
-            (_, _, _, Some(mode)) => Ok(mode),
+            (.., Some(mode)) => Ok(mode),
             (true,  false, false, None) => Ok(c::GENERIC_READ),
             (false, true,  false, None) => Ok(c::GENERIC_WRITE),
             (true,  true,  false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4394fb0e14312..bbd3345144585 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -562,7 +562,7 @@ impl Pat {
             PatKind::Wild |
             PatKind::Lit(_) |
             PatKind::Range(_, _) |
-            PatKind::Ident(_, _, _) |
+            PatKind::Ident(..) |
             PatKind::Path(..) |
             PatKind::Mac(_) => {
                 true
diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
index 5a3412b7ed9f9..5b1ecfed24278 100644
--- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
@@ -10,6 +10,7 @@
 
 // force-host
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(plugin_registrar, quote, rustc_private)]
 
 extern crate syntax;
@@ -75,7 +76,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::ImplItem(_) => {
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Impl(_, _, _, _, _, mut items) => {
+                    ItemKind::Impl(.., mut items) => {
                         Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
                     }
                     _ => unreachable!("impl parsed to something other than impl")
@@ -85,7 +86,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::TraitItem(_) => {
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Trait(_, _, _, mut items) => {
+                    ItemKind::Trait(.., mut items) => {
                         Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
                     }
                     _ => unreachable!("trait parsed to something other than trait")
diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
index 46fdf91125845..4885863122c3b 100644
--- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
@@ -10,6 +10,7 @@
 
 // force-host
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(plugin_registrar, quote, rustc_private)]
 
 extern crate syntax;
@@ -81,7 +82,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::ImplItem(_it) => vec![
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Impl(_, _, _, _, _, mut items) => {
+                    ItemKind::Impl(.., mut items) => {
                         Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
                     }
                     _ => unreachable!("impl parsed to something other than impl")
@@ -91,7 +92,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::TraitItem(_it) => vec![
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Trait(_, _, _, mut items) => {
+                    ItemKind::Trait(.., mut items) => {
                         Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
                     }
                     _ => unreachable!("trait parsed to something other than trait")
@@ -165,7 +166,7 @@ fn expand_caller(cx: &mut ExtCtxt,
                  push: &mut FnMut(Annotatable)) {
     let (orig_fn_name, ret_type) = match *it {
         Annotatable::Item(ref item) => match item.node {
-            ItemKind::Fn(ref decl, _, _, _, _, _) => {
+            ItemKind::Fn(ref decl, ..) => {
                 (item.ident, &decl.output)
             }
             _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")

From e05e74ac831bc8438f5daeb98432a29285ed9514 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 528/768] Replace `_, _` with `..`

---
 src/libgetopts/lib.rs                         |  2 +-
 src/librustc/cfg/construct.rs                 |  6 ++---
 src/librustc/hir/def.rs                       |  2 +-
 src/librustc/hir/intravisit.rs                |  4 +--
 src/librustc/hir/map/collector.rs             |  2 +-
 src/librustc/hir/mod.rs                       |  4 +--
 src/librustc/hir/pat_util.rs                  |  2 +-
 src/librustc/infer/error_reporting.rs         |  6 ++---
 src/librustc/infer/higher_ranked/mod.rs       |  2 +-
 src/librustc/infer/mod.rs                     |  6 ++---
 src/librustc/infer/region_inference/mod.rs    |  6 ++---
 src/librustc/infer/type_variable.rs           |  2 +-
 src/librustc/middle/effect.rs                 |  4 +--
 src/librustc/middle/expr_use_visitor.rs       |  8 +++---
 src/librustc/middle/intrinsicck.rs            |  4 +--
 src/librustc/middle/liveness.rs               |  6 ++---
 src/librustc/middle/mem_categorization.rs     | 26 +++++++++----------
 src/librustc/middle/region.rs                 |  2 +-
 src/librustc/middle/resolve_lifetime.rs       | 10 +++----
 src/librustc/middle/stability.rs              |  2 +-
 src/librustc/mir/tcx.rs                       |  2 +-
 src/librustc/session/config.rs                |  4 +--
 src/librustc/traits/select.rs                 |  4 +--
 src/librustc/ty/adjustment.rs                 |  2 +-
 src/librustc/ty/contents.rs                   |  2 +-
 src/librustc/ty/fast_reject.rs                |  2 +-
 src/librustc/ty/item_path.rs                  |  2 +-
 src/librustc/ty/mod.rs                        |  6 ++---
 src/librustc/ty/sty.rs                        |  6 ++---
 src/librustc/ty/util.rs                       |  2 +-
 src/librustc_borrowck/borrowck/check_loans.rs |  8 +++---
 src/librustc_borrowck/borrowck/fragments.rs   |  8 +++---
 .../borrowck/gather_loans/gather_moves.rs     |  6 ++---
 .../borrowck/gather_loans/lifetime.rs         | 12 ++++-----
 .../borrowck/gather_loans/mod.rs              |  2 +-
 .../borrowck/gather_loans/move_error.rs       |  6 ++---
 src/librustc_borrowck/borrowck/mod.rs         | 10 +++----
 src/librustc_borrowck/borrowck/move_data.rs   |  8 +++---
 src/librustc_const_eval/check_match.rs        | 12 ++++-----
 src/librustc_const_eval/eval.rs               |  6 ++---
 src/librustc_driver/lib.rs                    |  5 ++--
 src/librustc_incremental/assert_dep_graph.rs  |  2 +-
 .../calculate_svh/svh_visitor.rs              |  6 ++---
 src/librustc_incremental/lib.rs               |  1 +
 src/librustc_incremental/persist/fs.rs        |  4 +--
 src/librustc_lint/builtin.rs                  |  8 +++---
 src/librustc_lint/unused.rs                   | 14 +++++-----
 src/librustc_metadata/astencode.rs            |  2 +-
 src/librustc_metadata/creader.rs              | 16 ++++++------
 src/librustc_metadata/decoder.rs              |  4 +--
 src/librustc_metadata/encoder.rs              |  2 +-
 src/librustc_mir/hair/cx/expr.rs              |  6 ++---
 src/librustc_mir/hair/cx/mod.rs               |  2 +-
 src/librustc_mir/transform/qualify_consts.rs  | 10 +++----
 src/librustc_mir/transform/type_check.rs      |  2 +-
 src/librustc_passes/ast_validation.rs         |  2 +-
 src/librustc_passes/consts.rs                 | 12 ++++-----
 src/librustc_passes/loops.rs                  |  2 +-
 src/librustc_privacy/lib.rs                   | 12 ++++-----
 src/librustc_resolve/build_reduced_graph.rs   |  4 +--
 src/librustc_resolve/check_unused.rs          |  2 +-
 src/librustc_resolve/lib.rs                   | 16 ++++++------
 src/librustc_save_analysis/dump_visitor.rs    | 12 ++++-----
 src/librustc_save_analysis/lib.rs             |  6 ++---
 src/librustc_trans/adt.rs                     |  6 ++---
 src/librustc_trans/back/write.rs              | 12 ++++-----
 src/librustc_trans/base.rs                    |  2 +-
 src/librustc_trans/cabi_x86_64.rs             |  2 +-
 src/librustc_trans/callee.rs                  |  6 ++---
 src/librustc_trans/collector.rs               |  5 ++--
 src/librustc_trans/debuginfo/metadata.rs      |  8 +++---
 src/librustc_trans/debuginfo/type_names.rs    |  2 +-
 src/librustc_trans/intrinsic.rs               |  2 +-
 src/librustc_trans/mir/block.rs               |  4 +--
 src/librustc_trans/trans_item.rs              |  2 +-
 src/librustc_typeck/check/callee.rs           |  2 +-
 src/librustc_typeck/check/cast.rs             |  2 +-
 src/librustc_typeck/check/coercion.rs         |  2 +-
 src/librustc_typeck/check/intrinsic.rs        |  2 +-
 src/librustc_typeck/check/method/confirm.rs   |  2 +-
 src/librustc_typeck/check/method/probe.rs     |  8 +++---
 src/librustc_typeck/check/mod.rs              | 12 ++++-----
 src/librustc_typeck/check/regionck.rs         | 10 +++----
 src/librustc_typeck/check/upvar.rs            |  8 +++---
 src/librustc_typeck/check/wfcheck.rs          |  4 +--
 src/librustc_typeck/check/writeback.rs        |  4 +--
 src/librustc_typeck/coherence/mod.rs          |  2 +-
 src/librustc_typeck/collect.rs                |  6 ++---
 src/librustc_typeck/variance/constraints.rs   |  2 +-
 src/librustc_typeck/variance/terms.rs         |  2 +-
 src/librustdoc/clean/inline.rs                |  2 +-
 src/librustdoc/clean/mod.rs                   |  8 +++---
 src/librustdoc/html/render.rs                 |  2 +-
 src/librustdoc/lib.rs                         |  3 ++-
 src/libserialize/hex.rs                       |  2 +-
 src/libstd/path.rs                            |  2 +-
 src/libsyntax/ast.rs                          |  2 +-
 src/libsyntax/ext/tt/macro_parser.rs          |  4 +--
 src/libsyntax/parse/token.rs                  |  6 ++---
 src/libsyntax_ext/asm.rs                      |  2 +-
 src/libsyntax_ext/deriving/debug.rs           |  2 +-
 src/libsyntax_ext/deriving/generic/mod.rs     |  8 +++---
 src/libsyntax_ext/deriving/hash.rs            |  2 +-
 src/libsyntax_ext/lib.rs                      |  1 +
 src/libterm/terminfo/parm.rs                  |  2 +-
 src/test/run-make/save-analysis/foo.rs        |  8 +++---
 .../auxiliary/custom_derive_plugin_attr.rs    |  3 ++-
 107 files changed, 275 insertions(+), 271 deletions(-)

diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index eda20699755a1..42200795bb3a5 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -279,7 +279,7 @@ impl OptGroup {
                                   }],
                 }
             }
-            (_, _) => panic!("something is wrong with the long-form opt"),
+            _ => panic!("something is wrong with the long-form opt"),
         }
     }
 }
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 232db76a6d175..25a73226473b7 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -99,7 +99,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
     fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
         match pat.node {
-            PatKind::Binding(_, _, None) |
+            PatKind::Binding(.., None) |
             PatKind::Path(..) |
             PatKind::Lit(..) |
             PatKind::Range(..) |
@@ -109,7 +109,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
             PatKind::Box(ref subpat) |
             PatKind::Ref(ref subpat, _) |
-            PatKind::Binding(_, _, Some(ref subpat)) => {
+            PatKind::Binding(.., Some(ref subpat)) => {
                 let subpat_exit = self.pat(&subpat, pred);
                 self.add_ast_node(pat.id, &[subpat_exit])
             }
@@ -306,7 +306,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.call(expr, pred, &func, args.iter().map(|e| &**e))
             }
 
-            hir::ExprMethodCall(_, _, ref args) => {
+            hir::ExprMethodCall(.., ref args) => {
                 self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e))
             }
 
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 71bc2693abd27..a270be4f1dfda 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -104,7 +104,7 @@ impl Def {
     pub fn var_id(&self) -> ast::NodeId {
         match *self {
             Def::Local(_, id) |
-            Def::Upvar(_, id, _, _) => {
+            Def::Upvar(_, id, ..) => {
                 id
             }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 81b1be53615d6..f0caa971d9699 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -341,7 +341,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_id(item.id);
             visitor.visit_trait_ref(trait_ref)
         }
-        ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
+        ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
             visitor.visit_id(item.id);
             visitor.visit_generics(type_parameters);
             walk_list!(visitor, visit_trait_ref, opt_trait_reference);
@@ -625,7 +625,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
         FnKind::ItemFn(_, generics, ..) => {
             visitor.visit_generics(generics);
         }
-        FnKind::Method(_, sig, _, _) => {
+        FnKind::Method(_, sig, ..) => {
             visitor.visit_generics(&sig.generics);
         }
         FnKind::Closure(_) => {}
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 280c0f3048569..d4e1eb70ae8f9 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -109,7 +109,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                         this.insert(struct_def.id(), NodeStructCtor(struct_def));
                     }
                 }
-                ItemTrait(_, _, ref bounds, _) => {
+                ItemTrait(.., ref bounds, _) => {
                     for b in bounds.iter() {
                         if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
                             this.insert(t.trait_ref.ref_id, NodeItem(i));
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index e16005558f82b..e22c9869ab176 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -469,7 +469,7 @@ impl Pat {
         }
 
         match self.node {
-            PatKind::Binding(_, _, Some(ref p)) => p.walk_(it),
+            PatKind::Binding(.., Some(ref p)) => p.walk_(it),
             PatKind::Struct(_, ref fields, _) => {
                 fields.iter().all(|field| field.node.pat.walk_(it))
             }
@@ -486,7 +486,7 @@ impl Pat {
             }
             PatKind::Wild |
             PatKind::Lit(_) |
-            PatKind::Range(_, _) |
+            PatKind::Range(..) |
             PatKind::Binding(..) |
             PatKind::Path(..) => {
                 true
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index abb6084002448..a63bf14cb0238 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -53,7 +53,7 @@ impl EnumerateAndAdjustIterator for T {
 
 pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
     match pat.node {
-        PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true,
+        PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(Some(..), _) => true,
         PatKind::TupleStruct(..) |
         PatKind::Path(..) |
         PatKind::Struct(..) => {
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 753dd01d87eea..38f3f055cbb24 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -140,9 +140,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     Some(ast_map::NodeExpr(expr)) => match expr.node {
                         hir::ExprCall(..) => "call",
                         hir::ExprMethodCall(..) => "method call",
-                        hir::ExprMatch(_, _, hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                        hir::ExprMatch(_, _, hir::MatchSource::WhileLetDesugar) =>  "while let",
-                        hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) =>  "for",
+                        hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
+                        hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) =>  "while let",
+                        hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) =>  "for",
                         hir::ExprMatch(..) => "match",
                         _ => "expression",
                     },
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 90be5e935baf1..322752ccea3e5 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             warnings.extend(
                                 match self.region_vars.var_origin(vid) {
                                     LateBoundRegion(_,
-                                                    ty::BrNamed(_, _, wc),
+                                                    ty::BrNamed(.., wc),
                                                     _) => Some(wc),
                                     _ => None,
                                 });
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index bc5ca76c3f857..59431f3f02dce 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -225,7 +225,7 @@ impl TypeOrigin {
             &TypeOrigin::RelateOutputImplTypes(_) |
             &TypeOrigin::ExprAssignable(_) => "mismatched types",
             &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
-            &TypeOrigin::MatchExpressionArm(_, _, source) => match source {
+            &TypeOrigin::MatchExpressionArm(.., source) => match source {
                 hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
                 _ => "match arms have incompatible types",
             },
@@ -1712,7 +1712,7 @@ impl TypeOrigin {
             TypeOrigin::ExprAssignable(span) => span,
             TypeOrigin::Misc(span) => span,
             TypeOrigin::RelateOutputImplTypes(span) => span,
-            TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
+            TypeOrigin::MatchExpressionArm(match_span, ..) => match_span,
             TypeOrigin::IfExpression(span) => span,
             TypeOrigin::IfExpressionWithNoElse(span) => span,
             TypeOrigin::RangeExpression(span) => span,
@@ -1765,7 +1765,7 @@ impl RegionVariableOrigin {
             Autoref(a) => a,
             Coercion(a) => a,
             EarlyBoundRegion(a, _) => a,
-            LateBoundRegion(a, _, _) => a,
+            LateBoundRegion(a, ..) => a,
             BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
             UpvarRegion(_, a) => a
         }
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index b3693ae1e21ad..ef36ffa831921 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -605,7 +605,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                                  undo_entry: &UndoLogEntry<'tcx>)
                                  -> bool {
             match undo_entry {
-                &AddConstraint(ConstrainVarSubVar(_, _)) =>
+                &AddConstraint(ConstrainVarSubVar(..)) =>
                     false,
                 &AddConstraint(ConstrainRegSubVar(a, _)) =>
                     skols.contains(&a),
@@ -613,7 +613,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                     skols.contains(&b),
                 &AddConstraint(ConstrainRegSubReg(a, b)) =>
                     skols.contains(&a) || skols.contains(&b),
-                &AddGiven(_, _) =>
+                &AddGiven(..) =>
                     false,
                 &AddVerify(_) =>
                     false,
@@ -1372,7 +1372,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 (&ReFree(..), &ReFree(..)) => Equal,
                 (&ReFree(..), _) => Less,
                 (_, &ReFree(..)) => Greater,
-                (_, _) => Equal,
+                (..) => Equal,
             }
         }
         lower_bounds.sort_by(|a, b| free_regions_first(a, b));
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 09ae16540c4f1..da9fd1cff2b46 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -267,7 +267,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
                     debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
                 }
 
-                sv::UndoLog::Other(SpecifyVar(vid, _, _)) => {
+                sv::UndoLog::Other(SpecifyVar(vid, ..)) => {
                     if vid.index < new_elem_threshold {
                         // quick check to see if this variable was
                         // created since the snapshot started or not.
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 66c55eb1f3e5f..a7af0b50b8494 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -43,7 +43,7 @@ enum RootUnsafeContext {
 
 fn type_is_unsafe_function(ty: Ty) -> bool {
     match ty.sty {
-        ty::TyFnDef(_, _, ref f) |
+        ty::TyFnDef(.., ref f) |
         ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
         _ => false,
     }
@@ -85,7 +85,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
             FnKind::ItemFn(_, _, unsafety, ..) =>
                 (true, unsafety == hir::Unsafety::Unsafe),
-            FnKind::Method(_, sig, _, _) =>
+            FnKind::Method(_, sig, ..) =>
                 (true, sig.unsafety == hir::Unsafety::Unsafe),
             _ => (false, false),
         };
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 66c8a8ac0d37b..d32954d3800ad 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -409,7 +409,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 self.consume_exprs(args);
             }
 
-            hir::ExprMethodCall(_, _, ref args) => { // callee.m(args)
+            hir::ExprMethodCall(.., ref args) => { // callee.m(args)
                 self.consume_exprs(args);
             }
 
@@ -940,9 +940,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                pat);
         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
             match pat.node {
-                PatKind::Binding(hir::BindByRef(..), _, _) =>
+                PatKind::Binding(hir::BindByRef(..), ..) =>
                     mode.lub(BorrowingMatch),
-                PatKind::Binding(hir::BindByValue(..), _, _) => {
+                PatKind::Binding(hir::BindByValue(..), ..) => {
                     match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) {
                         Copy => mode.lub(CopyingMatch),
                         Move(..) => mode.lub(MovingMatch),
@@ -964,7 +964,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         let infcx = self.mc.infcx;
         let delegate = &mut self.delegate;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
-            if let PatKind::Binding(bmode, _, _) = pat.node {
+            if let PatKind::Binding(bmode, ..) = pat.node {
                 debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
 
                 // pat_ty: the type of the binding being produced.
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index a1a4f15b9f78e..61bcc05bbb4f4 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -52,7 +52,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty {
-            ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
+            ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic,
             _ => return false
         };
         intrinsic && self.infcx.tcx.item_name(def_id).as_str() == "transmute"
@@ -160,7 +160,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
                 Def::Fn(did) if self.def_id_is_transmute(did) => {
                     let typ = self.infcx.tcx.node_id_to_type(expr.id);
                     match typ.sty {
-                        ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
+                        ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
                             let from = bare_fn_ty.sig.0.inputs[0];
                             let to = bare_fn_ty.sig.0.output;
                             self.check_transmute(expr.span, from, to, expr.id);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index b83826de26dd6..b579c69cd05c0 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -482,7 +482,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
-      hir::ExprBinary(op, _, _) if op.node.is_lazy() => {
+      hir::ExprBinary(op, ..) if op.node.is_lazy() => {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
@@ -943,7 +943,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               self.propagate_through_expr(&e, succ)
           }
 
-          hir::ExprClosure(_, _, ref blk, _) => {
+          hir::ExprClosure(.., ref blk, _) => {
               debug!("{} is an ExprClosure",
                      expr_to_string(expr));
 
@@ -1123,7 +1123,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_expr(&f, succ)
           }
 
-          hir::ExprMethodCall(_, _, ref args) => {
+          hir::ExprMethodCall(.., ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
             let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
             // FIXME(canndrew): This is_never should really be an is_uninhabited
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index b17411ced57fb..f8eb0d4a0ece8 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -228,7 +228,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult {
             Ok(deref_interior(InteriorField(PositionalField(0))))
         }
 
-        ty::TyArray(_, _) | ty::TySlice(_) => {
+        ty::TyArray(..) | ty::TySlice(_) => {
             // no deref of indexed content without supplying InteriorOffsetKind
             if let Some(context) = context {
                 Ok(deref_interior(InteriorElement(context, ElementKind::VecElement)))
@@ -318,7 +318,7 @@ impl MutabilityCategory {
     fn from_local(tcx: TyCtxt, id: ast::NodeId) -> MutabilityCategory {
         let ret = match tcx.map.get(id) {
             ast_map::NodeLocal(p) => match p.node {
-                PatKind::Binding(bind_mode, _, _) => {
+                PatKind::Binding(bind_mode, ..) => {
                     if bind_mode == hir::BindByValue(hir::MutMutable) {
                         McDeclared
                     } else {
@@ -419,7 +419,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // *being borrowed* is.  But ideally we would put in a more
         // fundamental fix to this conflated use of the node id.
         let ret_ty = match pat.node {
-            PatKind::Binding(hir::BindByRef(_), _, _) => {
+            PatKind::Binding(hir::BindByRef(_), ..) => {
                 // a bind-by-ref means that the base_ty will be the type of the ident itself,
                 // but what we want here is the type of the underlying value being borrowed.
                 // So peel off one-level, turning the &T into T.
@@ -761,7 +761,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             };
 
             match fn_expr.node {
-                hir::ExprClosure(_, _, ref body, _) => body.id,
+                hir::ExprClosure(.., ref body, _) => body.id,
                 _ => bug!()
             }
         };
@@ -1185,7 +1185,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          PatKind::Binding(_, _, Some(ref subpat)) => {
+          PatKind::Binding(.., Some(ref subpat)) => {
               self.cat_pattern_(cmt, &subpat, op)?;
           }
 
@@ -1225,7 +1225,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          PatKind::Path(..) | PatKind::Binding(_, _, None) |
+          PatKind::Path(..) | PatKind::Binding(.., None) |
           PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
             // always ok
           }
@@ -1275,9 +1275,9 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Rvalue(..) |
             Categorization::StaticItem |
             Categorization::Local(..) |
-            Categorization::Deref(_, _, UnsafePtr(..)) |
-            Categorization::Deref(_, _, BorrowedPtr(..)) |
-            Categorization::Deref(_, _, Implicit(..)) |
+            Categorization::Deref(.., UnsafePtr(..)) |
+            Categorization::Deref(.., BorrowedPtr(..)) |
+            Categorization::Deref(.., Implicit(..)) |
             Categorization::Upvar(..) => {
                 Rc::new((*self).clone())
             }
@@ -1320,7 +1320,7 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Rvalue(..) |
             Categorization::Local(..) |
             Categorization::Upvar(..) |
-            Categorization::Deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
+            Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but...
                 NonAliasable
             }
 
@@ -1349,9 +1349,9 @@ impl<'tcx> cmt_<'tcx> {
         match self.note {
             NoteClosureEnv(..) | NoteUpvarRef(..) => {
                 Some(match self.cat {
-                    Categorization::Deref(ref inner, _, _) => {
+                    Categorization::Deref(ref inner, ..) => {
                         match inner.cat {
-                            Categorization::Deref(ref inner, _, _) => inner.clone(),
+                            Categorization::Deref(ref inner, ..) => inner.clone(),
                             Categorization::Upvar(..) => inner.clone(),
                             _ => bug!()
                         }
@@ -1379,7 +1379,7 @@ impl<'tcx> cmt_<'tcx> {
                     "local variable".to_string()
                 }
             }
-            Categorization::Deref(_, _, pk) => {
+            Categorization::Deref(.., pk) => {
                 let upvar = self.upvar();
                 match upvar.as_ref().map(|i| &i.cat) {
                     Some(&Categorization::Upvar(ref var)) => {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index ef905b51edfb2..fb99820f7c855 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -956,7 +956,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
     ///        | box P&
     fn is_binding_pat(pat: &hir::Pat) -> bool {
         match pat.node {
-            PatKind::Binding(hir::BindByRef(_), _, _) => true,
+            PatKind::Binding(hir::BindByRef(_), ..) => true,
 
             PatKind::Struct(_, ref field_pats, _) => {
                 field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index b6faf834b26f7..e897b16efab5a 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -157,7 +157,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
                 hir::ItemEnum(_, ref generics) |
                 hir::ItemStruct(_, ref generics) |
                 hir::ItemUnion(_, ref generics) |
-                hir::ItemTrait(_, ref generics, _, _) |
+                hir::ItemTrait(_, ref generics, ..) |
                 hir::ItemImpl(_, _, ref generics, ..) => {
                     // These kinds of items have only early bound lifetime parameters.
                     let lifetimes = &generics.lifetimes;
@@ -209,7 +209,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
                     this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)
                 })
             }
-            FnKind::Method(_, sig, _, _) => {
+            FnKind::Method(_, sig, ..) => {
                 self.visit_early_late(
                     fn_id,
                     decl,
@@ -455,7 +455,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
 
     fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
         match ex.node {
-            hir::ExprWhile(_, _, Some(label)) |
+            hir::ExprWhile(.., Some(label)) |
             hir::ExprLoop(_, Some(label)) => Some((label.node, label.span)),
             _ => None,
         }
@@ -503,7 +503,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(generics);
             }
-            FnKind::Method(_, sig, _, _) => {
+            FnKind::Method(_, sig, ..) => {
                 intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(&sig.generics);
             }
@@ -583,7 +583,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 start += 1; // Self comes first.
             }
             match parent.node {
-                hir::ItemTrait(_, ref generics, _, _) |
+                hir::ItemTrait(_, ref generics, ..) |
                 hir::ItemImpl(_, _, ref generics, ..) => {
                     start += generics.lifetimes.len() + generics.ty_params.len();
                 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 9fc83557fa44b..c62c99c3b7062 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -553,7 +553,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
                                            &Option)) {
     let span;
     let id = match e.node {
-        hir::ExprMethodCall(i, _, _) => {
+        hir::ExprMethodCall(i, ..) => {
             span = i.span;
             let method_call = ty::MethodCall::expr(e.id);
             tcx.tables.borrow().method_map[&method_call].def_id
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index a0ccc72aa1fce..c82e723525b45 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -153,7 +153,7 @@ impl<'tcx> Rvalue<'tcx> {
                 ))
             }
             &Rvalue::Len(..) => Some(tcx.types.usize),
-            &Rvalue::Cast(_, _, ty) => Some(ty),
+            &Rvalue::Cast(.., ty) => Some(ty),
             &Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index a2f926aa92c52..5917c8f90e037 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1535,8 +1535,8 @@ pub fn get_unstable_features_setting() -> UnstableFeatures {
     let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
     match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
         (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
-        (true, _, _) => UnstableFeatures::Disallow,
-        (false, _, _) => UnstableFeatures::Allow
+        (true, ..) => UnstableFeatures::Disallow,
+        (false, ..) => UnstableFeatures::Allow
     }
 }
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index f8f10d9c26541..3f2bc8cbd13c5 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1379,7 +1379,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             // provide an impl, but only for suitable `fn` pointers
-            ty::TyFnDef(_, _, &ty::BareFnTy {
+            ty::TyFnDef(.., &ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -1635,7 +1635,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             // [T; n] -> [T].
-            (&ty::TyArray(_, _), &ty::TySlice(_)) => true,
+            (&ty::TyArray(..), &ty::TySlice(_)) => true,
 
             // Struct -> Struct.
             (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index ae9fd5ab5bc87..3386d894196fa 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -160,7 +160,7 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
 
                     AdjustReifyFnPointer => {
                         match self.sty {
-                            ty::TyFnDef(_, _, f) => tcx.mk_fn_ptr(f),
+                            ty::TyFnDef(.., f) => tcx.mk_fn_ptr(f),
                             _ => {
                                 bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}",
                                      self);
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index d7d4693c1165f..e0e8a329e6e1d 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -202,7 +202,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                     TC::None
                 }
 
-                ty::TyRef(_, _) => {
+                ty::TyRef(..) => {
                     TC::None
                 }
 
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index f9ca2484d7efc..84f34a640dd8e 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -90,7 +90,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyTuple(ref tys) => {
             Some(TupleSimplifiedType(tys.len()))
         }
-        ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
+        ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
             Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
         }
         ty::TyProjection(_) | ty::TyParam(_) => {
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index ba8d332850925..ddb0a6970cba5 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -337,7 +337,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option {
                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
                                    .next(),
 
-        ty::TyFnDef(def_id, _, _) |
+        ty::TyFnDef(def_id, ..) |
         ty::TyClosure(def_id, _) => Some(def_id),
 
         ty::TyBool |
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index a9b3833b40175..dfe24d5627bf1 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1269,7 +1269,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
         match tcx.map.find(id) {
             Some(ast_map::NodeImplItem(ref impl_item)) => {
                 match impl_item.node {
-                    hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(_, _) => {
+                    hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(..) => {
                         // associated types don't have their own entry (for some reason),
                         // so for now just grab environment for the impl
                         let impl_id = tcx.map.get_parent(id);
@@ -2290,7 +2290,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             match self.map.expect_item(id).node {
                 ItemTrait(.., ref tis) => {
                     tis.iter().filter_map(|ti| {
-                        if let hir::ConstTraitItem(_, _) = ti.node {
+                        if let hir::ConstTraitItem(..) = ti.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
                                 ConstTraitItem(ac) => Some(ac),
                                 _ => {
@@ -2306,7 +2306,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 }
                 ItemImpl(.., ref iis) => {
                     iis.iter().filter_map(|ii| {
-                        if let hir::ImplItemKind::Const(_, _) = ii.node {
+                        if let hir::ImplItemKind::Const(..) = ii.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
                                 ConstTraitItem(ac) => Some(ac),
                                 _ => {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index d45fde925c511..7ded2b05f3b5b 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1171,7 +1171,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
     pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
         match self.sty {
-            TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig,
+            TyFnDef(.., ref f) | TyFnPtr(ref f) => &f.sig,
             _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
         }
     }
@@ -1179,7 +1179,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     /// Returns the ABI of the given function.
     pub fn fn_abi(&self) -> abi::Abi {
         match self.sty {
-            TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi,
+            TyFnDef(.., ref f) | TyFnPtr(ref f) => f.abi,
             _ => bug!("Ty::fn_abi() called on non-fn type"),
         }
     }
@@ -1252,7 +1252,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             TyFloat(_) |
             TyBox(_) |
             TyStr |
-            TyArray(_, _) |
+            TyArray(..) |
             TySlice(_) |
             TyRawPtr(_) |
             TyNever |
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index ad209094600ae..51ca6bfeb5aff 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -439,7 +439,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
             TyRef(_, m) => self.hash(m.mutbl),
             TyClosure(def_id, _) |
             TyAnon(def_id, _) |
-            TyFnDef(def_id, _, _) => self.def_id(def_id),
+            TyFnDef(def_id, ..) => self.def_id(def_id),
             TyFnPtr(f) => {
                 self.hash(f.unsafety);
                 self.hash(f.abi);
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index b4c6689c24b9e..6f4c48d632a7a 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -56,7 +56,7 @@ fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<
                 }
             }
             LpDowncast(ref lp_base, _) |
-            LpExtend(ref lp_base, _, _) => helper(&lp_base)
+            LpExtend(ref lp_base, ..) => helper(&lp_base)
         }
     }
 }
@@ -80,7 +80,7 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc>) -> Rc helper(lp_base)
+            LpExtend(ref lp_base, ..) => helper(lp_base)
         }
     }
 }
@@ -312,7 +312,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                     break;
                 }
                 LpDowncast(ref lp_base, _) |
-                LpExtend(ref lp_base, _, _) => {
+                LpExtend(ref lp_base, ..) => {
                     loan_path = &lp_base;
                 }
             }
@@ -542,7 +542,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                     err
                 }
 
-                (_, _) => {
+                (..) => {
                     let mut err = struct_span_err!(self.bccx, new_loan.span, E0502,
                                                    "cannot borrow `{}`{} as {} because \
                                                    {} is also borrowed as {}{}",
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index 86f396d8982b0..45f5c3288a6d0 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -365,9 +365,9 @@ fn add_fragment_siblings<'a, 'tcx>(this: &MoveData<'tcx>,
         }
 
         // *LV for unsafe and borrowed pointers do not consume their loan path, so stop here.
-        LpExtend(_, _, LpDeref(mc::UnsafePtr(..)))   |
-        LpExtend(_, _, LpDeref(mc::Implicit(..)))    |
-        LpExtend(_, _, LpDeref(mc::BorrowedPtr(..))) => {}
+        LpExtend(.., LpDeref(mc::UnsafePtr(..)))   |
+        LpExtend(.., LpDeref(mc::Implicit(..)))    |
+        LpExtend(.., LpDeref(mc::BorrowedPtr(..))) => {}
 
         // FIXME (pnkfelix): LV[j] should be tracked, at least in the
         // sense of we will track the remaining drop obligation of the
@@ -378,7 +378,7 @@ fn add_fragment_siblings<'a, 'tcx>(this: &MoveData<'tcx>,
         // bind.
         //
         // Anyway, for now: LV[j] is not tracked precisely
-        LpExtend(_, _, LpInterior(_, InteriorElement(..))) => {
+        LpExtend(.., LpInterior(_, InteriorElement(..))) => {
             let mp = this.move_path(tcx, lp.clone());
             gathered_fragments.push(AllButOneFrom(mp));
         }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 3cf02fc85a463..5f2d6c406c4b9 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -161,9 +161,9 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                                cmt: &mc::cmt<'tcx>)
                                                -> Option> {
     match cmt.cat {
-        Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
-        Categorization::Deref(_, _, mc::Implicit(..)) |
-        Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+        Categorization::Deref(.., mc::BorrowedPtr(..)) |
+        Categorization::Deref(.., mc::Implicit(..)) |
+        Categorization::Deref(.., mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
             Some(cmt.clone())
         }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index 9f95175d59d43..5970d6e4f2f65 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -74,9 +74,9 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
             Categorization::Rvalue(..) |
             Categorization::Local(..) |                         // L-Local
             Categorization::Upvar(..) |
-            Categorization::Deref(_, _, mc::BorrowedPtr(..)) |  // L-Deref-Borrowed
-            Categorization::Deref(_, _, mc::Implicit(..)) |
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
+            Categorization::Deref(.., mc::BorrowedPtr(..)) |  // L-Deref-Borrowed
+            Categorization::Deref(.., mc::Implicit(..)) |
+            Categorization::Deref(.., mc::UnsafePtr(..)) => {
                 self.check_scope(self.scope(cmt))
             }
 
@@ -119,11 +119,11 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
                     self.bccx.tcx.region_maps.var_scope(local_id)))
             }
             Categorization::StaticItem |
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
+            Categorization::Deref(.., mc::UnsafePtr(..)) => {
                 self.bccx.tcx.mk_region(ty::ReStatic)
             }
-            Categorization::Deref(_, _, mc::BorrowedPtr(_, r)) |
-            Categorization::Deref(_, _, mc::Implicit(_, r)) => {
+            Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
+            Categorization::Deref(.., mc::Implicit(_, r)) => {
                 r
             }
             Categorization::Downcast(ref cmt, _) |
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index a255564f01e25..763c012a8f8ab 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -205,7 +205,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                         alias_cause);
             Err(())
         }
-        (_, _) => {
+        (..) => {
             Ok(())
         }
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index 61c85e393d2dd..bda68a1cd1ceb 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -117,9 +117,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                        move_from: mc::cmt<'tcx>)
                                        -> DiagnosticBuilder<'a> {
     match move_from.cat {
-        Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
-        Categorization::Deref(_, _, mc::Implicit(..)) |
-        Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+        Categorization::Deref(.., mc::BorrowedPtr(..)) |
+        Categorization::Deref(.., mc::Implicit(..)) |
+        Categorization::Deref(.., mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
             let mut err = struct_span_err!(bccx, move_from.span, E0507,
                              "cannot move out of {}",
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index e25adadbb2443..5d62629b64810 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -142,7 +142,7 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &hir::Item) {
     // loan step is intended for things that have a data
     // flow dependent conditions.
     match item.node {
-        hir::ItemStatic(_, _, ref ex) |
+        hir::ItemStatic(.., ref ex) |
         hir::ItemConst(_, ref ex) => {
             gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
         }
@@ -422,7 +422,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
                         tcx: TyCtxt) -> ast::NodeId {
     match tcx.map.get(closure_id) {
         hir_map::NodeExpr(expr) => match expr.node {
-            hir::ExprClosure(_, _, ref block, _) => {
+            hir::ExprClosure(.., ref block, _) => {
                 block.id
             }
             _ => {
@@ -442,7 +442,7 @@ impl<'a, 'tcx> LoanPath<'tcx> {
                 tcx.region_maps.node_extent(block_id)
             }
             LpDowncast(ref base, _) |
-            LpExtend(ref base, _, _) => base.kill_scope(tcx),
+            LpExtend(ref base, ..) => base.kill_scope(tcx),
         }
     }
 
@@ -464,7 +464,7 @@ impl<'a, 'tcx> LoanPath<'tcx> {
     fn depth(&self) -> usize {
         match self.kind {
             LpExtend(ref base, _, LpDeref(_)) => base.depth(),
-            LpExtend(ref base, _, LpInterior(_, _)) => base.depth() + 1,
+            LpExtend(ref base, _, LpInterior(..)) => base.depth() + 1,
             _ => 0,
         }
     }
@@ -1177,7 +1177,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 out.push(')');
             }
 
-            LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => {
+            LpVar(..) | LpUpvar(..) | LpExtend(.., LpInterior(..)) => {
                 self.append_loan_path_to_string(loan_path, out)
             }
         }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 236a1a2835c2a..0c9261df54870 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -197,7 +197,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
         LpVar(_) | LpUpvar(_) => {
             true
         }
-        LpExtend(_, _, LpInterior(_, InteriorKind::InteriorElement(..))) => {
+        LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => {
             // Paths involving element accesses a[i] do not refer to a unique
             // location, as there is no accurate tracking of the indices.
             //
@@ -207,7 +207,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
             false
         }
         LpDowncast(ref lp_base, _) |
-        LpExtend(ref lp_base, _, _) => {
+        LpExtend(ref lp_base, ..) => {
             loan_path_is_precise(&lp_base)
         }
     }
@@ -295,7 +295,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
             }
 
             LpDowncast(ref base, _) |
-            LpExtend(ref base, _, _) => {
+            LpExtend(ref base, ..) => {
                 let parent_index = self.move_path(tcx, base.clone());
 
                 let index = MovePathIndex(self.paths.borrow().len());
@@ -351,7 +351,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
                 match lp.kind {
                     LpVar(..) | LpUpvar(..) => { }
                     LpDowncast(ref b, _) |
-                    LpExtend(ref b, _, _) => {
+                    LpExtend(ref b, ..) => {
                         self.add_existing_base_paths(b, result);
                     }
                 }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index de28cbb7c9c96..e49011d887370 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -372,8 +372,8 @@ fn check_arms(cx: &MatchCheckCtxt,
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
 fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
     match p.node {
-        PatKind::Binding(_, _, None) => true,
-        PatKind::Binding(_, _, Some(ref s)) => pat_is_catchall(dm, &s),
+        PatKind::Binding(.., None) => true,
+        PatKind::Binding(.., Some(ref s)) => pat_is_catchall(dm, &s),
         PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
         PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)),
         _ => false
@@ -382,7 +382,7 @@ fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
 
 fn raw_pat(p: &Pat) -> &Pat {
     match p.node {
-        PatKind::Binding(_, _, Some(ref s)) => raw_pat(&s),
+        PatKind::Binding(.., Some(ref s)) => raw_pat(&s),
         _ => p
     }
 }
@@ -804,7 +804,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
             vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))],
         PatKind::Vec(ref before, ref slice, ref after) =>
             match left_ty.sty {
-                ty::TyArray(_, _) => vec![Single],
+                ty::TyArray(..) => vec![Single],
                 ty::TySlice(_) if slice.is_some() => {
                     (before.len() + after.len()..max_slice_length+1)
                         .map(|length| Slice(length))
@@ -866,7 +866,7 @@ fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
 {
     let pat_ty = cx.tcx.pat_ty(pat);
     (pat, Some(match pat.node {
-        PatKind::Binding(hir::BindByRef(..), _, _) => {
+        PatKind::Binding(hir::BindByRef(..), ..) => {
             pat_ty.builtin_deref(false, NoPreference).unwrap().ty
         }
         _ => pat_ty
@@ -1217,7 +1217,7 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
     fn visit_pat(&mut self, pat: &Pat) {
         match pat.node {
-            PatKind::Binding(_, _, ref subpat) => {
+            PatKind::Binding(.., ref subpat) => {
                 if !self.bindings_allowed {
                     span_err!(self.cx.tcx.sess, pat.span, E0303,
                               "pattern bindings are not allowed after an `@`");
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index a74b8848c4d6b..30e5a0cacf551 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -106,7 +106,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                hir::ConstTraitItem(_, _) => {
+                hir::ConstTraitItem(..) => {
                     if let Some(substs) = substs {
                         // If we have a trait item and the substitutions for it,
                         // `resolve_trait_associated_const` will select an impl
@@ -151,7 +151,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
-                hir::ConstTraitItem(_, _) => {
+                hir::ConstTraitItem(..) => {
                     used_substs = true;
                     if let Some(substs) = substs {
                         // As mentioned in the comments above for in-crate
@@ -231,7 +231,7 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
         FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
             Some(fn_like)
         }
-        FnKind::Method(_, m, _, _) => {
+        FnKind::Method(_, m, ..) => {
             if m.constness == hir::Constness::Const {
                 Some(fn_like)
             } else {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 6616e9579e818..3fc24bf6c54ec 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -24,6 +24,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(libc)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
@@ -802,7 +803,7 @@ Available lint options:
     let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
                                                                  .iter()
                                                                  .cloned()
-                                                                 .partition(|&(_, _, p)| p);
+                                                                 .partition(|&(.., p)| p);
     let plugin_groups = sort_lint_groups(plugin_groups);
     let builtin_groups = sort_lint_groups(builtin_groups);
 
@@ -877,7 +878,7 @@ Available lint options:
             println!("Compiler plugins can provide additional lints and lint groups. To see a \
                       listing of these, re-run `rustc -W help` with a crate filename.");
         }
-        (false, _, _) => panic!("didn't load lint plugins but got them anyway!"),
+        (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
         (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
         (true, l, g) => {
             if l > 0 {
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 8df8f50037118..bd96ae69ffbc8 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -196,7 +196,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let targets = match then_this_would_need.get(id) {
             Some(targets) => targets,
             None => {
-                for &(source_span, _, _) in sources.iter().take(1) {
+                for &(source_span, ..) in sources.iter().take(1) {
                     tcx.sess.span_err(
                         source_span,
                         &format!("no targets for id `{}`", id));
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index d4a3ab59f9cb3..3b7a97dd763d6 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -158,7 +158,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
         ExprCall(..)             => SawExprCall,
         ExprMethodCall(..)       => SawExprMethodCall,
         ExprTup(..)              => SawExprTup,
-        ExprBinary(op, _, _)     => SawExprBinary(op.node),
+        ExprBinary(op, ..)       => SawExprBinary(op.node),
         ExprUnary(op, _)         => SawExprUnary(op),
         ExprLit(ref lit)         => SawExprLit(lit.node.clone()),
         ExprCast(..)             => SawExprCast,
@@ -170,7 +170,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
         ExprClosure(..)          => SawExprClosure,
         ExprBlock(..)            => SawExprBlock,
         ExprAssign(..)           => SawExprAssign,
-        ExprAssignOp(op, _, _)   => SawExprAssignOp(op.node),
+        ExprAssignOp(op, ..)     => SawExprAssignOp(op.node),
         ExprField(_, name)       => SawExprField(name.node.as_str()),
         ExprTupField(_, id)      => SawExprTupField(id.node),
         ExprIndex(..)            => SawExprIndex,
@@ -179,7 +179,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
         ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.as_str())),
         ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.as_str())),
         ExprRet(..)              => SawExprRet,
-        ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
+        ExprInlineAsm(ref a,..)  => SawExprInlineAsm(a),
         ExprStruct(..)           => SawExprStruct,
         ExprRepeat(..)           => SawExprRepeat,
     }
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 511ba8ec19cc7..c866014c76728 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -19,6 +19,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(question_mark)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index 4ad4b115759c4..8166045be5f6f 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -880,12 +880,12 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
 fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option)>)
                           -> FnvHashMap> {
     let most_recent = deletion_candidates.iter()
-                                         .map(|&(timestamp, _, _)| timestamp)
+                                         .map(|&(timestamp, ..)| timestamp)
                                          .max();
 
     if let Some(most_recent) = most_recent {
         deletion_candidates.into_iter()
-                           .filter(|&(timestamp, _, _)| timestamp != most_recent)
+                           .filter(|&(timestamp, ..)| timestamp != most_recent)
                            .map(|(_, path, lock)| (path, lock))
                            .collect()
     } else {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index eb2ded45c04c5..a73930fa52517 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -72,7 +72,7 @@ impl LintPass for WhileTrue {
 
 impl LateLintPass for WhileTrue {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
-        if let hir::ExprWhile(ref cond, _, _) = e.node {
+        if let hir::ExprWhile(ref cond, ..) = e.node {
             if let hir::ExprLit(ref lit) = cond.node {
                 if let ast::LitKind::Bool(true) = lit.node {
                     cx.span_lint(WHILE_TRUE, e.span,
@@ -219,7 +219,7 @@ impl LateLintPass for UnsafeCode {
             FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
 
-            FnKind::Method(_, sig, _, _) => {
+            FnKind::Method(_, sig, ..) => {
                 if sig.unsafety == hir::Unsafety::Unsafe {
                     cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
                 }
@@ -1116,7 +1116,7 @@ impl LateLintPass for MutableTransmutes {
                 }
                 let typ = cx.tcx.node_id_to_type(expr.id);
                 match typ.sty {
-                    ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
+                    ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
                         let from = bare_fn.sig.0.inputs[0];
                         let to = bare_fn.sig.0.output;
                         return Some((&from.sty, &to.sty));
@@ -1129,7 +1129,7 @@ impl LateLintPass for MutableTransmutes {
 
         fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
             match cx.tcx.lookup_item_type(def_id).ty.sty {
-                ty::TyFnDef(_, _, ref bfty) if bfty.abi == RustIntrinsic => (),
+                ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
                 _ => return false
             }
             cx.tcx.item_name(def_id).as_str() == "transmute"
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 44f1cf7b53356..f07720f5202bd 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -334,7 +334,7 @@ impl UnusedParens {
                     contains_exterior_struct_lit(&x)
                 }
 
-                ast::ExprKind::MethodCall(_, _, ref exprs) => {
+                ast::ExprKind::MethodCall(.., ref exprs) => {
                     // X { y: 1 }.bar(...)
                     contains_exterior_struct_lit(&exprs[0])
                 }
@@ -355,15 +355,15 @@ impl EarlyLintPass for UnusedParens {
     fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
         use syntax::ast::ExprKind::*;
         let (value, msg, struct_lit_needs_parens) = match e.node {
-            If(ref cond, _, _) => (cond, "`if` condition", true),
-            While(ref cond, _, _) => (cond, "`while` condition", true),
-            IfLet(_, ref cond, _, _) => (cond, "`if let` head expression", true),
-            WhileLet(_, ref cond, _, _) => (cond, "`while let` head expression", true),
-            ForLoop(_, ref cond, _, _) => (cond, "`for` head expression", true),
+            If(ref cond, ..) => (cond, "`if` condition", true),
+            While(ref cond, ..) => (cond, "`while` condition", true),
+            IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
+            WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
+            ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
             Match(ref head, _) => (head, "`match` head expression", true),
             Ret(Some(ref value)) => (value, "`return` value", false),
             Assign(_, ref value) => (value, "assigned value", false),
-            AssignOp(_, _, ref value) => (value, "assigned value", false),
+            AssignOp(.., ref value) => (value, "assigned value", false),
             InPlace(_, ref value) => (value, "emplacement value", false),
             _ => return
         };
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 9d9c6f033a960..fb7e1c0f7895e 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -303,7 +303,7 @@ impl Folder for NestedItemsDropper {
         blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
             let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
                 let use_stmt = match stmt.node {
-                    hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
+                    hir::StmtExpr(..) | hir::StmtSemi(..) => true,
                     hir::StmtDecl(ref decl, _) => {
                         match decl.node {
                             hir::DeclLocal(_) => true,
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 2524348dc1a96..7eb452ddbab11 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -490,7 +490,7 @@ impl<'a> CrateReader<'a> {
         // numbers
         let map: FnvHashMap<_, _> = decoder::get_crate_deps(cdata).iter().map(|dep| {
             debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
-            let (local_cnum, _, _) = self.resolve_crate(root,
+            let (local_cnum, ..) = self.resolve_crate(root,
                                                         &dep.name,
                                                         &dep.name,
                                                         Some(&dep.hash),
@@ -1003,13 +1003,13 @@ impl<'a> LocalCrateReader<'a> {
                     if !info.should_link {
                         return;
                     }
-                    let (cnum, _, _) = self.creader.resolve_crate(&None,
-                                                                  &info.ident,
-                                                                  &info.name,
-                                                                  None,
-                                                                  i.span,
-                                                                  PathKind::Crate,
-                                                                  true);
+                    let (cnum, ..) = self.creader.resolve_crate(&None,
+                                                                &info.ident,
+                                                                &info.name,
+                                                                None,
+                                                                i.span,
+                                                                PathKind::Crate,
+                                                                true);
 
                     let def_id = self.definitions.opt_local_def_id(i.id).unwrap();
                     let len = self.definitions.def_path(def_id.index).data.len();
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index aeb95e5670d6a..6b48b4dfabcfd 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -492,7 +492,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
                    variant.name,
                    ctor_ty);
             let field_tys = match ctor_ty.sty {
-                ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+                ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
                     ref inputs, ..
                 }), ..}) => {
                     // tuple-struct constructors don't have escaping regions
@@ -952,7 +952,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a
             let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates);
             let ity = tcx.lookup_item_type(def_id).ty;
             let fty = match ity.sty {
-                ty::TyFnDef(_, _, fty) => fty,
+                ty::TyFnDef(.., fty) => fty,
                 _ => bug!(
                     "the type {:?} of the method {:?} is not a function?",
                     ity, name)
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 583631d2e0ab5..23398a0400c51 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -915,7 +915,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                 encode_deprecation(self.rbml_w, depr);
                 encode_attributes(self.rbml_w, &item.attrs);
             }
-            hir::ItemConst(_, _) => {
+            hir::ItemConst(..) => {
                 encode_def_id_and_key(ecx, self.rbml_w, def_id);
                 encode_family(self.rbml_w, 'C');
                 self.encode_bounds_and_type_for_item(item.id);
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index c8f660a2d9c7c..8812287c34294 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -217,7 +217,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
-        hir::ExprMethodCall(_, _, ref args) => {
+        hir::ExprMethodCall(.., ref args) => {
             // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
             let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
             let args = args.iter()
@@ -242,7 +242,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
 
                 let sig = match method.ty.sty {
-                    ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig,
+                    ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
                     _ => span_bug!(expr.span, "type of method is not an fn")
                 };
 
@@ -743,7 +743,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let body_id = match cx.tcx.map.find(closure_expr_id) {
                 Some(map::NodeExpr(expr)) => {
                     match expr.node {
-                        hir::ExprClosure(_, _, ref body, _) => body.id,
+                        hir::ExprClosure(.., ref body, _) => body.id,
                         _ => {
                             span_bug!(expr.span, "closure expr is not a closure expr");
                         }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 919b23ffda540..8dd33ad2f9c7a 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
                 match fn_like.map(|f| f.kind()) {
                     Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
-                    Some(FnKind::Method(_, m, _, _)) => m.constness,
+                    Some(FnKind::Method(_, m, ..)) => m.constness,
                     _ => hir::Constness::NotConst
                 }
             }
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 751f25b279401..0bcd3e6d4ebb3 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -122,7 +122,7 @@ fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
             Some(FnKind::ItemFn(_, _, _, c, ..)) => {
                 c == hir::Constness::Const
             }
-            Some(FnKind::Method(_, m, _, _)) => {
+            Some(FnKind::Method(_, m, ..)) => {
                 m.constness == hir::Constness::Const
             }
             _ => false
@@ -576,9 +576,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             Rvalue::Repeat(..) |
             Rvalue::UnaryOp(..) |
             Rvalue::CheckedBinaryOp(..) |
-            Rvalue::Cast(CastKind::ReifyFnPointer, _, _) |
-            Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
-            Rvalue::Cast(CastKind::Unsize, _, _) => {}
+            Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
+            Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
+            Rvalue::Cast(CastKind::Unsize, ..) => {}
 
             Rvalue::Len(_) => {
                 // Static lvalues in consts would have errored already,
@@ -705,7 +705,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             }
 
             Rvalue::Aggregate(ref kind, _) => {
-                if let AggregateKind::Adt(def, _, _, _) = *kind {
+                if let AggregateKind::Adt(def, ..) = *kind {
                     if def.has_dtor() {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 55bd51cd75ba9..e260b1d262aed 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -457,7 +457,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let func_ty = func.ty(mir, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
                 let func_ty = match func_ty.sty {
-                    ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty,
+                    ty::TyFnDef(.., func_ty) | ty::TyFnPtr(func_ty) => func_ty,
                     _ => {
                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
                         return;
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 6a24742426ab0..6275639a9adff 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -98,7 +98,7 @@ impl<'a> Visitor for AstValidator<'a> {
 
     fn visit_expr(&mut self, expr: &Expr) {
         match expr.node {
-            ExprKind::While(_, _, Some(ident)) |
+            ExprKind::While(.., Some(ident)) |
             ExprKind::Loop(_, Some(ident)) |
             ExprKind::WhileLet(.., Some(ident)) |
             ExprKind::ForLoop(.., Some(ident)) |
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 3094ff49f1f59..d4e8eb51cde27 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -149,7 +149,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         let mode = match fk {
             FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
                 => Mode::ConstFn,
-            FnKind::Method(_, m, _, _) => {
+            FnKind::Method(_, m, ..) => {
                 if m.constness == hir::Constness::Const {
                     Mode::ConstFn
                 } else {
@@ -307,8 +307,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                         hir::DeclItem(_) => continue,
                     }
                 }
-                hir::StmtExpr(_, _) => {}
-                hir::StmtSemi(_, _) => {}
+                hir::StmtExpr(..) => {}
+                hir::StmtSemi(..) => {}
             }
             self.add_qualif(ConstQualif::NOT_CONST);
         }
@@ -671,7 +671,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                 Categorization::StaticItem => {
                     break;
                 }
-                Categorization::Deref(ref cmt, _, _) |
+                Categorization::Deref(ref cmt, ..) |
                 Categorization::Downcast(ref cmt, _) |
                 Categorization::Interior(ref cmt, _) => cur = cmt,
 
@@ -716,7 +716,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                         // type of the expression.  `&mut [1]` has exactly the
                         // same representation as &mut 1.
                         match cmt.ty.sty {
-                            ty::TyArray(_, _) |
+                            ty::TyArray(..) |
                             ty::TySlice(_) => break,
                             _ => {}
                         }
@@ -727,7 +727,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                 Categorization::StaticItem => {
                     break;
                 }
-                Categorization::Deref(ref cmt, _, _) |
+                Categorization::Deref(ref cmt, ..) |
                 Categorization::Downcast(ref cmt, _) |
                 Categorization::Interior(ref cmt, _) => {
                     cur = cmt;
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index eab16bd5bd1b5..e942707acd56b 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -53,7 +53,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
             hir::ExprLoop(ref b, _) => {
                 self.with_context(Loop, |v| v.visit_block(&b));
             }
-            hir::ExprClosure(_, _, ref b, _) => {
+            hir::ExprClosure(.., ref b, _) => {
                 self.with_context(Closure, |v| v.visit_block(&b));
             }
             hir::ExprBreak(_) => self.require_loop("break", e.span),
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 5e374ce7c5803..8c72933c4ce46 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -249,7 +249,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             // The interface is empty
             hir::ItemDefaultImpl(..) => {}
             // Visit everything except for private impl items
-            hir::ItemImpl(_, _, ref generics, None, _, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, None, _, ref impl_items) => {
                 if item_level.is_some() {
                     self.reach().visit_generics(generics);
                     for impl_item in impl_items {
@@ -454,7 +454,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 if let Def::Struct(..) = self.tcx.expect_def(expr.id) {
                     let expr_ty = self.tcx.expr_ty(expr);
                     let def = match expr_ty.sty {
-                        ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+                        ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
                             output: ty, ..
                         }), ..}) => ty,
                         _ => expr_ty
@@ -644,7 +644,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
             // namespace (the contents have their own privacies).
             hir::ItemForeignMod(_) => {}
 
-            hir::ItemTrait(_, _, ref bounds, _) => {
+            hir::ItemTrait(.., ref bounds, _) => {
                 if !self.trait_is_public(item.id) {
                     return
                 }
@@ -659,7 +659,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
             // (i.e. we could just return here to not check them at
             // all, or some worse estimation of whether an impl is
             // publicly visible).
-            hir::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => {
+            hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_items) => {
                 // `impl [... for] Private` is never visible.
                 let self_contains_private;
                 // impl [... for] Public<...>, but not `impl [... for]
@@ -1091,7 +1091,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
             hir::ItemDefaultImpl(..) => {}
             // An inherent impl is public when its type is public
             // Subitems of inherent impls have their own publicity
-            hir::ItemImpl(_, _, ref generics, None, ref ty, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, None, ref ty, ref impl_items) => {
                 let ty_vis = self.ty_visibility(ty);
                 check.required_visibility = ty_vis;
                 check.visit_generics(generics);
@@ -1105,7 +1105,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
             }
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity
-            hir::ItemImpl(_, _, ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
                 let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref));
                 check.required_visibility = vis;
                 check.visit_generics(generics);
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 98ddff70462c9..ad750ccc01299 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -228,7 +228,7 @@ impl<'b> Resolver<'b> {
                 let def = Def::Static(self.definitions.local_def_id(item.id), mutbl);
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
-            ItemKind::Const(_, _) => {
+            ItemKind::Const(..) => {
                 let def = Def::Const(self.definitions.local_def_id(item.id));
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
@@ -292,7 +292,7 @@ impl<'b> Resolver<'b> {
                 self.structs.insert(item_def_id, field_names);
             }
 
-            ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
+            ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => {}
 
             ItemKind::Trait(.., ref items) => {
                 let def_id = self.definitions.local_def_id(item.id);
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index bc923ba29ca47..93abe07128fa1 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -95,7 +95,7 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> {
             }
             ast::ItemKind::Use(ref p) => {
                 match p.node {
-                    ViewPathSimple(_, _) => {
+                    ViewPathSimple(..) => {
                         self.check_import(item.id, p.span)
                     }
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0a86eeef7c45b..0420fa8026884 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -381,7 +381,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                                     module = path,
                                     ident = ident.node)
                         }
-                        Some(&ExprKind::MethodCall(ident, _, _)) => {
+                        Some(&ExprKind::MethodCall(ident, ..)) => {
                             format!("to call a function from the `{module}` module, \
                                      use `{module}::{ident}(..)`",
                                     module = path,
@@ -1643,7 +1643,7 @@ impl<'a> Resolver<'a> {
             ItemKind::DefaultImpl(_, ref trait_ref) => {
                 self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
             }
-            ItemKind::Impl(_, _, ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
+            ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
                 self.resolve_implementation(generics,
                                             opt_trait_ref,
                                             &self_type,
@@ -2369,7 +2369,7 @@ impl<'a> Resolver<'a> {
                     self.record_def(pat.id, resolution);
                 }
 
-                PatKind::TupleStruct(ref path, _, _) => {
+                PatKind::TupleStruct(ref path, ..) => {
                     self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
                         match def {
                             Def::Struct(..) | Def::Variant(..) => true,
@@ -2388,7 +2388,7 @@ impl<'a> Resolver<'a> {
                     }, "variant, struct or constant");
                 }
 
-                PatKind::Struct(ref path, _, _) => {
+                PatKind::Struct(ref path, ..) => {
                     self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
                         match def {
                             Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
@@ -2963,7 +2963,7 @@ impl<'a> Resolver<'a> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::Struct(ref path, _, _) => {
+            ExprKind::Struct(ref path, ..) => {
                 // Resolve the path to the structure it goes to. We don't
                 // check to ensure that the path is actually a structure; that
                 // is checked later during typeck.
@@ -2985,7 +2985,7 @@ impl<'a> Resolver<'a> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::Loop(_, Some(label)) | ExprKind::While(_, _, Some(label)) => {
+            ExprKind::Loop(_, Some(label)) | ExprKind::While(.., Some(label)) => {
                 self.with_label_rib(|this| {
                     let def = Def::Label(expr.id);
 
@@ -3077,7 +3077,7 @@ impl<'a> Resolver<'a> {
                 let traits = self.get_traits_containing_item(name.node.name);
                 self.trait_map.insert(expr.id, traits);
             }
-            ExprKind::MethodCall(name, _, _) => {
+            ExprKind::MethodCall(name, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}",
                        expr.id);
                 let traits = self.get_traits_containing_item(name.node.name);
@@ -3241,7 +3241,7 @@ impl<'a> Resolver<'a> {
                     if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
                         // add the module to the lookup
                         let is_extern = in_module_is_extern || name_binding.is_extern_crate();
-                        if !worklist.iter().any(|&(m, _, _)| m.def == module.def) {
+                        if !worklist.iter().any(|&(m, ..)| m.def == module.def) {
                             worklist.push((module, path_segments, is_extern));
                         }
                     }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 329527b304e3e..eaf2a8f5e7817 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -312,7 +312,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     qualname: String::new()
                 }.lower(self.tcx));
             }
-            Def::Static(_, _) |
+            Def::Static(..) |
             Def::Const(_) |
             Def::AssociatedConst(..) |
             Def::Local(..) |
@@ -351,7 +351,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             let mut collector = PathCollector::new();
             collector.visit_pat(&arg.pat);
             let span_utils = self.span.clone();
-            for &(id, ref p, _, _) in &collector.collected_paths {
+            for &(id, ref p, ..) in &collector.collected_paths {
                 let typ = self.tcx.node_types().get(&id).unwrap().to_string();
                 // get the span only for the name of the variable (I hope the path is only ever a
                 // variable name, but who knows?)
@@ -879,7 +879,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 }
             }
             Def::Local(..) |
-            Def::Static(_,_) |
+            Def::Static(..) |
             Def::Const(..) |
             Def::AssociatedConst(..) |
             Def::Struct(..) |
@@ -1145,7 +1145,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 self.process_static_or_const_item(item, &typ, &expr),
             Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
-            Impl(_, _,
+            Impl(..,
                           ref ty_params,
                           ref trait_ref,
                           ref typ,
@@ -1280,7 +1280,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 let def = self.tcx.expect_def(hir_expr.id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
             }
-            ast::ExprKind::MethodCall(_, _, ref args) => self.process_method_call(ex, args),
+            ast::ExprKind::MethodCall(.., ref args) => self.process_method_call(ex, args),
             ast::ExprKind::Field(ref sub_ex, _) => {
                 self.visit_expr(&sub_ex);
 
@@ -1409,7 +1409,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
                 }
                 // FIXME(nrc) what are these doing here?
-                Def::Static(_, _) |
+                Def::Static(..) |
                 Def::Const(..) |
                 Def::AssociatedConst(..) => {}
                 def => error!("unexpected definition kind when processing collected paths: {:?}",
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 559893b26facc..f69edea047e31 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -422,7 +422,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     }
                 }
             }
-            ast::ExprKind::Struct(ref path, _, _) => {
+            ast::ExprKind::Struct(ref path, ..) => {
                 match self.tcx.expr_ty_adjusted(&hir_node).sty {
                     ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
@@ -694,11 +694,11 @@ impl PathCollector {
 impl Visitor for PathCollector {
     fn visit_pat(&mut self, p: &ast::Pat) {
         match p.node {
-            PatKind::Struct(ref path, _, _) => {
+            PatKind::Struct(ref path, ..) => {
                 self.collected_paths.push((p.id, path.clone(),
                                            ast::Mutability::Mutable, recorder::TypeRef));
             }
-            PatKind::TupleStruct(ref path, _, _) |
+            PatKind::TupleStruct(ref path, ..) |
             PatKind::Path(_, ref path) => {
                 self.collected_paths.push((p.id, path.clone(),
                                            ast::Mutability::Mutable, recorder::VarRef));
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 15a9d58c9b574..9eeefa079fb63 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -701,7 +701,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {}",
            r, name, sizing, dst);
     match *r {
-        CEnum(ity, _, _) => ll_inttype(cx, ity),
+        CEnum(ity, ..) => ll_inttype(cx, ity),
         RawNullablePointer { nnty, .. } =>
             type_of::sizing_type_of(cx, nnty),
         StructWrappedNullablePointer { nonnull: ref st, .. } => {
@@ -839,7 +839,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
 pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
     match *r {
-        CEnum(ity, _, _) => ity.is_signed(),
+        CEnum(ity, ..) => ity.is_signed(),
         General(ity, _) => ity.is_signed(),
         Univariant(..) | UntaggedUnion(..) => false,
         RawNullablePointer { .. } => false,
@@ -918,7 +918,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr,
 pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
                               -> ValueRef {
     match *r {
-        CEnum(ity, _, _) => {
+        CEnum(ity, ..) => {
             C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
         }
         General(ity, _) => {
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 081b4431bd7b8..04b814e2b9772 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -1130,10 +1130,10 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
     // inline with lifetime intrinsics, and O2+ we add an inliner with a
     // thresholds copied from clang.
     match (opt_level, opt_size, inline_threshold) {
-        (_, _, Some(t)) => {
+        (.., Some(t)) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
         }
-        (llvm::CodeGenOptLevel::Aggressive, _, _) => {
+        (llvm::CodeGenOptLevel::Aggressive, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
         }
         (_, llvm::CodeGenOptSizeDefault, _) => {
@@ -1142,16 +1142,16 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
         (_, llvm::CodeGenOptSizeAggressive, _) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
         }
-        (llvm::CodeGenOptLevel::None, _, _) => {
+        (llvm::CodeGenOptLevel::None, ..) => {
             llvm::LLVMRustAddAlwaysInlinePass(builder, false);
         }
-        (llvm::CodeGenOptLevel::Less, _, _) => {
+        (llvm::CodeGenOptLevel::Less, ..) => {
             llvm::LLVMRustAddAlwaysInlinePass(builder, true);
         }
-        (llvm::CodeGenOptLevel::Default, _, _) => {
+        (llvm::CodeGenOptLevel::Default, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
         }
-        (llvm::CodeGenOptLevel::Other, _, _) => {
+        (llvm::CodeGenOptLevel::Other, ..) => {
             bug!("CodeGenOptLevel::Other selected")
         }
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 99126095ede3e..c94de08118089 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -924,7 +924,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                block_arena: &'blk TypedArena>)
                -> FunctionContext<'blk, 'tcx> {
         let (param_substs, def_id) = match definition {
-            Some((instance, _, _)) => {
+            Some((instance, ..)) => {
                 common::validate_substs(instance.substs);
                 (instance.substs, Some(instance.def))
             }
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 805c7d345a0e7..eb67f4ca6185a 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -182,7 +182,7 @@ fn classify_ty(ty: Type) -> Vec {
             (SSEDs,       SSEUp) |
             (SSEInt(_),   SSEUp) => return,
 
-            (_,           _) => newv
+            (..) => newv
         };
         cls[i] = to_write;
     }
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 33cacbe194bb0..a6b92b949e0fc 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -98,7 +98,7 @@ impl<'tcx> Callee<'tcx> {
         }
 
         let fn_ty = def_ty(ccx.shared(), def_id, substs);
-        if let ty::TyFnDef(_, _, f) = fn_ty.sty {
+        if let ty::TyFnDef(.., f) = fn_ty.sty {
             if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
                 return Callee {
                     data: Intrinsic,
@@ -314,7 +314,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
     let sig = match bare_fn_ty.sty {
-        ty::TyFnDef(_, _,
+        ty::TyFnDef(..,
                     &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
                                     abi: Abi::Rust,
                                     ref sig }) |
@@ -442,7 +442,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // other weird situations. Annoying.
 
     let fn_ptr_ty = match fn_ty.sty {
-        ty::TyFnDef(_, _, fty) => {
+        ty::TyFnDef(.., fty) => {
             // Create a fn pointer with the substituted signature.
             tcx.mk_fn_ptr(fty)
         }
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index b5c922d7fda4b..704fac5ce7e53 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -628,7 +628,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                                               def_id: DefId)
                                               -> bool {
             if !match tcx.lookup_item_type(def_id).ty.sty {
-                ty::TyFnDef(def_id, _, _) => {
+                ty::TyFnDef(def_id, ..) => {
                     // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in
                     // translation item. Same for FFI functions.
@@ -1214,8 +1214,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
         hir::ItemImpl(_,
                       _,
                       ref generics,
-                      _,
-                      _,
+                      ..,
                       ref items) => {
             if generics.is_type_parameterized() {
                 return
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index bdfeee37625e8..1bf1023dcd895 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -252,7 +252,7 @@ impl<'tcx> TypeMap<'tcx> {
                                        principal.substs,
                                        &mut unique_type_id);
             },
-            ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+            ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
             ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
                 if unsafety == hir::Unsafety::Unsafe {
                     unique_type_id.push_str("unsafe ");
@@ -756,7 +756,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => {
+        ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => {
             let fn_metadata = subroutine_type_metadata(cx,
                                                        unique_type_id,
                                                        &barefnty.sig,
@@ -1679,7 +1679,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let type_rep = adt::represent_type(cx, enum_type);
 
     let discriminant_type_metadata = match *type_rep {
-        adt::CEnum(inttype, _, _) => {
+        adt::CEnum(inttype, ..) => {
             return FinalMetadata(discriminant_type_metadata(inttype))
         },
         adt::RawNullablePointer { .. }           |
@@ -1962,4 +1962,4 @@ pub fn extend_scope_to_file(ccx: &CrateContext,
             scope_metadata,
             file_metadata)
     }
-}
\ No newline at end of file
+}
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index bd839243e201f..8291f84054d0c 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -100,7 +100,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             push_item_name(cx, principal.def_id, false, output);
             push_type_params(cx, principal.substs, output);
         },
-        ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+        ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
         ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 8bef7584db9e2..c0ff6c508bf3e 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -544,7 +544,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
         }
 
-        (_, _) => {
+        (..) => {
             let intr = match Intrinsic::find(&name) {
                 Some(intr) => intr,
                 None => bug!("unknown intrinsic '{}'", name),
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 3ab4290e7b9b9..fbd04d7b38029 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -406,7 +406,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
-                    (&ty::TyFnDef(def_id, _, _), &Intrinsic) => {
+                    (&ty::TyFnDef(def_id, ..), &Intrinsic) => {
                         Some(bcx.tcx().item_name(def_id).as_str())
                     }
                     _ => None
@@ -880,7 +880,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // FIXME #19925 Remove this hack after a release cycle.
                 let f = Callee::def(bcx.ccx(), def_id, substs);
                 let ty = match f.ty.sty {
-                    ty::TyFnDef(_, _, f) => bcx.tcx().mk_fn_ptr(f),
+                    ty::TyFnDef(.., f) => bcx.tcx().mk_fn_ptr(f),
                     _ => f.ty
                 };
                 val = OperandRef {
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index deef0b09a17b0..3d85da42a6dc6 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -454,7 +454,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              &trait_data.projection_bounds,
                              output);
         },
-        ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+        ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
         ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index acb6653214dcb..49db56d2dabd9 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -186,7 +186,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let error_fn_sig;
 
         let fn_sig = match callee_ty.sty {
-            ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) |
+            ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) |
             ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
                 sig
             }
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 54e63497e6202..1fda38d8a3305 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -319,7 +319,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             (Some(t_from), Some(t_cast)) => (t_from, t_cast),
             // Function item types may need to be reified before casts.
             (None, Some(t_cast)) => {
-                if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
+                if let ty::TyFnDef(.., f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
                     let res = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f));
                     if !res.is_ok() {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 365c18d5e6661..60ca9309eea00 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -195,7 +195,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         }
 
         match a.sty {
-            ty::TyFnDef(_, _, a_f) => {
+            ty::TyFnDef(.., a_f) => {
                 // Function items are coercible to any closure
                 // type; function pointers are not (that would
                 // require double indirection).
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index bde7f20f5e6e6..eb87c230b74ad 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -53,7 +53,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     if i_n_tps != n_tps {
         let span = match it.node {
             hir::ForeignItemFn(_, ref generics) => generics.span,
-            hir::ForeignItemStatic(_, _) => it.span
+            hir::ForeignItemStatic(..) => it.span
         };
 
         struct_span_err!(tcx.sess, span, E0094,
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index be77ca435a18c..dbf74e371df45 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -501,7 +501,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                 assert!(adr.unsize.is_none());
                                 (adr.autoderefs, None)
                             }
-                            Some(AutoPtr(_, _)) => {
+                            Some(AutoPtr(..)) => {
                                 (adr.autoderefs, adr.unsize.map(|target| {
                                     target.builtin_deref(false, NoPreference)
                                             .expect("fixup: AutoPtr is not &T").ty
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index edee730086871..058049992dc00 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1314,8 +1314,8 @@ impl<'tcx> Candidate<'tcx> {
         Pick {
             item: self.item.clone(),
             kind: match self.kind {
-                InherentImplCandidate(_, _) => InherentImplPick,
-                ExtensionImplCandidate(def_id, _, _) => {
+                InherentImplCandidate(..) => InherentImplPick,
+                ExtensionImplCandidate(def_id, ..) => {
                     ExtensionImplPick(def_id)
                 }
                 ObjectCandidate => ObjectPick,
@@ -1340,10 +1340,10 @@ impl<'tcx> Candidate<'tcx> {
 
     fn to_source(&self) -> CandidateSource {
         match self.kind {
-            InherentImplCandidate(_, _) => {
+            InherentImplCandidate(..) => {
                 ImplSource(self.item.container().id())
             }
-            ExtensionImplCandidate(def_id, _, _) => ImplSource(def_id),
+            ExtensionImplCandidate(def_id, ..) => ImplSource(def_id),
             ObjectCandidate |
             TraitCandidate |
             WhereClauseCandidate(_) => TraitSource(self.item.container().id()),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 36c2494a00656..0aa523e9d5e47 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -536,7 +536,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            fn_id: ast::NodeId) {
     let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty;
     let fn_ty = match raw_fty.sty {
-        ty::TyFnDef(_, _, f) => f,
+        ty::TyFnDef(.., f) => f,
         _ => span_bug!(body.span, "check_bare_fn: function type expected")
     };
 
@@ -732,7 +732,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(_, _, ref e) |
+      hir::ItemStatic(.., ref e) |
       hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
       hir::ItemEnum(ref enum_definition, _) => {
         check_enum_variants(ccx,
@@ -2410,7 +2410,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.tcx.types.err
         } else {
             match method_fn_ty.sty {
-                ty::TyFnDef(_, _, ref fty) => {
+                ty::TyFnDef(.., ref fty) => {
                     // HACK(eddyb) ignore self in the definition (see above).
                     let expected_arg_tys = self.expected_types_for_fn_args(sp, expected,
                                                                            fty.sig.0.output,
@@ -2647,7 +2647,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            t)
                         }, arg_ty);
                     }
-                    ty::TyFnDef(_, _, f) => {
+                    ty::TyFnDef(.., f) => {
                         let ptr_ty = self.tcx.mk_fn_ptr(f);
                         let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
                         self.type_error_message(arg.span,
@@ -3983,7 +3983,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         _ => false,
                     }
                 }
-                hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
+                hir::StmtExpr(..) | hir::StmtSemi(..) => true,
             } {
                 self.tcx
                     .sess
@@ -4209,7 +4209,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
 
         match def {
-            Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
+            Def::Local(_, nid) | Def::Upvar(_, nid, ..) => {
                 let ty = self.local_ty(span, nid);
                 let ty = self.normalize_associated_types_in(span, &ty);
                 self.write_ty(node_id, ty);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index cef2bb07e35ca..939deee27c602 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -576,7 +576,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
                 /*
-                adjustment::AutoObject(_, ref bounds, _, _) => {
+                adjustment::AutoObject(_, ref bounds, ..) => {
                     // Determine if we are casting `expr` to a trait
                     // instance. If so, we have to be sure that the type
                     // of the source obeys the new region bound.
@@ -643,7 +643,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprMethodCall(_, _, ref args) => {
+            hir::ExprMethodCall(.., ref args) => {
                 self.constrain_call(expr, Some(&args[0]),
                                     args[1..].iter().map(|e| &**e), false);
 
@@ -758,7 +758,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprClosure(_, _, ref body, _) => {
+            hir::ExprClosure(.., ref body, _) => {
                 self.check_expr_fn_block(expr, &body);
             }
 
@@ -1156,7 +1156,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
                 match sub_pat.node {
                     // `ref x` pattern
-                    PatKind::Binding(hir::BindByRef(mutbl), _, _) => {
+                    PatKind::Binding(hir::BindByRef(mutbl), ..) => {
                         self.link_region_from_node_type(sub_pat.span, sub_pat.id,
                                                         mutbl, sub_cmt);
                     }
@@ -1269,7 +1269,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     borrow_kind = borrow_kind;
                 }
 
-                Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+                Categorization::Deref(.., mc::UnsafePtr(..)) |
                 Categorization::StaticItem |
                 Categorization::Upvar(..) |
                 Categorization::Local(..) |
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index a85e295784e97..f4a0df4611d33 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -283,8 +283,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
                guarantor);
         match guarantor.cat {
-            Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
-            Categorization::Deref(_, _, mc::Implicit(..)) => {
+            Categorization::Deref(.., mc::BorrowedPtr(..)) |
+            Categorization::Deref(.., mc::Implicit(..)) => {
                 match cmt.note {
                     mc::NoteUpvarRef(upvar_id) => {
                         debug!("adjust_upvar_borrow_kind_for_consume: \
@@ -344,7 +344,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                 }
             }
 
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+            Categorization::Deref(.., mc::UnsafePtr(..)) |
             Categorization::StaticItem |
             Categorization::Rvalue(_) |
             Categorization::Local(_) |
@@ -376,7 +376,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                 }
             }
 
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+            Categorization::Deref(.., mc::UnsafePtr(..)) |
             Categorization::StaticItem |
             Categorization::Rvalue(_) |
             Categorization::Local(_) |
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 8eb7d34568762..6e87c29c4b363 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -112,7 +112,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                           ref trait_ref, ref self_ty, _) => {
                 self.check_impl(item, self_ty, trait_ref);
             }
-            hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
+            hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
                 // FIXME(#27579) what amount of WF checking do we need for neg impls?
 
                 let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
@@ -286,7 +286,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
             let bare_fn_ty = match item_ty.sty {
-                ty::TyFnDef(_, _, ref bare_fn_ty) => bare_fn_ty,
+                ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty,
                 _ => {
                     span_bug!(item.span, "Fn item without fn type");
                 }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3bd0e890bb811..4be032c6f7f09 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -201,7 +201,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.visit_method_map_entry(ResolvingExpr(e.span),
                                     MethodCall::expr(e.id));
 
-        if let hir::ExprClosure(_, ref decl, _, _) = e.node {
+        if let hir::ExprClosure(_, ref decl, ..) = e.node {
             for input in &decl.inputs {
                 self.visit_node_id(ResolvingExpr(e.span), input.id);
             }
@@ -323,7 +323,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
                     // Free regions that come from early-bound regions are valid.
                     ty::ReFree(ty::FreeRegion {
-                        bound_region: ty::BoundRegion::BrNamed(def_id, _, _), ..
+                        bound_region: ty::BoundRegion::BrNamed(def_id, ..), ..
                     }) if self.free_to_bound_regions.contains_key(&def_id) => {
                         self.free_to_bound_regions[&def_id]
                     }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 70682bb8c8f35..d2b7f07b9ce6c 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
             TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
             TyTuple(..) | TyParam(..) | TyError | TyNever |
-            TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
+            TyRawPtr(_) | TyRef(..) | TyProjection(..) => {
                 None
             }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a012fd418cac6..fcc0b09e31acf 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -740,7 +740,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
                                                     Some(trait_ref));
         }
-        hir::ItemImpl(_, _,
+        hir::ItemImpl(..,
                       ref generics,
                       ref opt_trait_ref,
                       ref selfty,
@@ -1456,7 +1456,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         generics
                     }
 
-                    ItemTrait(_, ref generics, _, _) => {
+                    ItemTrait(_, ref generics, ..) => {
                         // Add in the self type parameter.
                         //
                         // Something of a hack: use the node id for the trait, also as
@@ -1566,7 +1566,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let ty = match ccx.tcx.map.get(node_id) {
             NodeItem(item) => {
                 match item.node {
-                    ItemStatic(ref t, _, _) | ItemConst(ref t, _) => {
+                    ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
                         ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t)
                     }
                     ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 24eb29f45a5e5..1e38f464651b9 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -415,7 +415,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
             }
 
-            ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) |
+            ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
             ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
                 self.add_constraints_from_sig(generics, sig, variance);
             }
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index 1238f7cbcb335..577a47a35e125 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -238,7 +238,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
             hir::ItemUnion(_, ref generics) => {
                 self.add_inferreds_for_item(item.id, false, generics);
             }
-            hir::ItemTrait(_, ref generics, _, _) => {
+            hir::ItemTrait(_, ref generics, ..) => {
                 // Note: all inputs for traits are ultimately
                 // constrained to be invariant. See `visit_item` in
                 // the impl for `ConstraintContext` in `constraints.rs`.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index b7e371e23f323..18c12f98fb428 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -180,7 +180,7 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx
                                      did: DefId) -> clean::Function {
     let t = tcx.lookup_item_type(did);
     let (decl, style, abi) = match t.ty.sty {
-        ty::TyFnDef(_, _, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
+        ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
         _ => panic!("bad function"),
     };
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f8ec5a55e7d4c..4bab79ea8a99b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -642,7 +642,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, has_self: boo
                 output: output
             }
         },
-        (_, _) => {
+        (..) => {
             PathParameters::AngleBracketed {
                 lifetimes: lifetimes,
                 types: types.clean(cx),
@@ -717,7 +717,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> {
             if let ty::TyTuple(ts) = ty_s.sty {
                 for &ty_s in ts {
                     if let ty::TyRef(ref reg, _) = ty_s.sty {
-                        if let &ty::Region::ReLateBound(_, _) = *reg {
+                        if let &ty::Region::ReLateBound(..) = *reg {
                             debug!("  hit an ReLateBound {:?}", reg);
                             if let Some(lt) = reg.clean(cx) {
                                 late_bounds.push(lt);
@@ -1794,7 +1794,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> {
                 mutability: mt.mutbl.clean(cx),
                 type_: box mt.ty.clean(cx),
             },
-            ty::TyFnDef(_, _, ref fty) |
+            ty::TyFnDef(.., ref fty) |
             ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
                 unsafety: fty.unsafety,
                 generics: Generics {
@@ -2699,7 +2699,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
     match p.node {
         PatKind::Wild => "_".to_string(),
         PatKind::Binding(_, ref p, _) => p.node.to_string(),
-        PatKind::TupleStruct(ref p, _, _) | PatKind::Path(None, ref p) => path_to_string(p),
+        PatKind::TupleStruct(ref p, ..) | PatKind::Path(None, ref p) => path_to_string(p),
         PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \
                                      which is not allowed in function arguments"),
         PatKind::Struct(ref name, ref fields, etc) => {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 6f66ce88df7a5..61b80be969980 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1891,7 +1891,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec 0 =>
                         format!(" (#{})", Escape(&tracker_url), issue_no,
                                 issue_no),
-                    (true, _, _) =>
+                    (true, ..) =>
                         format!(" ({})", Escape(&stab.feature)),
                     _ => String::new(),
                 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0e685f063bd7b..cc5cdf9f4e74c 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -20,6 +20,7 @@
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(libc)]
 #![feature(rustc_private)]
 #![feature(set_stdio)]
@@ -420,7 +421,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
     let mut pm = plugins::PluginManager::new(PathBuf::from(path));
     for pass in &passes {
         let plugin = match PASSES.iter()
-                                 .position(|&(p, _, _)| {
+                                 .position(|&(p, ..)| {
                                      p == *pass
                                  }) {
             Some(i) => PASSES[i].1,
diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs
index 31b71dbc80b62..b5b344e8d5f24 100644
--- a/src/libserialize/hex.rs
+++ b/src/libserialize/hex.rs
@@ -82,7 +82,7 @@ impl fmt::Display for FromHexError {
 impl error::Error for FromHexError {
     fn description(&self) -> &str {
         match *self {
-            InvalidHexCharacter(_, _) => "invalid character",
+            InvalidHexCharacter(..) => "invalid character",
             InvalidHexLength => "invalid length",
         }
     }
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 9a5b1da0f08f4..0a9c77f253848 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -332,7 +332,7 @@ impl<'a> Prefix<'a> {
     pub fn is_verbatim(&self) -> bool {
         use self::Prefix::*;
         match *self {
-            Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true,
+            Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
             _ => false,
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index bbd3345144585..105f911dd575c 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -561,7 +561,7 @@ impl Pat {
             }
             PatKind::Wild |
             PatKind::Lit(_) |
-            PatKind::Range(_, _) |
+            PatKind::Range(..) |
             PatKind::Ident(..) |
             PatKind::Path(..) |
             PatKind::Mac(_) => {
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 7db03e9a8634a..b0696a986e3c0 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -156,7 +156,7 @@ pub fn count_names(ms: &[TokenTree]) -> usize {
             TokenTree::Token(_, MatchNt(..)) => {
                 1
             }
-            TokenTree::Token(_, _) => 0,
+            TokenTree::Token(..) => 0,
         }
     })
 }
@@ -231,7 +231,7 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc])
             TokenTree::Token(sp, SubstNt(..)) => {
                 return Err((sp, "missing fragment specifier".to_string()))
             }
-            TokenTree::Token(_, _) => (),
+            TokenTree::Token(..) => (),
         }
 
         Ok(())
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index dc0fb02ea45d9..ff01d37581544 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -180,7 +180,7 @@ impl Token {
             Ident(..)                   => true,
             Underscore                  => true,
             Tilde                       => true,
-            Literal(_, _)               => true,
+            Literal(..)                 => true,
             Not                         => true,
             BinOp(Minus)                => true,
             BinOp(Star)                 => true,
@@ -202,8 +202,8 @@ impl Token {
     /// Returns `true` if the token is any literal
     pub fn is_lit(&self) -> bool {
         match *self {
-            Literal(_, _) => true,
-            _             => false,
+            Literal(..) => true,
+            _           => false,
         }
     }
 
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 6f368e1bc6f06..77425b809de1d 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -233,7 +233,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     p.bump();
                     state = st;
                 }
-                (&token::Eof, _, _) => break 'statement,
+                (&token::Eof, ..) => break 'statement,
                 _ => break,
             }
         }
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index b974699003b97..f367fed9cc2ce 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -78,7 +78,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P {
+        EnumMatching(.., ref fields) => {
             let mut stmts = vec![];
             if !is_struct {
                 // tuple struct/"normal" variant
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index b37d533298399..600f5d335c472 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -976,7 +976,7 @@ impl<'a> MethodDef<'a> {
                         other: other_fields.iter_mut()
                             .map(|l| {
                                 match l.next().unwrap() {
-                                    (_, _, ex, _) => ex,
+                                    (.., ex, _) => ex,
                                 }
                             })
                             .collect(),
@@ -1527,7 +1527,7 @@ impl<'a> TraitDef<'a> {
             VariantData::Struct(..) => {
                 let field_pats = subpats.into_iter()
                     .zip(&ident_exprs)
-                    .map(|(pat, &(sp, ident, _, _))| {
+                    .map(|(pat, &(sp, ident, ..))| {
                         if ident.is_none() {
                             cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
                         }
@@ -1583,7 +1583,7 @@ pub fn cs_fold(use_foldl: bool,
     where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P
 {
     match *substructure.fields {
-        EnumMatching(_, _, ref all_fields) |
+        EnumMatching(.., ref all_fields) |
         Struct(_, ref all_fields) => {
             if use_foldl {
                 all_fields.iter().fold(base, |old, field| {
@@ -1623,7 +1623,7 @@ pub fn cs_same_method(f: F,
     where F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P
 {
     match *substructure.fields {
-        EnumMatching(_, _, ref all_fields) |
+        EnumMatching(.., ref all_fields) |
         Struct(_, ref all_fields) => {
             // call self_n.method(other_1_n, other_2_n, ...)
             let called = all_fields.iter()
diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs
index 0941ebca868e3..97d7f2ce8003e 100644
--- a/src/libsyntax_ext/deriving/hash.rs
+++ b/src/libsyntax_ext/deriving/hash.rs
@@ -82,7 +82,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
 
     let fields = match *substr.fields {
         Struct(_, ref fs) => fs,
-        EnumMatching(_, _, ref fs) => {
+        EnumMatching(.., ref fs) => {
             let variant_value = deriving::call_intrinsic(cx,
                                                          trait_span,
                                                          "discriminant_value",
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 4bae9ec5a1a1f..2065d92fd6ed7 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -19,6 +19,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_macro_lib)]
 #![feature(rustc_macro_internals)]
 #![feature(rustc_private)]
diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs
index fbc6bfb6c8d9f..bd5ab92e8b078 100644
--- a/src/libterm/terminfo/parm.rs
+++ b/src/libterm/terminfo/parm.rs
@@ -199,7 +199,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result {
+                            _ => {
                                 return Err("first two params not numbers with %i".to_string())
                             }
                         }
diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs
index 7a1c200ba20e8..3f36ebe649234 100644
--- a/src/test/run-make/save-analysis/foo.rs
+++ b/src/test/run-make/save-analysis/foo.rs
@@ -10,9 +10,9 @@
 
 #![ crate_name = "test" ]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_private)]
 
-
 extern crate graphviz;
 // A simple rust project
 
@@ -206,7 +206,7 @@ fn matchSomeEnum(val: SomeEnum) {
     match val {
         SomeEnum::Ints(int1, int2) => { println(&(int1+int2).to_string()); }
         SomeEnum::Floats(float1, float2) => { println(&(float2*float1).to_string()); }
-        SomeEnum::Strings(_, _, s3) => { println(s3); }
+        SomeEnum::Strings(.., s3) => { println(s3); }
         SomeEnum::MyTypes(mt1, mt2) => { println(&(mt1.field1 - mt2.field1).to_string()); }
     }
 }
@@ -225,7 +225,7 @@ fn matchSomeStructEnum2(se: SomeStructEnum) {
     match se {
         EnumStruct{a: ref aaa, ..} => println(&aaa.to_string()),
         EnumStruct2{f1, f2: f2} => println(&f1.field1.to_string()),
-        EnumStruct3{f1, f3: SomeEnum::Ints(_, _), f2} => println(&f1.field1.to_string()),
+        EnumStruct3{f1, f3: SomeEnum::Ints(..), f2} => println(&f1.field1.to_string()),
         _ => {},
     }
 }
@@ -435,4 +435,4 @@ fn test_format_args() {
     print!("Hello {0}", name);
     print!("{0} + {} = {}", x, y);
     print!("x is {}, y is {1}, name is {n}", x, y, n = name);
-}
\ No newline at end of file
+}
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
index c6174745bfc06..5df95ba5facbf 100644
--- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
@@ -12,6 +12,7 @@
 
 #![feature(plugin_registrar)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_private)]
 
 extern crate syntax;
@@ -75,7 +76,7 @@ fn expand(cx: &mut ExtCtxt,
 fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span,
                          substr: &Substructure) -> P {
     let fields = match *substr.fields {
-        Struct(_, ref fs) | EnumMatching(_, _, ref fs) => fs,
+        Struct(_, ref fs) | EnumMatching(.., ref fs) => fs,
         _ => cx.span_bug(trait_span, "impossible substructure")
     };
 

From 8d3fd03855c597ebaf81d727bae76217237f0a3f Mon Sep 17 00:00:00 2001
From: Andrew Paseltiner 
Date: Sun, 4 Sep 2016 10:16:25 -0400
Subject: [PATCH 529/768] Clean up thread-local storage docs

`std` no longer contains an implementation of scoped TLS.
---
 src/libstd/thread/mod.rs | 35 +++++++++++++++--------------------
 1 file changed, 15 insertions(+), 20 deletions(-)

diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index e3f3f9dd6de1e..d8e021bb04ff9 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -135,29 +135,24 @@
 //!
 //! ## Thread-local storage
 //!
-//! This module also provides an implementation of thread local storage for Rust
-//! programs. Thread local storage is a method of storing data into a global
-//! variable which each thread in the program will have its own copy of.
+//! This module also provides an implementation of thread-local storage for Rust
+//! programs. Thread-local storage is a method of storing data into a global
+//! variable that each thread in the program will have its own copy of.
 //! Threads do not share this data, so accesses do not need to be synchronized.
 //!
-//! At a high level, this module provides two variants of storage:
-//!
-//! * Owned thread-local storage. This is a type of thread local key which
-//!   owns the value that it contains, and will destroy the value when the
-//!   thread exits. This variant is created with the `thread_local!` macro and
-//!   can contain any value which is `'static` (no borrowed pointers).
-//!
-//! * Scoped thread-local storage. This type of key is used to store a reference
-//!   to a value into local storage temporarily for the scope of a function
-//!   call. There are no restrictions on what types of values can be placed
-//!   into this key.
-//!
-//! Both forms of thread local storage provide an accessor function, `with`,
-//! which will yield a shared reference to the value to the specified
-//! closure. Thread-local keys only allow shared access to values as there is no
-//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
+//! A thread-local key owns the value it contains and will destroy the value when the
+//! thread exits. It is created with the [`thread_local!`] macro and can contain any
+//! value that is `'static` (no borrowed pointers). It provides an accessor function,
+//! [`with`], that yields a shared reference to the value to the specified
+//! closure. Thread-local keys allow only shared access to values, as there would be no
+//! way to guarantee uniqueness if mutable borrows were allowed. Most values
 //! will want to make use of some form of **interior mutability** through the
-//! `Cell` or `RefCell` types.
+//! [`Cell`] or [`RefCell`] types.
+//!
+//! [`Cell`]: ../cell/struct.Cell.html
+//! [`RefCell`]: ../cell/struct.RefCell.html
+//! [`thread_local!`]: ../macro.thread_local!.html
+//! [`with`]: struct.LocalKey.html#method.with
 
 #![stable(feature = "rust1", since = "1.0.0")]
 

From 1aa777b51f03593eb557d4e550830f8406ee37c3 Mon Sep 17 00:00:00 2001
From: Cobrand 
Date: Sun, 4 Sep 2016 21:14:41 +0200
Subject: [PATCH 530/768] Updated E0559 to new format

Refactored a method that printed one suggested field name,
into a method that returns an `Option` of a suggestion

Updated test cases accordingly
---
 src/librustc_typeck/check/mod.rs              | 28 +++++++++++--------
 src/test/compile-fail/E0559.rs                |  4 ++-
 .../struct-fields-hints-no-dupe.rs            |  5 ++--
 src/test/compile-fail/struct-fields-hints.rs  |  5 ++--
 .../compile-fail/suggest-private-fields.rs    | 20 +++++++------
 .../compile-fail/union/union-suggest-field.rs |  5 ++--
 6 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f4fea5542b3de..8518689fcb40b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -118,7 +118,6 @@ use syntax::parse::token::{self, InternedString, keywords};
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{self, Span};
-use errors::DiagnosticBuilder;
 
 use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir::{self, PatKind};
@@ -2996,7 +2995,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }, expr_t);
             match expr_t.sty {
                 ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
-                    Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
+                    if let Some(suggested_field_name) =
+                        Self::suggest_field_name(def.struct_variant(), field, vec![]) {
+                        err.span_help(field.span,
+                                      &format!("did you mean `{}`?", suggested_field_name));
+                    };
                 }
                 ty::TyRawPtr(..) => {
                     err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
@@ -3009,11 +3012,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    // displays hints about the closest matches in field names
-    fn suggest_field_names(err: &mut DiagnosticBuilder,
-                           variant: ty::VariantDef<'tcx>,
-                           field: &Spanned,
-                           skip : Vec) {
+    // Return an hint about the closest match in field names
+    fn suggest_field_name(variant: ty::VariantDef<'tcx>,
+                          field: &Spanned,
+                          skip : Vec)
+                          -> Option {
         let name = field.node.as_str();
         let names = variant.fields.iter().filter_map(|field| {
             // ignore already set fields and private fields from non-local crates
@@ -3026,10 +3029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         });
 
         // only find fits with at least one matching letter
-        if let Some(name) = find_best_match_for_name(names, &name, Some(name.len())) {
-            err.span_help(field.span,
-                          &format!("did you mean `{}`?", name));
-        }
+        find_best_match_for_name(names, &name, Some(name.len()))
     }
 
     // Check tuple index expressions
@@ -3125,7 +3125,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ty);
         // prevent all specified fields from being suggested
         let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
-        Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
+        if let Some(field_name) = Self::suggest_field_name(variant,
+                                                           &field.name,
+                                                           skip_fields.collect()) {
+            err.span_label(field.name.span,&format!("did you mean `{}`?",field_name));
+        };
         err.emit();
     }
 
diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs
index 80eeb203a850e..aeeeae4222813 100644
--- a/src/test/compile-fail/E0559.rs
+++ b/src/test/compile-fail/E0559.rs
@@ -13,5 +13,7 @@ enum Field {
 }
 
 fn main() {
-    let s = Field::Fool { joke: 0 }; //~ ERROR E0559
+    let s = Field::Fool { joke: 0 };
+    //~^ ERROR E0559
+    //~| NOTE did you mean `x`?
 }
diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
index 5f1f8ca856f9c..f25f01af33fd1 100644
--- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs
+++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
@@ -17,8 +17,9 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR struct `A` has no field named `bar`
-        //~^ HELP did you mean `barr`?
+        bar : 42,
+        //~^ ERROR struct `A` has no field named `bar`
+        //~| NOTE did you mean `barr`?
         car : 9,
     };
 }
diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs
index 4ba1fd2f7bb33..62ec6e6b0d249 100644
--- a/src/test/compile-fail/struct-fields-hints.rs
+++ b/src/test/compile-fail/struct-fields-hints.rs
@@ -17,7 +17,8 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR struct `A` has no field named `bar`
-        //~^ HELP did you mean `car`?
+        bar : 42,
+        //~^ ERROR struct `A` has no field named `bar`
+        //~| NOTE did you mean `car`?
     };
 }
diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs
index 41bd00a518c5c..906bfc78498e4 100644
--- a/src/test/compile-fail/suggest-private-fields.rs
+++ b/src/test/compile-fail/suggest-private-fields.rs
@@ -22,16 +22,20 @@ struct A {
 fn main () {
     // external crate struct
     let k = B {
-        aa: 20, //~ ERROR struct `xc::B` has no field named `aa`
-        //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR struct `xc::B` has no field named `bb`
-        //~^ HELP did you mean `a`?
+        aa: 20,
+        //~^ ERROR struct `xc::B` has no field named `aa`
+        //~| NOTE did you mean `a`?
+        bb: 20,
+        //~^ ERROR struct `xc::B` has no field named `bb`
+        //~| NOTE did you mean `a`?
     };
     // local crate struct
     let l = A {
-        aa: 20, //~ ERROR struct `A` has no field named `aa`
-        //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR struct `A` has no field named `bb`
-        //~^ HELP did you mean `b`?
+        aa: 20,
+        //~^ ERROR struct `A` has no field named `aa`
+        //~| NOTE did you mean `a`?
+        bb: 20,
+        //~^ ERROR struct `A` has no field named `bb`
+        //~| NOTE did you mean `b`?
     };
 }
diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs
index b05e9b6e27334..92811b6b5be11 100644
--- a/src/test/compile-fail/union/union-suggest-field.rs
+++ b/src/test/compile-fail/union/union-suggest-field.rs
@@ -19,8 +19,9 @@ impl U {
 }
 
 fn main() {
-    let u = U { principle: 0 }; //~ ERROR union `U` has no field named `principle`
-                                //~^ HELP did you mean `principal`?
+    let u = U { principle: 0 };
+    //~^ ERROR union `U` has no field named `principle`
+    //~| NOTE did you mean `principal`?
     let w = u.principial; //~ ERROR attempted access of field `principial` on type `U`
                           //~^ HELP did you mean `principal`?
 

From b9a8c1a06300c4d042b5455d83cacd689bad6283 Mon Sep 17 00:00:00 2001
From: Matt Ickstadt 
Date: Thu, 1 Sep 2016 13:52:33 -0500
Subject: [PATCH 531/768] Fix incorrect LLVM Linkage enum

The `Linkage` enum in librustc_llvm got out of sync with the version in LLVM and it caused two variants of the #[linkage=""] attribute to break.

This adds the functions `LLVMRustGetLinkage` and `LLVMRustSetLinkage` which convert between the Rust Linkage enum and the LLVM one, which should stop this from breaking every time LLVM changes it.

Fixes #33992
---
 src/librustc_llvm/ffi.rs            | 28 ++++------
 src/librustc_trans/base.rs          | 64 +++++++++++------------
 src/librustc_trans/callee.rs        |  2 +-
 src/librustc_trans/closure.rs       |  4 +-
 src/librustc_trans/common.rs        |  2 +-
 src/librustc_trans/consts.rs        |  8 +--
 src/librustc_trans/debuginfo/gdb.rs |  2 +-
 src/librustc_trans/declare.rs       |  2 +-
 src/librustc_trans/trans_item.rs    | 14 ++---
 src/rustllvm/RustWrapper.cpp        | 80 +++++++++++++++++++++++++++++
 src/test/run-pass/issue-33992.rs    | 40 +++++++++++++++
 11 files changed, 180 insertions(+), 66 deletions(-)
 create mode 100644 src/test/run-pass/issue-33992.rs

diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 92fe568a72c57..50c68d5e75eef 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -47,12 +47,7 @@ pub enum CallConv {
     X86_VectorCall = 80
 }
 
-/// LLVMLinkage
-///
-/// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage,
-/// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage.
-/// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either;
-/// they've been removed in upstream LLVM commit r203866.
+/// LLVMRustLinkage
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[repr(C)]
 pub enum Linkage {
@@ -60,13 +55,13 @@ pub enum Linkage {
     AvailableExternallyLinkage = 1,
     LinkOnceAnyLinkage = 2,
     LinkOnceODRLinkage = 3,
-    WeakAnyLinkage = 5,
-    WeakODRLinkage = 6,
-    AppendingLinkage = 7,
-    InternalLinkage = 8,
-    PrivateLinkage = 9,
-    ExternalWeakLinkage = 12,
-    CommonLinkage = 14,
+    WeakAnyLinkage = 4,
+    WeakODRLinkage = 5,
+    AppendingLinkage = 6,
+    InternalLinkage = 7,
+    PrivateLinkage = 8,
+    ExternalWeakLinkage = 9,
+    CommonLinkage = 10,
 }
 
 /// LLVMDiagnosticSeverity
@@ -253,8 +248,7 @@ pub enum FileType {
     ObjectFile,
 }
 
-/// Enum pinned in LLVMContext, used in
-/// LLVMSetMetadata so ABI-stable.
+/// LLVMMetadataType
 #[derive(Copy, Clone)]
 #[repr(C)]
 pub enum MetadataType {
@@ -821,8 +815,8 @@ extern {
     /* Operations on global variables, functions, and aliases (globals) */
     pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef;
     pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool;
-    pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint;
-    pub fn LLVMSetLinkage(Global: ValueRef, Link: Linkage);
+    pub fn LLVMRustGetLinkage(Global: ValueRef) -> Linkage;
+    pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage);
     pub fn LLVMGetSection(Global: ValueRef) -> *const c_char;
     pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char);
     pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint;
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 99126095ede3e..53d55f4a903d7 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1198,17 +1198,17 @@ pub fn llvm_linkage_by_name(name: &str) -> Option {
     // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
     // and don't have to be, LLVM treats them as no-ops.
     match name {
-        "appending" => Some(llvm::AppendingLinkage),
-        "available_externally" => Some(llvm::AvailableExternallyLinkage),
-        "common" => Some(llvm::CommonLinkage),
-        "extern_weak" => Some(llvm::ExternalWeakLinkage),
-        "external" => Some(llvm::ExternalLinkage),
-        "internal" => Some(llvm::InternalLinkage),
-        "linkonce" => Some(llvm::LinkOnceAnyLinkage),
-        "linkonce_odr" => Some(llvm::LinkOnceODRLinkage),
-        "private" => Some(llvm::PrivateLinkage),
-        "weak" => Some(llvm::WeakAnyLinkage),
-        "weak_odr" => Some(llvm::WeakODRLinkage),
+        "appending" => Some(llvm::Linkage::AppendingLinkage),
+        "available_externally" => Some(llvm::Linkage::AvailableExternallyLinkage),
+        "common" => Some(llvm::Linkage::CommonLinkage),
+        "extern_weak" => Some(llvm::Linkage::ExternalWeakLinkage),
+        "external" => Some(llvm::Linkage::ExternalLinkage),
+        "internal" => Some(llvm::Linkage::InternalLinkage),
+        "linkonce" => Some(llvm::Linkage::LinkOnceAnyLinkage),
+        "linkonce_odr" => Some(llvm::Linkage::LinkOnceODRLinkage),
+        "private" => Some(llvm::Linkage::PrivateLinkage),
+        "weak" => Some(llvm::Linkage::WeakAnyLinkage),
+        "weak_odr" => Some(llvm::Linkage::WeakODRLinkage),
         _ => None,
     }
 }
@@ -1401,10 +1401,10 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
         // are referenced via a declaration in some other codegen unit.
         for ccx in ccxs.iter_need_trans() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
-                let linkage = llvm::LLVMGetLinkage(val);
+                let linkage = llvm::LLVMRustGetLinkage(val);
                 // We only care about external declarations (not definitions)
                 // and available_externally definitions.
-                let is_available_externally = linkage == llvm::AvailableExternallyLinkage as c_uint;
+                let is_available_externally = linkage == llvm::Linkage::AvailableExternallyLinkage;
                 let is_decl = llvm::LLVMIsDeclaration(val) != 0;
 
                 if is_decl || is_available_externally {
@@ -1446,11 +1446,11 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
         // then give it internal linkage.
         for ccx in ccxs.iter_need_trans() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
-                let linkage = llvm::LLVMGetLinkage(val);
+                let linkage = llvm::LLVMRustGetLinkage(val);
 
-                let is_externally_visible = (linkage == llvm::ExternalLinkage as c_uint) ||
-                                            (linkage == llvm::LinkOnceODRLinkage as c_uint) ||
-                                            (linkage == llvm::WeakODRLinkage as c_uint);
+                let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) ||
+                                            (linkage == llvm::Linkage::LinkOnceODRLinkage) ||
+                                            (linkage == llvm::Linkage::WeakODRLinkage);
                 let is_definition = llvm::LLVMIsDeclaration(val) == 0;
 
                 // If this is a definition (as opposed to just a declaration)
@@ -1465,7 +1465,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
                     let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow);
 
                     if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
-                        llvm::LLVMSetLinkage(val, llvm::InternalLinkage);
+                        llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage);
                         llvm::LLVMSetDLLStorageClass(val,
                                                      llvm::DLLStorageClass::Default);
                         llvm::UnsetComdat(val);
@@ -1495,8 +1495,8 @@ fn create_imps(cx: &CrateContextList) {
         for ccx in cx.iter_need_trans() {
             let exported: Vec<_> = iter_globals(ccx.llmod())
                                        .filter(|&val| {
-                                           llvm::LLVMGetLinkage(val) ==
-                                           llvm::ExternalLinkage as c_uint &&
+                                           llvm::LLVMRustGetLinkage(val) ==
+                                           llvm::Linkage::ExternalLinkage &&
                                            llvm::LLVMIsDeclaration(val) == 0
                                        })
                                        .collect();
@@ -1512,7 +1512,7 @@ fn create_imps(cx: &CrateContextList) {
                                               imp_name.as_ptr() as *const _);
                 let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref());
                 llvm::LLVMSetInitializer(imp, init);
-                llvm::LLVMSetLinkage(imp, llvm::ExternalLinkage);
+                llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
             }
         }
     }
@@ -1937,17 +1937,17 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
                     output.push_str(&cgu_name[..]);
 
                     let linkage_abbrev = match linkage {
-                        llvm::ExternalLinkage => "External",
-                        llvm::AvailableExternallyLinkage => "Available",
-                        llvm::LinkOnceAnyLinkage => "OnceAny",
-                        llvm::LinkOnceODRLinkage => "OnceODR",
-                        llvm::WeakAnyLinkage => "WeakAny",
-                        llvm::WeakODRLinkage => "WeakODR",
-                        llvm::AppendingLinkage => "Appending",
-                        llvm::InternalLinkage => "Internal",
-                        llvm::PrivateLinkage => "Private",
-                        llvm::ExternalWeakLinkage => "ExternalWeak",
-                        llvm::CommonLinkage => "Common",
+                        llvm::Linkage::ExternalLinkage => "External",
+                        llvm::Linkage::AvailableExternallyLinkage => "Available",
+                        llvm::Linkage::LinkOnceAnyLinkage => "OnceAny",
+                        llvm::Linkage::LinkOnceODRLinkage => "OnceODR",
+                        llvm::Linkage::WeakAnyLinkage => "WeakAny",
+                        llvm::Linkage::WeakODRLinkage => "WeakODR",
+                        llvm::Linkage::AppendingLinkage => "Appending",
+                        llvm::Linkage::InternalLinkage => "Internal",
+                        llvm::Linkage::PrivateLinkage => "Private",
+                        llvm::Linkage::ExternalWeakLinkage => "ExternalWeak",
+                        llvm::Linkage::CommonLinkage => "Common",
                     };
 
                     output.push_str("[");
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 33cacbe194bb0..51e79d1e4b33f 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -472,7 +472,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
             attributes::unwind(llfn, true);
             unsafe {
-                llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage);
+                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
             }
         }
 
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 842a8fddb83e1..83882c27e8e7b 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -110,10 +110,10 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
         unsafe {
             if ccx.sess().target.target.options.allows_weak_linkage {
-                llvm::LLVMSetLinkage(llfn, llvm::WeakODRLinkage);
+                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage);
                 llvm::SetUniqueComdat(ccx.llmod(), llfn);
             } else {
-                llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage);
+                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage);
             }
         }
 
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 6ae6f8aead77d..bd98eee8869b1 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -817,7 +817,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
         });
         llvm::LLVMSetInitializer(g, sc);
         llvm::LLVMSetGlobalConstant(g, True);
-        llvm::LLVMSetLinkage(g, llvm::InternalLinkage);
+        llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
 
         cx.const_cstr_cache().borrow_mut().insert(s, g);
         g
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 2b6e2a23261bd..15f7132e52d2f 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -11,7 +11,7 @@
 
 use llvm;
 use llvm::{SetUnnamedAddr};
-use llvm::{InternalLinkage, ValueRef, True};
+use llvm::{ValueRef, True};
 use rustc_const_eval::ConstEvalErr;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
@@ -53,7 +53,7 @@ pub fn addr_of_mut(ccx: &CrateContext,
         });
         llvm::LLVMSetInitializer(gv, cv);
         llvm::LLVMSetAlignment(gv, align);
-        llvm::LLVMSetLinkage(gv, InternalLinkage);
+        llvm::LLVMRustSetLinkage(gv, llvm::Linkage::InternalLinkage);
         SetUnnamedAddr(gv, true);
         gv
     }
@@ -142,7 +142,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                     unsafe {
                         // Declare a symbol `foo` with the desired linkage.
                         let g1 = declare::declare_global(ccx, &sym, llty2);
-                        llvm::LLVMSetLinkage(g1, linkage);
+                        llvm::LLVMRustSetLinkage(g1, linkage);
 
                         // Declare an internal global `extern_with_linkage_foo` which
                         // is initialized with the address of `foo`.  If `foo` is
@@ -156,7 +156,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                             ccx.sess().span_fatal(span,
                                 &format!("symbol `{}` is already defined", &sym))
                         });
-                        llvm::LLVMSetLinkage(g2, llvm::InternalLinkage);
+                        llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
                         llvm::LLVMSetInitializer(g2, g1);
                         g2
                     }
diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_trans/debuginfo/gdb.rs
index 0a8d490dcd2dd..8f937d3fe25cb 100644
--- a/src/librustc_trans/debuginfo/gdb.rs
+++ b/src/librustc_trans/debuginfo/gdb.rs
@@ -77,7 +77,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
             llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddr(section_var, llvm::True);
-            llvm::LLVMSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+            llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
             // This should make sure that the whole section is not larger than
             // the string it contains. Otherwise we get a warning from GDB.
             llvm::LLVMSetAlignment(section_var, 1);
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 4d9ee187ac50c..0c1156a98743e 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -164,7 +164,7 @@ pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     name: &str,
                                     fn_type: ty::Ty<'tcx>) -> ValueRef {
     let llfn = define_fn(ccx, name, fn_type);
-    unsafe { llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage) };
+    unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
     llfn
 }
 
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index deef0b09a17b0..9a55877a13453 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -160,7 +160,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
                 &format!("symbol `{}` is already defined", symbol_name))
         });
 
-        unsafe { llvm::LLVMSetLinkage(g, linkage) };
+        unsafe { llvm::LLVMRustSetLinkage(g, linkage) };
 
         let instance = Instance::mono(ccx.shared(), def_id);
         ccx.instances().borrow_mut().insert(instance, g);
@@ -180,10 +180,10 @@ impl<'a, 'tcx> TransItem<'tcx> {
 
         let attrs = ccx.tcx().get_attrs(instance.def);
         let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
-        unsafe { llvm::LLVMSetLinkage(lldecl, linkage) };
+        unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) };
         base::set_link_section(ccx, lldecl, &attrs);
-        if linkage == llvm::LinkOnceODRLinkage ||
-            linkage == llvm::WeakODRLinkage {
+        if linkage == llvm::Linkage::LinkOnceODRLinkage ||
+            linkage == llvm::Linkage::WeakODRLinkage {
             llvm::SetUniqueComdat(ccx.llmod(), lldecl);
         }
 
@@ -214,9 +214,9 @@ impl<'a, 'tcx> TransItem<'tcx> {
 
         assert!(declare::get_defined_value(ccx, symbol_name).is_none());
         let llfn = declare::declare_cfn(ccx, symbol_name, llfnty);
-        unsafe { llvm::LLVMSetLinkage(llfn, linkage) };
-        if linkage == llvm::LinkOnceODRLinkage ||
-           linkage == llvm::WeakODRLinkage {
+        unsafe { llvm::LLVMRustSetLinkage(llfn, linkage) };
+        if linkage == llvm::Linkage::LinkOnceODRLinkage ||
+           linkage == llvm::Linkage::WeakODRLinkage {
             llvm::SetUniqueComdat(ccx.llmod(), llfn);
         }
         attributes::set_frame_pointer_elimination(ccx, llfn);
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 82fb2b0918f79..124eb1eba4f7b 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -1232,3 +1232,83 @@ extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) {
     GlobalObject *GV = unwrap(V);
     GV->setComdat(nullptr);
 }
+
+enum class LLVMRustLinkage {
+    ExternalLinkage = 0,
+    AvailableExternallyLinkage = 1,
+    LinkOnceAnyLinkage = 2,
+    LinkOnceODRLinkage = 3,
+    WeakAnyLinkage = 4,
+    WeakODRLinkage = 5,
+    AppendingLinkage = 6,
+    InternalLinkage = 7,
+    PrivateLinkage = 8,
+    ExternalWeakLinkage = 9,
+    CommonLinkage = 10,
+};
+
+static LLVMRustLinkage to_rust(LLVMLinkage linkage) {
+    switch (linkage) {
+        case LLVMExternalLinkage:
+            return LLVMRustLinkage::ExternalLinkage;
+        case LLVMAvailableExternallyLinkage:
+            return LLVMRustLinkage::AvailableExternallyLinkage;
+        case LLVMLinkOnceAnyLinkage:
+            return LLVMRustLinkage::LinkOnceAnyLinkage;
+        case LLVMLinkOnceODRLinkage:
+            return LLVMRustLinkage::LinkOnceODRLinkage;
+        case LLVMWeakAnyLinkage:
+            return LLVMRustLinkage::WeakAnyLinkage;
+        case LLVMWeakODRLinkage:
+            return LLVMRustLinkage::WeakODRLinkage;
+        case LLVMAppendingLinkage:
+            return LLVMRustLinkage::AppendingLinkage;
+        case LLVMInternalLinkage:
+            return LLVMRustLinkage::InternalLinkage;
+        case LLVMPrivateLinkage:
+            return LLVMRustLinkage::PrivateLinkage;
+        case LLVMExternalWeakLinkage:
+            return LLVMRustLinkage::ExternalWeakLinkage;
+        case LLVMCommonLinkage:
+            return LLVMRustLinkage::CommonLinkage;
+        default:
+            llvm_unreachable("Invalid LLVMRustLinkage value!");
+    }
+}
+
+static LLVMLinkage from_rust(LLVMRustLinkage linkage) {
+    switch (linkage) {
+        case LLVMRustLinkage::ExternalLinkage:
+            return LLVMExternalLinkage;
+        case LLVMRustLinkage::AvailableExternallyLinkage:
+            return LLVMAvailableExternallyLinkage;
+        case LLVMRustLinkage::LinkOnceAnyLinkage:
+            return LLVMLinkOnceAnyLinkage;
+        case LLVMRustLinkage::LinkOnceODRLinkage:
+            return LLVMLinkOnceODRLinkage;
+        case LLVMRustLinkage::WeakAnyLinkage:
+            return LLVMWeakAnyLinkage;
+        case LLVMRustLinkage::WeakODRLinkage:
+            return LLVMWeakODRLinkage;
+        case LLVMRustLinkage::AppendingLinkage:
+            return LLVMAppendingLinkage;
+        case LLVMRustLinkage::InternalLinkage:
+            return LLVMInternalLinkage;
+        case LLVMRustLinkage::PrivateLinkage:
+            return LLVMPrivateLinkage;
+        case LLVMRustLinkage::ExternalWeakLinkage:
+            return LLVMExternalWeakLinkage;
+        case LLVMRustLinkage::CommonLinkage:
+            return LLVMCommonLinkage;
+        default:
+            llvm_unreachable("Invalid LLVMRustLinkage value!");
+    } 
+}
+
+extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
+    return to_rust(LLVMGetLinkage(V));
+}
+
+extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) {
+    LLVMSetLinkage(V, from_rust(RustLinkage));
+}
diff --git a/src/test/run-pass/issue-33992.rs b/src/test/run-pass/issue-33992.rs
new file mode 100644
index 0000000000000..5729469f69754
--- /dev/null
+++ b/src/test/run-pass/issue-33992.rs
@@ -0,0 +1,40 @@
+// 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.
+
+// ignore-windows
+// ignore-macos
+
+#![feature(linkage)]
+
+#[linkage = "common"]
+pub static mut TEST1: u32 = 0u32;
+
+#[linkage = "external"]
+pub static TEST2: bool = true;
+
+#[linkage = "internal"]
+pub static TEST3: bool = true;
+
+#[linkage = "linkonce"]
+pub static TEST4: bool = true;
+
+#[linkage = "linkonce_odr"]
+pub static TEST5: bool = true;
+
+#[linkage = "private"]
+pub static TEST6: bool = true;
+
+#[linkage = "weak"]
+pub static TEST7: bool = true;
+
+#[linkage = "weak_odr"]
+pub static TEST8: bool = true;
+
+fn main() {}
\ No newline at end of file

From 3be6d1f954f2c8d36d40cea56494386e4259819c Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 532/768] Make `private_in_public` compatibility lint
 warn-by-default again

---
 src/librustc/lint/builtin.rs                                | 2 +-
 src/librustc_privacy/diagnostics.rs                         | 4 ++++
 src/test/compile-fail/issue-28514.rs                        | 2 ++
 src/test/compile-fail/issue-30079.rs                        | 1 +
 src/test/compile-fail/private-in-public-warn.rs             | 4 ++--
 src/test/compile-fail/private-variant-and-crate-reexport.rs | 1 +
 6 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index ed94e5fe377c4..173f8d496990a 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -114,7 +114,7 @@ declare_lint! {
 
 declare_lint! {
     pub PRIVATE_IN_PUBLIC,
-    Deny,
+    Warn,
     "detect private items in public interfaces not caught by the old implementation"
 }
 
diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs
index 891b6adea7893..66afe5835bf6f 100644
--- a/src/librustc_privacy/diagnostics.rs
+++ b/src/librustc_privacy/diagnostics.rs
@@ -17,6 +17,8 @@ A private trait was used on a public type parameter bound. Erroneous code
 examples:
 
 ```compile_fail,E0445
+#![deny(private_in_public)]
+
 trait Foo {
     fn dummy(&self) { }
 }
@@ -45,6 +47,8 @@ E0446: r##"
 A private type was used in a public type signature. Erroneous code example:
 
 ```compile_fail,E0446
+#![deny(private_in_public)]
+
 mod Foo {
     struct Bar(u32);
 
diff --git a/src/test/compile-fail/issue-28514.rs b/src/test/compile-fail/issue-28514.rs
index 6ee375503c2af..fb25166531dcb 100644
--- a/src/test/compile-fail/issue-28514.rs
+++ b/src/test/compile-fail/issue-28514.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(private_in_public)]
+
 pub use inner::C;
 
 mod inner {
diff --git a/src/test/compile-fail/issue-30079.rs b/src/test/compile-fail/issue-30079.rs
index 55c58ed021b27..6a54e53f14638 100644
--- a/src/test/compile-fail/issue-30079.rs
+++ b/src/test/compile-fail/issue-30079.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(private_in_public)]
 #![allow(unused)]
 
 struct SemiPriv;
diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs
index 6d6af77be92b0..455de37aee96f 100644
--- a/src/test/compile-fail/private-in-public-warn.rs
+++ b/src/test/compile-fail/private-in-public-warn.rs
@@ -13,8 +13,8 @@
 
 #![feature(associated_consts)]
 #![feature(associated_type_defaults)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
+#![deny(private_in_public)]
+#![allow(unused)]
 #![allow(improper_ctypes)]
 
 mod types {
diff --git a/src/test/compile-fail/private-variant-and-crate-reexport.rs b/src/test/compile-fail/private-variant-and-crate-reexport.rs
index ce029e7eff7fc..dce533e73feea 100644
--- a/src/test/compile-fail/private-variant-and-crate-reexport.rs
+++ b/src/test/compile-fail/private-variant-and-crate-reexport.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(private_in_public)]
 #![allow(dead_code)]
 
 extern crate core;

From e4784fc3137b9bdd3a45483f490b1f362506c794 Mon Sep 17 00:00:00 2001
From: Andrew Paseltiner 
Date: Sun, 4 Sep 2016 22:57:27 -0400
Subject: [PATCH 533/768] Remove mention of `unsafe_no_drop_flag` from
 Reference and Nomicon

---
 src/doc/nomicon/safe-unsafe-meaning.md |  4 ----
 src/doc/reference.md                   | 10 ----------
 2 files changed, 14 deletions(-)

diff --git a/src/doc/nomicon/safe-unsafe-meaning.md b/src/doc/nomicon/safe-unsafe-meaning.md
index c4f939a608b79..adede0ec91117 100644
--- a/src/doc/nomicon/safe-unsafe-meaning.md
+++ b/src/doc/nomicon/safe-unsafe-meaning.md
@@ -26,10 +26,6 @@ can therefore be trusted. You can use `unsafe` on a trait implementation
 to declare that the implementation of that trait has adhered to whatever
 contracts the trait's documentation requires.
 
-There is also the `#[unsafe_no_drop_flag]` attribute, which exists for
-historic reasons and is being phased out. See the section on [drop flags]
-for details.
-
 The standard library has a number of unsafe functions, including:
 
 * `slice::get_unchecked`, which performs unchecked indexing, allowing
diff --git a/src/doc/reference.md b/src/doc/reference.md
index cc5d9c3685aba..f29cdf6b08035 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2059,10 +2059,6 @@ macro scope.
   outside of its dynamic extent), and thus this attribute has the word
   "unsafe" in its name. To use this, the
   `unsafe_destructor_blind_to_params` feature gate must be enabled.
-- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
-  destructors from being run twice. Destructors might be run multiple times on
-  the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
-  gate must be enabled.
 - `doc` - Doc comments such as `/// foo` are equivalent to `#[doc = "foo"]`.
 - `rustc_on_unimplemented` - Write a custom note to be shown along with the error
    when the trait is found to be unimplemented on a type.
@@ -2458,12 +2454,6 @@ The currently implemented features of the reference compiler are:
 * `unboxed_closures` - Rust's new closure design, which is currently a work in
                        progress feature with many known bugs.
 
-* `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute,
-                          which removes hidden flag added to a type that
-                          implements the `Drop` trait. The design for the
-                          `Drop` flag is subject to change, and this feature
-                          may be removed in the future.
-
 * `unmarked_api` - Allows use of items within a `#![staged_api]` crate
                    which have not been marked with a stability marker.
                    Such items should not be allowed by the compiler to exist,

From 0ddf060b6d347f89afb584501c86a4fa96ec7acc Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Tue, 9 Aug 2016 20:57:41 +0800
Subject: [PATCH 534/768] Make write_ty and friends return adjusted type

---
 src/librustc_typeck/check/_match.rs  |   4 +-
 src/librustc_typeck/check/callee.rs  |  23 +--
 src/librustc_typeck/check/closure.rs |   8 +-
 src/librustc_typeck/check/mod.rs     | 241 ++++++++++++++-------------
 src/librustc_typeck/check/op.rs      |  23 +--
 5 files changed, 153 insertions(+), 146 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 12fce4b928e08..1f0faab8f2c4a 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        discrim: &'gcx hir::Expr,
                        arms: &'gcx [hir::Arm],
                        expected: Expectation<'tcx>,
-                       match_src: hir::MatchSource) {
+                       match_src: hir::MatchSource) -> Ty<'tcx> {
         let tcx = self.tcx;
 
         // Not entirely obvious: if matches may create ref bindings, we
@@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
         }
 
-        self.write_ty(expr.id, result_ty);
+        self.write_ty(expr.id, result_ty)
     }
 }
 
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 49db56d2dabd9..4f673606de52f 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       call_expr: &'gcx hir::Expr,
                       callee_expr: &'gcx hir::Expr,
                       arg_exprs: &'gcx [P],
-                      expected: Expectation<'tcx>)
+                      expected: Expectation<'tcx>) -> Ty<'tcx>
     {
         self.check_expr(callee_expr);
         let original_callee_ty = self.expr_ty(callee_expr);
@@ -60,20 +60,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match result {
             None => {
                 // this will report an error since original_callee_ty is not a fn
-                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected);
+                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
             }
 
             Some(CallStep::Builtin) => {
-                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected);
+                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected)
             }
 
             Some(CallStep::DeferredClosure(fn_sig)) => {
-                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig);
+                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig)
             }
 
             Some(CallStep::Overloaded(method_callee)) => {
                 self.confirm_overloaded_call(call_expr, callee_expr,
-                                             arg_exprs, expected, method_callee);
+                                             arg_exprs, expected, method_callee)
             }
         }
     }
@@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             call_expr: &hir::Expr,
                             callee_ty: Ty<'tcx>,
                             arg_exprs: &'gcx [P],
-                            expected: Expectation<'tcx>)
+                            expected: Expectation<'tcx>) -> Ty<'tcx>
     {
         let error_fn_sig;
 
@@ -245,14 +245,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::DontTupleArguments);
 
-        self.write_call(call_expr, fn_sig.output);
+        self.write_ty(call_expr.id, fn_sig.output)
     }
 
     fn confirm_deferred_closure_call(&self,
                                      call_expr: &hir::Expr,
                                      arg_exprs: &'gcx [P],
                                      expected: Expectation<'tcx>,
-                                     fn_sig: ty::FnSig<'tcx>)
+                                     fn_sig: ty::FnSig<'tcx>) -> Ty<'tcx>
     {
         // `fn_sig` is the *signature* of the cosure being called. We
         // don't know the full details yet (`Fn` vs `FnMut` etc), but we
@@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::TupleArguments);
 
-        self.write_call(call_expr, fn_sig.output);
+        self.write_ty(call_expr.id, fn_sig.output)
     }
 
     fn confirm_overloaded_call(&self,
@@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                callee_expr: &'gcx hir::Expr,
                                arg_exprs: &'gcx [P],
                                expected: Expectation<'tcx>,
-                               method_callee: ty::MethodCallee<'tcx>)
+                               method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx>
     {
         let output_type =
             self.check_method_argument_types(call_expr.span,
@@ -289,9 +289,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                              arg_exprs,
                                              TupleArgumentsFlag::TupleArguments,
                                              expected);
-        self.write_call(call_expr, output_type);
+        let ty = self.write_ty(call_expr.id, output_type);
 
         self.write_overloaded_call_method_map(call_expr, method_callee);
+        ty
     }
 
     fn write_overloaded_call_method_map(&self,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 8980cb9076027..1f4201aa39cdd 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -24,7 +24,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
                               body: &'gcx hir::Block,
-                              expected: Expectation<'tcx>) {
+                              expected: Expectation<'tcx>) -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
                expr,
                expected);
@@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      opt_kind: Option,
                      decl: &'gcx hir::FnDecl,
                      body: &'gcx hir::Block,
-                     expected_sig: Option>) {
+                     expected_sig: Option>) -> Ty<'tcx> {
         let expr_def_id = self.tcx.map.local_def_id(expr.id);
 
         debug!("check_closure opt_kind={:?} expected_sig={:?}",
@@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.parameter_environment.free_substs,
             upvar_tys);
 
-        self.write_ty(expr.id, closure_type);
+        let ty = self.write_ty(expr.id, closure_type);
 
         let fn_sig = self.tcx.liberate_late_bound_regions(
             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
@@ -93,6 +93,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
             None => { }
         }
+
+        ty
     }
 
     fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0aa523e9d5e47..5c528cc46a73c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1530,7 +1530,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     #[inline]
-    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
+    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) -> Ty<'tcx> {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
@@ -1538,10 +1538,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Add adjustments to !-expressions
         if ty.is_never() {
             if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
-                let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var());
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
                 self.write_adjustment(node_id, adj);
+                return adj_ty;
             }
         }
+        ty
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1715,16 +1718,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty_substituted
     }
 
-    pub fn write_nil(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.mk_nil());
+    pub fn write_nil(&self, node_id: ast::NodeId) -> Ty<'tcx> {
+        self.write_ty(node_id, self.tcx.mk_nil())
     }
 
-    pub fn write_never(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.types.never);
+    pub fn write_never(&self, node_id: ast::NodeId) -> Ty<'tcx> {
+        self.write_ty(node_id, self.tcx.types.never)
     }
 
-    pub fn write_error(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.types.err);
+    pub fn write_error(&self, node_id: ast::NodeId) -> Ty<'tcx> {
+        self.write_ty(node_id, self.tcx.types.err)
     }
 
     pub fn require_type_meets(&self,
@@ -2666,12 +2669,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         (0..len).map(|_| self.tcx.types.err).collect()
     }
 
-    fn write_call(&self,
-                  call_expr: &hir::Expr,
-                  output: Ty<'tcx>) {
-        self.write_ty(call_expr.id, output);
-    }
-
     // AST fragment checking
     fn check_lit(&self,
                  lit: &ast::Lit,
@@ -2727,35 +2724,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn check_expr_has_type(&self,
                                expr: &'gcx hir::Expr,
-                               expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
+                               expected: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.check_expr_with_hint(expr, expected);
         self.demand_suptype(expr.span, expected, self.expr_ty(expr));
+        ty
     }
 
     fn check_expr_coercable_to_type(&self,
                                     expr: &'gcx hir::Expr,
-                                    expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
+                                    expected: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.check_expr_with_hint(expr, expected);
         self.demand_coerce(expr, expected);
+        ty
     }
 
     fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
-                            expected: Ty<'tcx>) {
+                            expected: Ty<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
     fn check_expr_with_expectation(&self,
                                    expr: &'gcx hir::Expr,
-                                   expected: Expectation<'tcx>) {
+                                   expected: Expectation<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
     }
 
-    fn check_expr(&self, expr: &'gcx hir::Expr)  {
+    fn check_expr(&self, expr: &'gcx hir::Expr) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, NoExpectation)
     }
 
     fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr,
-                                   lvalue_pref: LvaluePreference)  {
+                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
     }
 
@@ -2820,7 +2819,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          args: &'gcx [P],
                          tps: &[P],
                          expected: Expectation<'tcx>,
-                         lvalue_pref: LvaluePreference) {
+                         lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let rcvr = &args[0];
         self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
 
@@ -2856,7 +2855,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                       DontTupleArguments,
                                                       expected);
 
-        self.write_call(expr, ret_ty);
+        self.write_ty(expr.id, ret_ty)
     }
 
     // A generic function for checking the then and else in an if
@@ -2867,7 +2866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        opt_else_expr: Option<&'gcx hir::Expr>,
                        id: ast::NodeId,
                        sp: Span,
-                       expected: Expectation<'tcx>) {
+                       expected: Expectation<'tcx>) -> Ty<'tcx> {
         self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
@@ -2932,7 +2931,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         };
 
-        self.write_ty(id, if_ty);
+        self.write_ty(id, if_ty)
     }
 
     // Check field access expressions
@@ -2940,7 +2939,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                    expr: &'gcx hir::Expr,
                    lvalue_pref: LvaluePreference,
                    base: &'gcx hir::Expr,
-                   field: &Spanned) {
+                   field: &Spanned) -> Ty<'tcx> {
         self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
                                                      self.expr_ty(base));
@@ -2954,9 +2953,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             autoderef.finalize(lvalue_pref, Some(base));
-                            self.write_ty(expr.id, field_ty);
+                            let ty = self.write_ty(expr.id, field_ty);
                             self.write_autoderef_adjustment(base.id, autoderefs);
-                            return;
+                            return ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
                     }
@@ -2968,7 +2967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            self.write_ty(expr.id, field_ty);
+            let ty = self.write_ty(expr.id, field_ty);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
             let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
             // Also check if an accessible method exists, which is often what is meant.
@@ -2977,8 +2976,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   field.node));
             }
             err.emit();
+            ty
         } else if field.node == keywords::Invalid.name() {
-            self.write_error(expr.id);
+            self.write_error(expr.id)
         } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) {
             self.type_error_struct(field.span, |actual| {
                 format!("attempted to take value of method `{}` on type \
@@ -2987,7 +2987,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .help("maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
-            self.write_error(expr.id);
+            self.write_error(expr.id)
         } else {
             let mut err = self.type_error_struct(expr.span, |actual| {
                 format!("attempted access of field `{}` on type `{}`, \
@@ -3005,7 +3005,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => {}
             }
             err.emit();
-            self.write_error(expr.id);
+            self.write_error(expr.id)
         }
     }
 
@@ -3037,7 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        expr: &'gcx hir::Expr,
                        lvalue_pref: LvaluePreference,
                        base: &'gcx hir::Expr,
-                       idx: codemap::Spanned) {
+                       idx: codemap::Spanned) -> Ty<'tcx> {
         self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
                                                      self.expr_ty(base));
@@ -3070,9 +3070,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                self.write_ty(expr.id, field_ty);
+                let ty = self.write_ty(expr.id, field_ty);
                 self.write_autoderef_adjustment(base.id, autoderefs);
-                return;
+                return ty;
             }
         }
         autoderef.unambiguous_final_ty();
@@ -3081,8 +3081,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
             self.tcx().sess.span_err(expr.span, &msg);
-            self.write_ty(expr.id, field_ty);
-            return;
+            return self.write_ty(expr.id, field_ty)
         }
 
         self.type_error_message(
@@ -3102,7 +3101,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             expr_t);
 
-        self.write_error(expr.id);
+        self.write_error(expr.id)
     }
 
     fn report_unknown_field(&self,
@@ -3207,17 +3206,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_struct_fields_on_error(&self,
                                     id: ast::NodeId,
                                     fields: &'gcx [hir::Field],
-                                    base_expr: &'gcx Option>) {
+                                    base_expr: &'gcx Option>) -> Ty<'tcx> {
         // Make sure to still write the types
         // otherwise we might ICE
-        self.write_error(id);
+        let ty = self.write_error(id);
         for field in fields {
             self.check_expr(&field.expr);
         }
         match *base_expr {
-            Some(ref base) => self.check_expr(&base),
+            Some(ref base) => {
+                self.check_expr(&base);
+            },
             None => {}
         }
+        ty
     }
 
     pub fn check_struct_path(&self,
@@ -3267,15 +3269,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          expr: &hir::Expr,
                          path: &hir::Path,
                          fields: &'gcx [hir::Field],
-                         base_expr: &'gcx Option>)
+                         base_expr: &'gcx Option>) -> Ty<'tcx>
     {
         // Find the relevant variant
         let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
                                                                                   expr.span) {
             variant_ty
         } else {
-            self.check_struct_fields_on_error(expr.id, fields, base_expr);
-            return;
+            return self.check_struct_fields_on_error(expr.id, fields, base_expr);
         };
 
         self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
@@ -3299,6 +3300,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
+        expr_ty
     }
 
 
@@ -3315,13 +3317,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_expr_with_expectation_and_lvalue_pref(&self,
                                                    expr: &'gcx hir::Expr,
                                                    expected: Expectation<'tcx>,
-                                                   lvalue_pref: LvaluePreference) {
+                                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
 
         let tcx = self.tcx;
         let id = expr.id;
-        match expr.node {
+        let ty = match expr.node {
           hir::ExprBox(ref subexpr) => {
             let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
                 match ty.sty {
@@ -3331,18 +3333,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             });
             self.check_expr_with_expectation(subexpr, expected_inner);
             let referent_ty = self.expr_ty(&subexpr);
-            self.write_ty(id, tcx.mk_box(referent_ty));
+            self.write_ty(id, tcx.mk_box(referent_ty))
           }
 
           hir::ExprLit(ref lit) => {
             let typ = self.check_lit(&lit, expected);
-            self.write_ty(id, typ);
+            self.write_ty(id, typ)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            self.check_binop(expr, op, lhs, rhs);
+            self.check_binop(expr, op, lhs, rhs)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            self.check_binop_assign(expr, op, lhs, rhs);
+            self.check_binop_assign(expr, op, lhs, rhs)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
@@ -3357,10 +3359,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 hir::UnDeref => lvalue_pref,
                 _ => NoPreference
             };
-            self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
-                                                             expected_inner,
-                                                             lvalue_pref);
-            let mut oprnd_t = self.expr_ty(&oprnd);
+            let mut oprnd_t = self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
+                                                                               expected_inner,
+                                                                               lvalue_pref);
 
             if !oprnd_t.references_error() {
                 match unop {
@@ -3402,7 +3403,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, oprnd_t);
+            self.write_ty(id, oprnd_t)
           }
           hir::ExprAddrOf(mutbl, ref oprnd) => {
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
@@ -3421,9 +3422,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             });
             let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
-            self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
+            let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
-            let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl };
+            let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
             let oprnd_t = if tm.ty.references_error() {
                 tcx.types.err
             } else {
@@ -3443,24 +3444,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
                 tcx.mk_ref(region, tm)
             };
-            self.write_ty(id, oprnd_t);
+            self.write_ty(id, oprnd_t)
           }
           hir::ExprPath(ref opt_qself, ref path) => {
               let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
               let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
                                                                          expr.id, expr.span);
-              if def != Def::Err {
-                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id);
+              let ty = if def != Def::Err {
+                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id)
               } else {
                   self.set_tainted_by_errors();
-                  self.write_error(id);
-              }
+                  self.write_error(id)
+              };
 
               // We always require that the type provided as the value for
               // a type parameter outlives the moment of instantiation.
               self.opt_node_ty_substs(expr.id, |item_substs| {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
+              ty
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3469,10 +3471,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               for input in inputs {
                   self.check_expr(input);
               }
-              self.write_nil(id);
+              self.write_nil(id)
           }
-          hir::ExprBreak(_) => { self.write_never(id); }
-          hir::ExprAgain(_) => { self.write_never(id); }
+          hir::ExprBreak(_) => { self.write_never(id) }
+          hir::ExprAgain(_) => { self.write_never(id) }
           hir::ExprRet(ref expr_opt) => {
             if let Some(ref e) = *expr_opt {
                 self.check_expr_coercable_to_type(&e, self.ret_ty);
@@ -3490,10 +3492,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                 }
             }
-            self.write_never(id);
+            self.write_never(id)
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
-            self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
+            let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
 
             let tcx = self.tcx;
             if !tcx.expr_is_lval(&lhs) {
@@ -3506,21 +3508,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .emit();
             }
 
-            let lhs_ty = self.expr_ty(&lhs);
-            self.check_expr_coercable_to_type(&rhs, lhs_ty);
-            let rhs_ty = self.expr_ty(&rhs);
+            let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
 
             self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             } else {
-                self.write_nil(id);
+                self.write_nil(id)
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
             self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 id, expr.span, expected);
+                                 id, expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
             self.check_expr_has_type(&cond, tcx.types.bool);
@@ -3528,43 +3528,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let cond_ty = self.expr_ty(&cond);
             let body_ty = self.node_ty(body.id);
             if cond_ty.references_error() || body_ty.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             }
             else {
-                self.write_nil(id);
+                self.write_nil(id)
             }
           }
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_never(id);
+                self.write_never(id)
             } else {
-                self.write_nil(id);
+                self.write_nil(id)
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            self.check_match(expr, &discrim, arms, expected, match_src);
+            self.check_match(expr, &discrim, arms, expected, match_src)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              self.check_expr_closure(expr, capture, &decl, &body, expected);
+              self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);
-            self.write_ty(id, self.node_ty(b.id));
+            let ty = self.node_ty(b.id);
+            self.write_ty(id, ty)
           }
           hir::ExprCall(ref callee, ref args) => {
-              self.check_call(expr, &callee, &args[..], expected);
+              let ret_ty = self.check_call(expr, &callee, &args[..], expected);
 
               // we must check that return type of called functions is WF:
-              let ret_ty = self.expr_ty(expr);
               self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
+              ret_ty
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
+              let ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
               let arg_tys = args.iter().map(|a| self.expr_ty(&a));
               let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
               if args_err {
-                  self.write_error(id);
+                  self.write_error(id)
+              }
+              else {
+                  ty
               }
           }
           hir::ExprCast(ref e, ref t) => {
@@ -3576,26 +3580,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // if appropriate.
             let t_cast = self.to_ty(t);
             let t_cast = self.resolve_type_vars_if_possible(&t_cast);
-            self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
-            let t_expr = self.expr_ty(e);
+            let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
             let t_cast = self.resolve_type_vars_if_possible(&t_cast);
 
             // Eagerly check for some obvious errors.
             if t_expr.references_error() || t_cast.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             } else {
                 // Write a type for the whole expression, assuming everything is going
                 // to work out Ok.
-                self.write_ty(id, t_cast);
+                let ty = self.write_ty(id, t_cast);
 
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
+                        ty
                     }
                     Err(ErrorReported) => {
-                        self.write_error(id);
+                        self.write_error(id)
                     }
                 }
             }
@@ -3603,7 +3607,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprType(ref e, ref t) => {
             let typ = self.to_ty(&t);
             self.check_expr_eq_type(&e, typ);
-            self.write_ty(id, typ);
+            self.write_ty(id, typ)
           }
           hir::ExprVec(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
@@ -3617,8 +3621,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let coerce_to = uty.unwrap_or(unified);
 
             for (i, e) in args.iter().enumerate() {
-                self.check_expr_with_hint(e, coerce_to);
-                let e_ty = self.expr_ty(e);
+                let e_ty = self.check_expr_with_hint(e, coerce_to);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
@@ -3636,7 +3639,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, tcx.mk_array(unified, args.len()));
+            self.write_ty(id, tcx.mk_array(unified, args.len()))
           }
           hir::ExprRepeat(ref element, ref count_expr) => {
             self.check_expr_has_type(&count_expr, tcx.types.usize);
@@ -3660,8 +3663,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 None => {
                     let t: Ty = self.next_ty_var();
-                    self.check_expr_has_type(&element, t);
-                    (self.expr_ty(&element), t)
+                    let element_ty = self.check_expr_has_type(&element, t);
+                    (element_ty, t)
                 }
             };
 
@@ -3672,10 +3675,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
 
             if element_ty.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             } else {
                 let t = tcx.mk_array(t, count);
-                self.write_ty(id, t);
+                self.write_ty(id, t)
             }
           }
           hir::ExprTup(ref elts) => {
@@ -3695,49 +3698,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         ety
                     }
                     _ => {
-                        self.check_expr_with_expectation(&e, NoExpectation);
-                        self.expr_ty(&e)
+                        self.check_expr_with_expectation(&e, NoExpectation)
                     }
                 };
                 err_field = err_field || t.references_error();
                 t
             }).collect();
             if err_field {
-                self.write_error(id);
+                self.write_error(id)
             } else {
                 let typ = tcx.mk_tup(elt_ts);
-                self.write_ty(id, typ);
+                self.write_ty(id, typ)
             }
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-            self.check_expr_struct(expr, path, fields, base_expr);
+            let ty = self.check_expr_struct(expr, path, fields, base_expr);
 
             self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+            ty
           }
           hir::ExprField(ref base, ref field) => {
-            self.check_field(expr, lvalue_pref, &base, field);
+            self.check_field(expr, lvalue_pref, &base, field)
           }
           hir::ExprTupField(ref base, idx) => {
-            self.check_tup_field(expr, lvalue_pref, &base, idx);
+            self.check_tup_field(expr, lvalue_pref, &base, idx)
           }
           hir::ExprIndex(ref base, ref idx) => {
-              self.check_expr_with_lvalue_pref(&base, lvalue_pref);
-              self.check_expr(&idx);
-
-              let base_t = self.expr_ty(&base);
-              let idx_t = self.expr_ty(&idx);
+              let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
+              let idx_t = self.check_expr(&idx);
 
               if base_t.references_error() {
-                  self.write_ty(id, base_t);
+                  self.write_ty(id, base_t)
               } else if idx_t.references_error() {
-                  self.write_ty(id, idx_t);
+                  self.write_ty(id, idx_t)
               } else {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
                           let idx_expr_ty = self.expr_ty(idx);
                           self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
-                          self.write_ty(id, element_ty);
+                          self.write_ty(id, element_ty)
                       }
                       None => {
                           self.check_expr_has_type(&idx, self.tcx.types.err);
@@ -3773,18 +3773,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               }
                           }
                           err.emit();
-                          self.write_ty(id, self.tcx().types.err);
+                          self.write_ty(id, self.tcx().types.err)
                       }
                   }
               }
            }
-        }
+        };
 
         debug!("type of expr({}) {} is...", expr.id,
                pprust::expr_to_string(expr));
         debug!("... {:?}, expected is {:?}",
-               self.expr_ty(expr),
+               ty,
                expected);
+        ty
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
@@ -3878,9 +3879,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // referent for the reference that results is *equal to* the
             // type of the lvalue it is referencing, and not some
             // supertype thereof.
-            self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
-            let init_ty = self.expr_ty(init);
+            let init_ty = self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
             self.demand_eqtype(init.span, init_ty, local_ty);
+            init_ty
         } else {
             self.check_expr_coercable_to_type(init, local_ty)
         };
@@ -3905,7 +3906,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt)  {
+    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
         let node_id;
         let mut saw_bot = false;
         let mut saw_err = false;
@@ -3945,7 +3946,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_error(node_id);
         }
         else {
-            self.write_nil(node_id)
+            self.write_nil(node_id);
         }
     }
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index a8b1683f6d354..feb3258c88c25 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &'gcx hir::Expr,
                               op: hir::BinOp,
                               lhs_expr: &'gcx hir::Expr,
-                              rhs_expr: &'gcx hir::Expr)
+                              rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
         self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
@@ -32,12 +32,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
-        if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
+        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
             self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-            self.write_nil(expr.id);
+            self.tcx.mk_nil()
         } else {
-            self.write_ty(expr.id, return_ty);
-        }
+            return_ty
+        };
+        let ty = self.write_ty(expr.id, ty);
 
         let tcx = self.tcx;
         if !tcx.expr_is_lval(lhs_expr) {
@@ -49,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 &format!("invalid expression for left-hand side"))
             .emit();
         }
+        ty
     }
 
     /// Check a potentially overloaded binary operator.
@@ -56,7 +58,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        expr: &'gcx hir::Expr,
                        op: hir::BinOp,
                        lhs_expr: &'gcx hir::Expr,
-                       rhs_expr: &'gcx hir::Expr)
+                       rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
         let tcx = self.tcx;
 
@@ -70,12 +72,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.check_expr(lhs_expr);
         let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
 
-        match BinOpCategory::from(op) {
+        let ty = match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {
                 // && and || are a simple case.
                 self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
                 self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
-                self.write_ty(expr.id, tcx.mk_bool());
+                tcx.mk_bool()
             }
             _ => {
                 // Otherwise, we always treat operators as if they are
@@ -107,9 +109,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.demand_suptype(expr.span, builtin_return_ty, return_ty);
                 }
 
-                self.write_ty(expr.id, return_ty);
+                return_ty
             }
-        }
+        };
+        self.write_ty(expr.id, ty)
     }
 
     fn enforce_builtin_binop_types(&self,

From b93435fd79e26e09b8aa786eb682c82ec81f0293 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Wed, 10 Aug 2016 00:13:20 +0800
Subject: [PATCH 535/768] Remove most uses of expr_ty

---
 src/librustc_typeck/check/_match.rs | 20 +++----
 src/librustc_typeck/check/callee.rs |  3 +-
 src/librustc_typeck/check/mod.rs    | 85 ++++++++++++-----------------
 src/librustc_typeck/check/op.rs     |  8 +--
 4 files changed, 47 insertions(+), 69 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 1f0faab8f2c4a..2bb0abfab4ee7 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -37,12 +37,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.write_ty(pat.id, expected);
             }
             PatKind::Lit(ref lt) => {
-                self.check_expr(<);
-                let expr_ty = self.expr_ty(<);
+                let expr_t = self.check_expr(<);
 
                 // Byte string patterns behave the same way as array patterns
                 // They can denote both statically and dynamically sized byte arrays
-                let mut pat_ty = expr_ty;
+                let mut pat_ty = expr_t;
                 if let hir::ExprLit(ref lt) = lt.node {
                     if let ast::LitKind::ByteStr(_) = lt.node {
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
@@ -63,7 +62,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // relation at all but rather that there exists a LUB (so
                 // that they can be compared). However, in practice,
                 // constants are always scalars or strings.  For scalars
-                // subtyping is irrelevant, and for strings `expr_ty` is
+                // subtyping is irrelevant, and for strings `expr_t` is
                 // type is `&'static str`, so if we say that
                 //
                 //     &'static str <: expected
@@ -72,11 +71,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.demand_suptype(pat.span, expected, pat_ty);
             }
             PatKind::Range(ref begin, ref end) => {
-                self.check_expr(begin);
-                self.check_expr(end);
-
-                let lhs_ty = self.expr_ty(begin);
-                let rhs_ty = self.expr_ty(end);
+                let lhs_ty = self.check_expr(begin);
+                let rhs_ty = self.check_expr(end);
 
                 // Check that both end-points are of numeric or char type.
                 let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
@@ -385,8 +381,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                         });
         let discrim_ty;
         if let Some(m) = contains_ref_bindings {
-            self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
-            discrim_ty = self.expr_ty(discrim);
+            discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
         } else {
             // ...but otherwise we want to use any supertype of the
             // discriminant. This is sort of a workaround, see note (*) in
@@ -429,8 +424,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
-            self.check_expr_with_expectation(&arm.body, expected);
-            let arm_ty = self.expr_ty(&arm.body);
+            let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 4f673606de52f..bc3c5aba7100b 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -47,8 +47,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       arg_exprs: &'gcx [P],
                       expected: Expectation<'tcx>) -> Ty<'tcx>
     {
-        self.check_expr(callee_expr);
-        let original_callee_ty = self.expr_ty(callee_expr);
+        let original_callee_ty = self.check_expr(callee_expr);
 
         let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty);
         let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5c528cc46a73c..774969daf388a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1750,13 +1750,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.require_type_meets(ty, span, code, ty::BoundSized);
     }
 
-    pub fn require_expr_have_sized_type(&self,
-                                        expr: &hir::Expr,
-                                        code: traits::ObligationCauseCode<'tcx>)
-    {
-        self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
-    }
-
     pub fn register_builtin_bound(&self,
                                   ty: Ty<'tcx>,
                                   builtin_bound: ty::BuiltinBound,
@@ -1801,7 +1794,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
                           -> Ty<'tcx>
     {
-        let raw_ty = self.expr_ty(expr);
+        let raw_ty = self.node_ty(expr.id);
         let raw_ty = self.shallow_resolve(raw_ty);
         let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
         raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| {
@@ -2623,12 +2616,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // arguments which we skipped above.
         if variadic {
             for arg in args.iter().skip(expected_arg_count) {
-                self.check_expr(&arg);
+                let arg_ty = self.check_expr(&arg);
 
                 // There are a few types which get autopromoted when passed via varargs
                 // in C but we just error out instead and require explicit casts.
                 let arg_ty = self.structurally_resolved_type(arg.span,
-                                                             self.expr_ty(&arg));
+                                                             arg_ty);
                 match arg_ty.sty {
                     ty::TyFloat(ast::FloatTy::F32) => {
                         self.type_error_message(arg.span, |t| {
@@ -2718,15 +2711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_expr_eq_type(&self,
                           expr: &'gcx hir::Expr,
                           expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
-        self.demand_eqtype(expr.span, expected, self.expr_ty(expr));
+        let ty = self.check_expr_with_hint(expr, expected);
+        self.demand_eqtype(expr.span, expected, ty);
     }
 
     pub fn check_expr_has_type(&self,
                                expr: &'gcx hir::Expr,
                                expected: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.check_expr_with_hint(expr, expected);
-        self.demand_suptype(expr.span, expected, self.expr_ty(expr));
+        self.demand_suptype(expr.span, expected, ty);
         ty
     }
 
@@ -2821,10 +2814,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          expected: Expectation<'tcx>,
                          lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let rcvr = &args[0];
-        self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
+        let rcvr_t = self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
 
         // no need to check for bot/err -- callee does that
-        let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(&rcvr));
+        let expr_t = self.structurally_resolved_type(expr.span, rcvr_t);
 
         let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::>();
         let fn_ty = match self.lookup_method(method_name.span,
@@ -2867,7 +2860,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        id: ast::NodeId,
                        sp: Span,
                        expected: Expectation<'tcx>) -> Ty<'tcx> {
-        self.check_expr_has_type(cond_expr, self.tcx.types.bool);
+        let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
         self.check_block_with_expected(then_blk, expected);
@@ -2876,8 +2869,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
         if let Some(else_expr) = opt_else_expr {
-            self.check_expr_with_expectation(else_expr, expected);
-            let else_ty = self.expr_ty(else_expr);
+            let else_ty = self.check_expr_with_expectation(else_expr, expected);
             let origin = TypeOrigin::IfExpression(sp);
 
             // Only try to coerce-unify if we have a then expression
@@ -2919,7 +2911,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let if_ty = match result {
             Ok(ty) => {
-                if self.expr_ty(cond_expr).references_error() {
+                if cond_ty.references_error() {
                     self.tcx.types.err
                 } else {
                     ty
@@ -2940,9 +2932,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                    lvalue_pref: LvaluePreference,
                    base: &'gcx hir::Expr,
                    field: &Spanned) -> Ty<'tcx> {
-        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
-                                                     self.expr_ty(base));
+                                                     expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
         while let Some((base_t, autoderefs)) = autoderef.next() {
@@ -3038,9 +3030,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        lvalue_pref: LvaluePreference,
                        base: &'gcx hir::Expr,
                        idx: codemap::Spanned) -> Ty<'tcx> {
-        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
-                                                     self.expr_ty(base));
+                                                     expr_t);
         let mut private_candidate = None;
         let mut tuple_like = false;
         let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -3272,18 +3264,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          base_expr: &'gcx Option>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
+        let (variant, expr_t) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
                                                                                   expr.span) {
             variant_ty
         } else {
             return self.check_struct_fields_on_error(expr.id, fields, base_expr);
         };
 
-        self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
+        self.check_expr_struct_fields(expr_t, path.span, variant, fields,
                                       base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            self.check_expr_has_type(base_expr, expr_ty);
-            match expr_ty.sty {
+            self.check_expr_has_type(base_expr, expr_t);
+            match expr_t.sty {
                 ty::TyStruct(adt, substs) => {
                     self.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
@@ -3300,7 +3292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
-        expr_ty
+        expr_t
     }
 
 
@@ -3331,8 +3323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => NoExpectation
                 }
             });
-            self.check_expr_with_expectation(subexpr, expected_inner);
-            let referent_ty = self.expr_ty(&subexpr);
+            let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner);
             self.write_ty(id, tcx.mk_box(referent_ty))
           }
 
@@ -3510,7 +3501,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
 
-            self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
+            self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
                 self.write_error(id)
@@ -3523,9 +3514,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                  id, expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
-            self.check_expr_has_type(&cond, tcx.types.bool);
+            let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
             self.check_block_no_value(&body);
-            let cond_ty = self.expr_ty(&cond);
             let body_ty = self.node_ty(body.id);
             if cond_ty.references_error() || body_ty.references_error() {
                 self.write_error(id)
@@ -3714,7 +3704,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
             let ty = self.check_expr_struct(expr, path, fields, base_expr);
 
-            self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+            self.require_type_is_sized(ty, expr.span, traits::StructInitializerSized);
             ty
           }
           hir::ExprField(ref base, ref field) => {
@@ -3735,8 +3725,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
-                          let idx_expr_ty = self.expr_ty(idx);
-                          self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
+                          self.demand_eqtype(expr.span, index_ty, idx_t);
                           self.write_ty(id, element_ty)
                       }
                       None => {
@@ -3865,7 +3854,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn check_decl_initializer(&self,
                                   local: &'gcx hir::Local,
-                                  init: &'gcx hir::Expr)
+                                  init: &'gcx hir::Expr) -> Ty<'tcx>
     {
         let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
 
@@ -3884,7 +3873,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             init_ty
         } else {
             self.check_expr_coercable_to_type(init, local_ty)
-        };
+        }
     }
 
     pub fn check_decl_local(&self, local: &'gcx hir::Local)  {
@@ -3892,8 +3881,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.write_ty(local.id, t);
 
         if let Some(ref init) = local.init {
-            self.check_decl_initializer(local, &init);
-            let init_ty = self.expr_ty(&init);
+            let init_ty = self.check_decl_initializer(local, &init);
             if init_ty.references_error() {
                 self.write_ty(local.id, init_ty);
             }
@@ -3926,17 +3914,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::StmtExpr(ref expr, id) => {
             node_id = id;
             // Check with expected type of ()
-            self.check_expr_has_type(&expr, self.tcx.mk_nil());
-            let expr_ty = self.expr_ty(&expr);
-            saw_bot = saw_bot || self.type_var_diverges(expr_ty);
-            saw_err = saw_err || expr_ty.references_error();
+            let expr_t = self.check_expr_has_type(&expr, self.tcx.mk_nil());
+            saw_bot = saw_bot || self.type_var_diverges(expr_t);
+            saw_err = saw_err || expr_t.references_error();
           }
           hir::StmtSemi(ref expr, id) => {
             node_id = id;
-            self.check_expr(&expr);
-            let expr_ty = self.expr_ty(&expr);
-            saw_bot |= self.type_var_diverges(expr_ty);
-            saw_err |= expr_ty.references_error();
+            let expr_t = self.check_expr(&expr);
+            saw_bot |= self.type_var_diverges(expr_t);
+            saw_err |= expr_t.references_error();
           }
         }
         if saw_bot {
@@ -4023,8 +4009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         ety
                     }
                     _ => {
-                        self.check_expr_with_expectation(&e, expected);
-                        self.expr_ty(&e)
+                        self.check_expr_with_expectation(&e, expected)
                     }
                 };
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index feb3258c88c25..5462826ef9048 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -25,9 +25,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               lhs_expr: &'gcx hir::Expr,
                               rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
-        self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
+        let lhs_ty = self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
-        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
         let (rhs_ty, return_ty) =
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
@@ -69,8 +69,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                lhs_expr,
                rhs_expr);
 
-        self.check_expr(lhs_expr);
-        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let lhs_ty = self.check_expr(lhs_expr);
+        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
         let ty = match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {

From c7ea3e8d134b941a0ed2f3d6b535649d081bf92d Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 14:21:13 +0800
Subject: [PATCH 536/768] Remove redundant error checking around ExprMethodCall

---
 src/librustc_typeck/check/mod.rs | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 774969daf388a..df789897bf154 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3551,15 +3551,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               ret_ty
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              let ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
-              let arg_tys = args.iter().map(|a| self.expr_ty(&a));
-              let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
-              if args_err {
-                  self.write_error(id)
-              }
-              else {
-                  ty
-              }
+              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {

From 06ad8fe261aae7b58b70be58f6a3ac6d5d9d2328 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 17:16:42 +0800
Subject: [PATCH 537/768] Factor write_ty out of check_binop*

---
 src/librustc_typeck/check/mod.rs | 6 ++++--
 src/librustc_typeck/check/op.rs  | 6 ++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index df789897bf154..7a5b2bdeb1638 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3332,10 +3332,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_ty(id, typ)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            self.check_binop(expr, op, lhs, rhs)
+            let ty = self.check_binop(expr, op, lhs, rhs);
+            self.write_ty(id, ty)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            self.check_binop_assign(expr, op, lhs, rhs)
+            let ty = self.check_binop_assign(expr, op, lhs, rhs);
+            self.write_ty(id, ty)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 5462826ef9048..af7e12bd48dc2 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -38,7 +38,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         } else {
             return_ty
         };
-        let ty = self.write_ty(expr.id, ty);
 
         let tcx = self.tcx;
         if !tcx.expr_is_lval(lhs_expr) {
@@ -72,7 +71,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let lhs_ty = self.check_expr(lhs_expr);
         let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
-        let ty = match BinOpCategory::from(op) {
+        match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {
                 // && and || are a simple case.
                 self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
@@ -111,8 +110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 return_ty
             }
-        };
-        self.write_ty(expr.id, ty)
+        }
     }
 
     fn enforce_builtin_binop_types(&self,

From 91b39b5e65ac66f85bc6be749593690417d0373e Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 21:09:21 +0800
Subject: [PATCH 538/768] Factor write_ty out of more checking functions

---
 src/librustc_typeck/check/_match.rs |  6 ++++--
 src/librustc_typeck/check/mod.rs    | 27 +++++++++++----------------
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 2bb0abfab4ee7..b69afbf8ff03d 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -473,8 +473,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
         }
-
-        self.write_ty(expr.id, result_ty)
+        
+        result_ty
     }
 }
 
@@ -545,6 +545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
+        self.write_ty(pat.id, pat_ty);
         self.demand_suptype(pat.span, expected, pat_ty);
     }
 
@@ -603,6 +604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
+        self.write_ty(pat.id, pat_ty);
 
         let pat_ty = if pat_ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7a5b2bdeb1638..4d5160a4de6b3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2857,7 +2857,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        cond_expr: &'gcx hir::Expr,
                        then_blk: &'gcx hir::Block,
                        opt_else_expr: Option<&'gcx hir::Expr>,
-                       id: ast::NodeId,
                        sp: Span,
                        expected: Expectation<'tcx>) -> Ty<'tcx> {
         let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
@@ -2909,7 +2908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                  }))
         };
 
-        let if_ty = match result {
+        match result {
             Ok(ty) => {
                 if cond_ty.references_error() {
                     self.tcx.types.err
@@ -2921,9 +2920,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.report_mismatched_types(origin, expected, found, e);
                 self.tcx.types.err
             }
-        };
-
-        self.write_ty(id, if_ty)
+        }
     }
 
     // Check field access expressions
@@ -3447,7 +3444,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   self.instantiate_value_path(segments, opt_ty, def, expr.span, id)
               } else {
                   self.set_tainted_by_errors();
-                  self.write_error(id)
+                  tcx.types.err
               };
 
               // We always require that the type provided as the value for
@@ -3455,7 +3452,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               self.opt_node_ty_substs(expr.id, |item_substs| {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
-              ty
+
+              self.write_ty(id, ty)
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3512,8 +3510,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
-            self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 id, expr.span, expected)
+            let if_ty = self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
+                                 expr.span, expected);
+            self.write_ty(id, if_ty)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
             let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
@@ -3535,7 +3534,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            self.check_match(expr, &discrim, arms, expected, match_src)
+            let result_ty = self.check_match(expr, &discrim, arms, expected, match_src);
+            self.write_ty(expr.id, result_ty)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
               self.check_expr_closure(expr, capture, &decl, &body, expected)
@@ -3571,16 +3571,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if t_expr.references_error() || t_cast.references_error() {
                 self.write_error(id)
             } else {
-                // Write a type for the whole expression, assuming everything is going
-                // to work out Ok.
-                let ty = self.write_ty(id, t_cast);
-
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
-                        ty
+                        self.write_ty(id, t_cast)
                     }
                     Err(ErrorReported) => {
                         self.write_error(id)
@@ -4328,7 +4324,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });

From f22dd2e2d9f29869ff7956cecb5a616ce50e3e89 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 22:07:57 +0800
Subject: [PATCH 539/768] Factor write_ty out of field/indexing methods

---
 src/librustc_typeck/check/mod.rs | 38 ++++++++++++++++----------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4d5160a4de6b3..30f4202fccbf0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2942,9 +2942,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             autoderef.finalize(lvalue_pref, Some(base));
-                            let ty = self.write_ty(expr.id, field_ty);
                             self.write_autoderef_adjustment(base.id, autoderefs);
-                            return ty;
+                            return field_ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
                     }
@@ -2956,7 +2955,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            let ty = self.write_ty(expr.id, field_ty);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
             let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
             // Also check if an accessible method exists, which is often what is meant.
@@ -2965,9 +2963,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   field.node));
             }
             err.emit();
-            ty
+            field_ty
         } else if field.node == keywords::Invalid.name() {
-            self.write_error(expr.id)
+            self.tcx().types.err
         } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) {
             self.type_error_struct(field.span, |actual| {
                 format!("attempted to take value of method `{}` on type \
@@ -2976,7 +2974,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .help("maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
-            self.write_error(expr.id)
+            self.tcx().types.err
         } else {
             let mut err = self.type_error_struct(expr.span, |actual| {
                 format!("attempted access of field `{}` on type `{}`, \
@@ -2994,7 +2992,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => {}
             }
             err.emit();
-            self.write_error(expr.id)
+            self.tcx().types.err
         }
     }
 
@@ -3059,9 +3057,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                let ty = self.write_ty(expr.id, field_ty);
                 self.write_autoderef_adjustment(base.id, autoderefs);
-                return ty;
+                return field_ty;
             }
         }
         autoderef.unambiguous_final_ty();
@@ -3070,7 +3067,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
             self.tcx().sess.span_err(expr.span, &msg);
-            return self.write_ty(expr.id, field_ty)
+            return field_ty;
         }
 
         self.type_error_message(
@@ -3090,7 +3087,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             expr_t);
 
-        self.write_error(expr.id)
+        self.tcx().types.err
     }
 
     fn report_unknown_field(&self,
@@ -3698,25 +3695,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ty
           }
           hir::ExprField(ref base, ref field) => {
-            self.check_field(expr, lvalue_pref, &base, field)
+            let ty = self.check_field(expr, lvalue_pref, &base, field);
+            self.write_ty(id, ty)
           }
           hir::ExprTupField(ref base, idx) => {
-            self.check_tup_field(expr, lvalue_pref, &base, idx)
+            let ty = self.check_tup_field(expr, lvalue_pref, &base, idx);
+            self.write_ty(id, ty)
           }
           hir::ExprIndex(ref base, ref idx) => {
               let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
               let idx_t = self.check_expr(&idx);
 
-              if base_t.references_error() {
-                  self.write_ty(id, base_t)
+              let ty = if base_t.references_error() {
+                  base_t
               } else if idx_t.references_error() {
-                  self.write_ty(id, idx_t)
+                  idx_t
               } else {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
                           self.demand_eqtype(expr.span, index_ty, idx_t);
-                          self.write_ty(id, element_ty)
+                          element_ty
                       }
                       None => {
                           self.check_expr_has_type(&idx, self.tcx.types.err);
@@ -3752,10 +3751,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               }
                           }
                           err.emit();
-                          self.write_ty(id, self.tcx().types.err)
+                          self.tcx().types.err
                       }
                   }
-              }
+              };
+              self.write_ty(id, ty)
            }
         };
 

From 144b8cf5db99df4f6132f1ac5b59184f8907965d Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 22:51:01 +0800
Subject: [PATCH 540/768] Factor write_ty out of check_struct_expr

---
 src/librustc_typeck/check/_match.rs |  1 +
 src/librustc_typeck/check/mod.rs    | 16 +++++-----------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index b69afbf8ff03d..838cf36b8853e 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -497,6 +497,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             return;
         };
+        self.write_ty(pat.id, pat_ty);
 
         // Type check the path.
         self.demand_eqtype(pat.span, expected, pat_ty);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 30f4202fccbf0..f70d7c577486c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1711,7 +1711,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.add_obligations_for_parameters(cause, &bounds);
 
         let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty);
-        self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });
@@ -3190,12 +3189,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn check_struct_fields_on_error(&self,
-                                    id: ast::NodeId,
                                     fields: &'gcx [hir::Field],
-                                    base_expr: &'gcx Option>) -> Ty<'tcx> {
-        // Make sure to still write the types
-        // otherwise we might ICE
-        let ty = self.write_error(id);
+                                    base_expr: &'gcx Option>) {
         for field in fields {
             self.check_expr(&field.expr);
         }
@@ -3205,7 +3200,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             None => {}
         }
-        ty
     }
 
     pub fn check_struct_path(&self,
@@ -3262,7 +3256,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                                   expr.span) {
             variant_ty
         } else {
-            return self.check_struct_fields_on_error(expr.id, fields, base_expr);
+            self.check_struct_fields_on_error(fields, base_expr);
+            return self.tcx().types.err;
         };
 
         self.check_expr_struct_fields(expr_t, path.span, variant, fields,
@@ -3286,6 +3281,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
+        self.require_type_is_sized(expr_t, expr.span, traits::StructInitializerSized);
         expr_t
     }
 
@@ -3690,9 +3686,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
             let ty = self.check_expr_struct(expr, path, fields, base_expr);
-
-            self.require_type_is_sized(ty, expr.span, traits::StructInitializerSized);
-            ty
+            self.write_ty(id, ty)
           }
           hir::ExprField(ref base, ref field) => {
             let ty = self.check_field(expr, lvalue_pref, &base, field);

From 21720641dc4d3b921eb5be2a4c66900003a742dd Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 23:30:11 +0800
Subject: [PATCH 541/768] Factor write_ty out of check_expr_closure

---
 src/librustc_typeck/check/closure.rs | 4 +---
 src/librustc_typeck/check/mod.rs     | 3 ++-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 1f4201aa39cdd..9e41d1b5676e4 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -70,8 +70,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.parameter_environment.free_substs,
             upvar_tys);
 
-        let ty = self.write_ty(expr.id, closure_type);
-
         let fn_sig = self.tcx.liberate_late_bound_regions(
             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
         let fn_sig =
@@ -94,7 +92,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             None => { }
         }
 
-        ty
+        closure_type
     }
 
     fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f70d7c577486c..4c400f1092c5f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3531,7 +3531,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_ty(expr.id, result_ty)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              self.check_expr_closure(expr, capture, &decl, &body, expected)
+              let ty = self.check_expr_closure(expr, capture, &decl, &body, expected);
+              self.write_ty(id, ty)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);

From 9cd8d7a24f73e7de91cc3ba4461eeb6fe8a086f3 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 23:52:05 +0800
Subject: [PATCH 542/768] Factor write_ty out of function checking functions

---
 src/librustc_typeck/check/callee.rs | 18 +++++++++++-------
 src/librustc_typeck/check/mod.rs    | 10 ++++------
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index bc3c5aba7100b..5bd4f13a1119c 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -15,7 +15,7 @@ use CrateCtxt;
 use middle::cstore::LOCAL_CRATE;
 use hir::def::Def;
 use hir::def_id::DefId;
-use rustc::infer;
+use rustc::{infer, traits};
 use rustc::ty::{self, LvaluePreference, Ty};
 use syntax::parse::token;
 use syntax::ptr::P;
@@ -56,7 +56,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let callee_ty = autoderef.unambiguous_final_ty();
         autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
 
-        match result {
+        let output = match result {
             None => {
                 // this will report an error since original_callee_ty is not a fn
                 self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
@@ -74,7 +74,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.confirm_overloaded_call(call_expr, callee_expr,
                                              arg_exprs, expected, method_callee)
             }
-        }
+        };
+
+        // we must check that return type of called functions is WF:
+        self.register_wf_obligation(output, call_expr.span, traits::MiscObligation);
+
+        output
     }
 
     fn try_overloaded_call_step(&self,
@@ -244,7 +249,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::DontTupleArguments);
 
-        self.write_ty(call_expr.id, fn_sig.output)
+        fn_sig.output
     }
 
     fn confirm_deferred_closure_call(&self,
@@ -271,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::TupleArguments);
 
-        self.write_ty(call_expr.id, fn_sig.output)
+        fn_sig.output
     }
 
     fn confirm_overloaded_call(&self,
@@ -288,10 +293,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                              arg_exprs,
                                              TupleArgumentsFlag::TupleArguments,
                                              expected);
-        let ty = self.write_ty(call_expr.id, output_type);
 
         self.write_overloaded_call_method_map(call_expr, method_callee);
-        ty
+        output_type
     }
 
     fn write_overloaded_call_method_map(&self,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4c400f1092c5f..8406b491737ec 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2847,7 +2847,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                       DontTupleArguments,
                                                       expected);
 
-        self.write_ty(expr.id, ret_ty)
+        ret_ty
     }
 
     // A generic function for checking the then and else in an if
@@ -3541,13 +3541,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           }
           hir::ExprCall(ref callee, ref args) => {
               let ret_ty = self.check_call(expr, &callee, &args[..], expected);
-
-              // we must check that return type of called functions is WF:
-              self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
-              ret_ty
+              self.write_ty(id, ret_ty)
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
+              let ret_ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
+              self.write_ty(id, ret_ty)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {

From adb19ff277262ce629e092feabdc5f5f5a2ac408 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 00:13:15 +0800
Subject: [PATCH 543/768] Add AdjustNeverToAny in check_expr

---
 src/librustc_typeck/check/mod.rs | 130 ++++++++++++++-----------------
 1 file changed, 57 insertions(+), 73 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8406b491737ec..2a12b7055d4ed 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1530,21 +1530,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     #[inline]
-    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) -> Ty<'tcx> {
+    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
-
-        // Add adjustments to !-expressions
-        if ty.is_never() {
-            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
-                let adj_ty = self.next_diverging_ty_var();
-                let adj = adjustment::AdjustNeverToAny(adj_ty);
-                self.write_adjustment(node_id, adj);
-                return adj_ty;
-            }
-        }
-        ty
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1717,16 +1706,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty_substituted
     }
 
-    pub fn write_nil(&self, node_id: ast::NodeId) -> Ty<'tcx> {
-        self.write_ty(node_id, self.tcx.mk_nil())
+    pub fn write_nil(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.mk_nil());
     }
 
-    pub fn write_never(&self, node_id: ast::NodeId) -> Ty<'tcx> {
-        self.write_ty(node_id, self.tcx.types.never)
+    pub fn write_never(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.types.never);
     }
 
-    pub fn write_error(&self, node_id: ast::NodeId) -> Ty<'tcx> {
-        self.write_ty(node_id, self.tcx.types.err)
+    pub fn write_error(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.types.err);
     }
 
     pub fn require_type_meets(&self,
@@ -3314,20 +3303,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             });
             let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner);
-            self.write_ty(id, tcx.mk_box(referent_ty))
+            tcx.mk_box(referent_ty)
           }
 
           hir::ExprLit(ref lit) => {
-            let typ = self.check_lit(&lit, expected);
-            self.write_ty(id, typ)
+            self.check_lit(&lit, expected)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            let ty = self.check_binop(expr, op, lhs, rhs);
-            self.write_ty(id, ty)
+            self.check_binop(expr, op, lhs, rhs)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            let ty = self.check_binop_assign(expr, op, lhs, rhs);
-            self.write_ty(id, ty)
+            self.check_binop_assign(expr, op, lhs, rhs)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
@@ -3386,7 +3372,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, oprnd_t)
+            oprnd_t
           }
           hir::ExprAddrOf(mutbl, ref oprnd) => {
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
@@ -3408,7 +3394,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
             let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
-            let oprnd_t = if tm.ty.references_error() {
+            if tm.ty.references_error() {
                 tcx.types.err
             } else {
                 // Note: at this point, we cannot say what the best lifetime
@@ -3426,8 +3412,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // as long as it needs to live.
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
                 tcx.mk_ref(region, tm)
-            };
-            self.write_ty(id, oprnd_t)
+            }
           }
           hir::ExprPath(ref opt_qself, ref path) => {
               let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
@@ -3446,7 +3431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
 
-              self.write_ty(id, ty)
+              ty
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3455,10 +3440,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               for input in inputs {
                   self.check_expr(input);
               }
-              self.write_nil(id)
+              tcx.mk_nil()
           }
-          hir::ExprBreak(_) => { self.write_never(id) }
-          hir::ExprAgain(_) => { self.write_never(id) }
+          hir::ExprBreak(_) => { tcx.types.never }
+          hir::ExprAgain(_) => { tcx.types.never }
           hir::ExprRet(ref expr_opt) => {
             if let Some(ref e) = *expr_opt {
                 self.check_expr_coercable_to_type(&e, self.ret_ty);
@@ -3476,7 +3461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                 }
             }
-            self.write_never(id)
+            tcx.types.never
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
             let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
@@ -3497,55 +3482,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
-                self.write_error(id)
+                tcx.types.err
             } else {
-                self.write_nil(id)
+                tcx.mk_nil()
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
-            let if_ty = self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 expr.span, expected);
-            self.write_ty(id, if_ty)
+            self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
+                                 expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
             let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
             self.check_block_no_value(&body);
             let body_ty = self.node_ty(body.id);
             if cond_ty.references_error() || body_ty.references_error() {
-                self.write_error(id)
+                tcx.types.err
             }
             else {
-                self.write_nil(id)
+                tcx.mk_nil()
             }
           }
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_never(id)
+                tcx.types.never
             } else {
-                self.write_nil(id)
+                tcx.mk_nil()
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            let result_ty = self.check_match(expr, &discrim, arms, expected, match_src);
-            self.write_ty(expr.id, result_ty)
+            self.check_match(expr, &discrim, arms, expected, match_src)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              let ty = self.check_expr_closure(expr, capture, &decl, &body, expected);
-              self.write_ty(id, ty)
+              self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);
-            let ty = self.node_ty(b.id);
-            self.write_ty(id, ty)
+            self.node_ty(b.id)
           }
           hir::ExprCall(ref callee, ref args) => {
-              let ret_ty = self.check_call(expr, &callee, &args[..], expected);
-              self.write_ty(id, ret_ty)
+              self.check_call(expr, &callee, &args[..], expected)
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              let ret_ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
-              self.write_ty(id, ret_ty)
+              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
@@ -3561,17 +3540,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             // Eagerly check for some obvious errors.
             if t_expr.references_error() || t_cast.references_error() {
-                self.write_error(id)
+                tcx.types.err
             } else {
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
-                        self.write_ty(id, t_cast)
+                        t_cast
                     }
                     Err(ErrorReported) => {
-                        self.write_error(id)
+                        tcx.types.err
                     }
                 }
             }
@@ -3579,7 +3558,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprType(ref e, ref t) => {
             let typ = self.to_ty(&t);
             self.check_expr_eq_type(&e, typ);
-            self.write_ty(id, typ)
+            typ
           }
           hir::ExprVec(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
@@ -3611,7 +3590,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, tcx.mk_array(unified, args.len()))
+            tcx.mk_array(unified, args.len())
           }
           hir::ExprRepeat(ref element, ref count_expr) => {
             self.check_expr_has_type(&count_expr, tcx.types.usize);
@@ -3647,10 +3626,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
 
             if element_ty.references_error() {
-                self.write_error(id)
+                tcx.types.err
             } else {
-                let t = tcx.mk_array(t, count);
-                self.write_ty(id, t)
+                tcx.mk_array(t, count)
             }
           }
           hir::ExprTup(ref elts) => {
@@ -3677,29 +3655,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 t
             }).collect();
             if err_field {
-                self.write_error(id)
+                tcx.types.err
             } else {
-                let typ = tcx.mk_tup(elt_ts);
-                self.write_ty(id, typ)
+                tcx.mk_tup(elt_ts)
             }
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-            let ty = self.check_expr_struct(expr, path, fields, base_expr);
-            self.write_ty(id, ty)
+            self.check_expr_struct(expr, path, fields, base_expr)
           }
           hir::ExprField(ref base, ref field) => {
-            let ty = self.check_field(expr, lvalue_pref, &base, field);
-            self.write_ty(id, ty)
+            self.check_field(expr, lvalue_pref, &base, field)
           }
           hir::ExprTupField(ref base, idx) => {
-            let ty = self.check_tup_field(expr, lvalue_pref, &base, idx);
-            self.write_ty(id, ty)
+            self.check_tup_field(expr, lvalue_pref, &base, idx)
           }
           hir::ExprIndex(ref base, ref idx) => {
               let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
               let idx_t = self.check_expr(&idx);
 
-              let ty = if base_t.references_error() {
+              if base_t.references_error() {
                   base_t
               } else if idx_t.references_error() {
                   idx_t
@@ -3747,16 +3721,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           self.tcx().types.err
                       }
                   }
-              };
-              self.write_ty(id, ty)
+              }
            }
         };
+        self.write_ty(id, ty);
 
         debug!("type of expr({}) {} is...", expr.id,
                pprust::expr_to_string(expr));
         debug!("... {:?}, expected is {:?}",
                ty,
                expected);
+
+        // Add adjustments to !-expressions
+        if ty.is_never() {
+            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(id) {
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
+                self.write_adjustment(id, adj);
+                return adj_ty;
+            }
+        }
         ty
     }
 

From 1c3e8b0a1c15d4cb7315a7067c19901c2cf66e0c Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 00:24:32 +0800
Subject: [PATCH 544/768] Tidy

---
 src/librustc_typeck/check/_match.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 838cf36b8853e..5e7c499671c34 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -473,7 +473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
         }
-        
+
         result_ty
     }
 }

From f120c71775994e4fb94941cbc5539f6d5ffddced Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 14:12:37 +0800
Subject: [PATCH 545/768] Tidy. Rename variables.

---
 src/librustc_typeck/check/_match.rs |  6 +++---
 src/librustc_typeck/check/mod.rs    | 26 +++++++++++++-------------
 src/librustc_typeck/check/op.rs     |  3 ++-
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5e7c499671c34..763e92b69baf0 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -37,11 +37,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.write_ty(pat.id, expected);
             }
             PatKind::Lit(ref lt) => {
-                let expr_t = self.check_expr(<);
+                let ty = self.check_expr(<);
 
                 // Byte string patterns behave the same way as array patterns
                 // They can denote both statically and dynamically sized byte arrays
-                let mut pat_ty = expr_t;
+                let mut pat_ty = ty;
                 if let hir::ExprLit(ref lt) = lt.node {
                     if let ast::LitKind::ByteStr(_) = lt.node {
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
@@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // relation at all but rather that there exists a LUB (so
                 // that they can be compared). However, in practice,
                 // constants are always scalars or strings.  For scalars
-                // subtyping is irrelevant, and for strings `expr_t` is
+                // subtyping is irrelevant, and for strings `ty` is
                 // type is `&'static str`, so if we say that
                 //
                 //     &'static str <: expected
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2a12b7055d4ed..a8c8a10dc568e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3241,19 +3241,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          base_expr: &'gcx Option>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, expr_t) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
-                                                                                  expr.span) {
+        let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
+                                                                                    expr.span) {
             variant_ty
         } else {
             self.check_struct_fields_on_error(fields, base_expr);
             return self.tcx().types.err;
         };
 
-        self.check_expr_struct_fields(expr_t, path.span, variant, fields,
+        self.check_expr_struct_fields(struct_ty, path.span, variant, fields,
                                       base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            self.check_expr_has_type(base_expr, expr_t);
-            match expr_t.sty {
+            self.check_expr_has_type(base_expr, struct_ty);
+            match struct_ty.sty {
                 ty::TyStruct(adt, substs) => {
                     self.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
@@ -3270,8 +3270,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
-        self.require_type_is_sized(expr_t, expr.span, traits::StructInitializerSized);
-        expr_t
+        self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized);
+        struct_ty
     }
 
 
@@ -3881,15 +3881,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::StmtExpr(ref expr, id) => {
             node_id = id;
             // Check with expected type of ()
-            let expr_t = self.check_expr_has_type(&expr, self.tcx.mk_nil());
-            saw_bot = saw_bot || self.type_var_diverges(expr_t);
-            saw_err = saw_err || expr_t.references_error();
+            let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil());
+            saw_bot = saw_bot || self.type_var_diverges(ty);
+            saw_err = saw_err || ty.references_error();
           }
           hir::StmtSemi(ref expr, id) => {
             node_id = id;
-            let expr_t = self.check_expr(&expr);
-            saw_bot |= self.type_var_diverges(expr_t);
-            saw_err |= expr_t.references_error();
+            let ty = self.check_expr(&expr);
+            saw_bot |= self.type_var_diverges(ty);
+            saw_err |= ty.references_error();
           }
         }
         if saw_bot {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index af7e12bd48dc2..411bd7e7b5ca1 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -32,7 +32,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
-        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
+        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var()
+                    && is_builtin_binop(lhs_ty, rhs_ty, op) {
             self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
             self.tcx.mk_nil()
         } else {

From f54c47d34b0d8c898529c479a270ab034ce36f78 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 14:17:00 +0800
Subject: [PATCH 546/768] Move check_expr match block into its own method

---
 src/librustc_typeck/check/mod.rs | 45 ++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a8c8a10dc568e..3fbfd2aedb466 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3291,10 +3291,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                    lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
+        let ty = self.check_expr_kind(expr, expected, lvalue_pref);
 
+        self.write_ty(expr.id, ty);
+
+        debug!("type of expr({}) {} is...", expr.id,
+               pprust::expr_to_string(expr));
+        debug!("... {:?}, expected is {:?}",
+               ty,
+               expected);
+
+        // Add adjustments to !-expressions
+        if ty.is_never() {
+            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) {
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
+                self.write_adjustment(expr.id, adj);
+                return adj_ty;
+            }
+        }
+        ty
+    }
+
+    fn check_expr_kind(&self,
+                       expr: &'gcx hir::Expr,
+                       expected: Expectation<'tcx>,
+                       lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let tcx = self.tcx;
         let id = expr.id;
-        let ty = match expr.node {
+        match expr.node {
           hir::ExprBox(ref subexpr) => {
             let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
                 match ty.sty {
@@ -3723,25 +3748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   }
               }
            }
-        };
-        self.write_ty(id, ty);
-
-        debug!("type of expr({}) {} is...", expr.id,
-               pprust::expr_to_string(expr));
-        debug!("... {:?}, expected is {:?}",
-               ty,
-               expected);
-
-        // Add adjustments to !-expressions
-        if ty.is_never() {
-            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(id) {
-                let adj_ty = self.next_diverging_ty_var();
-                let adj = adjustment::AdjustNeverToAny(adj_ty);
-                self.write_adjustment(id, adj);
-                return adj_ty;
-            }
         }
-        ty
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.

From 8c6086a0a3f0de3cd31b01eb223d36cd15314d6f Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 14:41:25 +0800
Subject: [PATCH 547/768] check_block_with_expected returns the checked type

---
 src/librustc_typeck/check/mod.rs | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3fbfd2aedb466..79dd951a5d85e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2850,8 +2850,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
-        self.check_block_with_expected(then_blk, expected);
-        let then_ty = self.node_ty(then_blk.id);
+        let then_ty = self.check_block_with_expected(then_blk, expected);
 
         let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
@@ -3542,8 +3541,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
-            self.check_block_with_expected(&b, expected);
-            self.node_ty(b.id)
+            self.check_block_with_expected(&b, expected)
           }
           hir::ExprCall(ref callee, ref args) => {
               self.check_call(expr, &callee, &args[..], expected)
@@ -3911,8 +3909,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_block_no_value(&self, blk: &'gcx hir::Block)  {
-        self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
-        let blkty = self.node_ty(blk.id);
+        let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
         if blkty.references_error() {
             self.write_error(blk.id);
         } else {
@@ -3923,7 +3920,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     fn check_block_with_expected(&self,
                                  blk: &'gcx hir::Block,
-                                 expected: Expectation<'tcx>) {
+                                 expected: Expectation<'tcx>) -> Ty<'tcx> {
         let prev = {
             let mut fcx_ps = self.ps.borrow_mut();
             let unsafety_state = fcx_ps.recurse(blk);
@@ -3960,13 +3957,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                            s_ty.is_never();
             any_err = any_err || s_ty.references_error();
         }
-        match blk.expr {
+        let ty = match blk.expr {
             None => if any_err {
-                self.write_error(blk.id);
+                self.tcx.types.err
             } else if any_diverges {
-                self.write_ty(blk.id, self.next_diverging_ty_var());
+                self.next_diverging_ty_var()
             } else {
-                self.write_nil(blk.id);
+                self.tcx.mk_nil()
             },
             Some(ref e) => {
                 if any_diverges && !warned {
@@ -3988,16 +3985,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
 
                 if any_err {
-                    self.write_error(blk.id);
+                    self.tcx.types.err
                 } else if any_diverges {
-                    self.write_ty(blk.id, self.next_diverging_ty_var());
+                    self.next_diverging_ty_var()
                 } else {
-                    self.write_ty(blk.id, ety);
+                    ety
                 }
             }
         };
+        self.write_ty(blk.id, ty);
 
         *self.ps.borrow_mut() = prev;
+        ty
     }
 
     // Instantiates the given path, which must refer to an item with the given

From c5ff28cd14bf90b45f97d370538d792693036b27 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sat, 27 Aug 2016 20:06:47 +0800
Subject: [PATCH 548/768] Factor write_ty out of pattern-matching functions

---
 src/librustc_typeck/check/_match.rs | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 763e92b69baf0..35d77e8c2adeb 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -54,8 +54,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                self.write_ty(pat.id, pat_ty);
-
                 // somewhat surprising: in this case, the subtyping
                 // relation goes the opposite way as the other
                 // cases. Actually what we really want is not a subtyping
@@ -69,6 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 //
                 // that's equivalent to there existing a LUB.
                 self.demand_suptype(pat.span, expected, pat_ty);
+                self.write_ty(pat.id, pat_ty);
             }
             PatKind::Range(ref begin, ref end) => {
                 let lhs_ty = self.check_expr(begin);
@@ -101,11 +100,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // it to type the entire expression.
                 let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
 
-                self.write_ty(pat.id, common_type);
-
                 // subtyping doesn't matter here, as the value is some kind of scalar
                 self.demand_eqtype(pat.span, expected, lhs_ty);
                 self.demand_eqtype(pat.span, expected, rhs_ty);
+                self.write_ty(pat.id, common_type);
             }
             PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
@@ -132,8 +130,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                self.write_ty(pat.id, typ);
-
                 // if there are multiple arms, make sure they all agree on
                 // what the type of the binding `x` ought to be
                 match tcx.expect_def(pat.id) {
@@ -150,6 +146,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let Some(ref p) = *sub {
                     self.check_pat(&p, expected);
                 }
+
+                self.write_ty(pat.id, typ);
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
                 self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
@@ -174,11 +172,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect();
                 let pat_ty = tcx.mk_tup(element_tys.clone());
-                self.write_ty(pat.id, pat_ty);
                 self.demand_eqtype(pat.span, expected, pat_ty);
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                     self.check_pat(elem, &element_tys[i]);
                 }
+                self.write_ty(pat.id, pat_ty);
             }
             PatKind::Box(ref inner) => {
                 let inner_ty = self.next_ty_var();
@@ -189,11 +187,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // think any errors can be introduced by using
                     // `demand::eqtype`.
                     self.demand_eqtype(pat.span, expected, uniq_ty);
-                    self.write_ty(pat.id, uniq_ty);
                     self.check_pat(&inner, inner_ty);
+                    self.write_ty(pat.id, uniq_ty);
                 } else {
-                    self.write_error(pat.id);
                     self.check_pat(&inner, tcx.types.err);
+                    self.write_error(pat.id);
                 }
             }
             PatKind::Ref(ref inner, mutbl) => {
@@ -221,11 +219,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     };
 
-                    self.write_ty(pat.id, rptr_ty);
                     self.check_pat(&inner, inner_ty);
+                    self.write_ty(pat.id, rptr_ty);
                 } else {
-                    self.write_error(pat.id);
                     self.check_pat(&inner, tcx.types.err);
+                    self.write_error(pat.id);
                 }
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
@@ -277,8 +275,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                self.write_ty(pat.id, expected_ty);
-
                 for elt in before {
                     self.check_pat(&elt, inner_ty);
                 }
@@ -288,6 +284,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for elt in after {
                     self.check_pat(&elt, inner_ty);
                 }
+                self.write_ty(pat.id, expected_ty);
             }
         }
 

From 1749fda9c04fdb051c82904b522eb79697bbf1c0 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sat, 27 Aug 2016 20:34:37 +0800
Subject: [PATCH 549/768] Factor write_ty out of more pattern-checking
 functions

---
 src/librustc_typeck/check/_match.rs | 42 ++++++++++++++---------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 35d77e8c2adeb..ee66597e72a46 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -150,14 +150,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.write_ty(pat.id, typ);
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
-                self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
+                let pat_ty = self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
+                write_ty(pat.id, pat_ty);
             }
             PatKind::Path(ref opt_qself, ref path) => {
                 let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
-                self.check_pat_path(pat, opt_qself_ty, path, expected);
+                let pat_ty = self.check_pat_path(pat, opt_qself_ty, path, expected);
+                write_ty(pat.id, pat_ty);
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                self.check_pat_struct(pat, path, fields, etc, expected);
+                let pat_ty = self.check_pat_struct(pat, path, fields, etc, expected);
+                write_ty(pat.id, pat_ty);
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -481,40 +484,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         path: &hir::Path,
                         fields: &'gcx [Spanned],
                         etc: bool,
-                        expected: Ty<'tcx>)
+                        expected: Ty<'tcx>) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
                                                                                  pat.span) {
             variant_ty
         } else {
-            self.write_error(pat.id);
             for field in fields {
                 self.check_pat(&field.node.pat, self.tcx.types.err);
             }
-            return;
+            return tcx.types.err;
         };
-        self.write_ty(pat.id, pat_ty);
 
         // Type check the path.
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
         self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
+        pat_ty
     }
 
     fn check_pat_path(&self,
                       pat: &hir::Pat,
                       opt_self_ty: Option>,
                       path: &hir::Path,
-                      expected: Ty<'tcx>)
+                      expected: Ty<'tcx>) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let report_unexpected_def = || {
             span_err!(tcx.sess, pat.span, E0533,
                       "`{}` does not name a unit variant, unit struct or a constant",
                       pprust::path_to_string(path));
-            self.write_error(pat.id);
         };
 
         // Resolve the path and check the definition for errors.
@@ -523,18 +524,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match def {
             Def::Err => {
                 self.set_tainted_by_errors();
-                self.write_error(pat.id);
-                return;
+                return tcx.types.err;
             }
             Def::Method(..) => {
                 report_unexpected_def();
-                return;
+                return tcx.types.err;
             }
             Def::Variant(..) | Def::Struct(..) => {
                 let variant = tcx.expect_variant_def(def);
                 if variant.kind != VariantKind::Unit {
                     report_unexpected_def();
-                    return;
+                    return tcx.types.err;
                 }
             }
             Def::Const(..) | Def::AssociatedConst(..) => {} // OK
@@ -543,8 +543,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
-        self.write_ty(pat.id, pat_ty);
         self.demand_suptype(pat.span, expected, pat_ty);
+        pat_ty
     }
 
     fn check_pat_tuple_struct(&self,
@@ -552,11 +552,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               path: &hir::Path,
                               subpats: &'gcx [P],
                               ddpos: Option,
-                              expected: Ty<'tcx>)
+                              expected: Ty<'tcx>) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let on_error = || {
-            self.write_error(pat.id);
             for pat in subpats {
                 self.check_pat(&pat, tcx.types.err);
             }
@@ -580,11 +579,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::Err => {
                 self.set_tainted_by_errors();
                 on_error();
-                return;
+                return tcx.types.err;
             }
             Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
                 report_unexpected_def(false);
-                return;
+                return tcx.types.err;
             }
             Def::Variant(..) | Def::Struct(..) => {
                 tcx.expect_variant_def(def)
@@ -597,13 +596,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             report_unexpected_def(true);
         } else if variant.kind != VariantKind::Tuple {
             report_unexpected_def(false);
-            return;
+            return tcx.types.err;
         }
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
-        self.write_ty(pat.id, pat_ty);
-
         let pat_ty = if pat_ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
             tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap()
@@ -611,7 +608,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Leave the type as is for unit structs (backward compatibility).
             pat_ty
         };
-        self.write_ty(pat.id, pat_ty);
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
@@ -644,7 +640,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                variant.fields.len(), fields_ending, subpats.len()))
                 .emit();
             on_error();
+            return tcx.types.err;
         }
+        pat_ty
     }
 
     fn check_struct_pat_fields(&self,

From bd661481e79bb5701455b03d8d3b587309e56186 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sat, 27 Aug 2016 20:38:06 +0800
Subject: [PATCH 550/768] Move write_ty to the bottom of check_pat

---
 src/librustc_typeck/check/_match.rs | 37 ++++++++++++++---------------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index ee66597e72a46..c1a0a6f70aa44 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -32,9 +32,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_pat(pat={:?},expected={:?})", pat, expected);
 
-        match pat.node {
+        let ty = match pat.node {
             PatKind::Wild => {
-                self.write_ty(pat.id, expected);
+                expected
             }
             PatKind::Lit(ref lt) => {
                 let ty = self.check_expr(<);
@@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 //
                 // that's equivalent to there existing a LUB.
                 self.demand_suptype(pat.span, expected, pat_ty);
-                self.write_ty(pat.id, pat_ty);
+                pat_ty
             }
             PatKind::Range(ref begin, ref end) => {
                 let lhs_ty = self.check_expr(begin);
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // subtyping doesn't matter here, as the value is some kind of scalar
                 self.demand_eqtype(pat.span, expected, lhs_ty);
                 self.demand_eqtype(pat.span, expected, rhs_ty);
-                self.write_ty(pat.id, common_type);
+                common_type
             }
             PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
@@ -147,20 +147,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.check_pat(&p, expected);
                 }
 
-                self.write_ty(pat.id, typ);
+                typ
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
-                let pat_ty = self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
-                write_ty(pat.id, pat_ty);
+                self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected)
             }
             PatKind::Path(ref opt_qself, ref path) => {
                 let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
-                let pat_ty = self.check_pat_path(pat, opt_qself_ty, path, expected);
-                write_ty(pat.id, pat_ty);
+                self.check_pat_path(pat, opt_qself_ty, path, expected)
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                let pat_ty = self.check_pat_struct(pat, path, fields, etc, expected);
-                write_ty(pat.id, pat_ty);
+                self.check_pat_struct(pat, path, fields, etc, expected)
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -179,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                     self.check_pat(elem, &element_tys[i]);
                 }
-                self.write_ty(pat.id, pat_ty);
+                pat_ty
             }
             PatKind::Box(ref inner) => {
                 let inner_ty = self.next_ty_var();
@@ -191,10 +188,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // `demand::eqtype`.
                     self.demand_eqtype(pat.span, expected, uniq_ty);
                     self.check_pat(&inner, inner_ty);
-                    self.write_ty(pat.id, uniq_ty);
+                    uniq_ty
                 } else {
                     self.check_pat(&inner, tcx.types.err);
-                    self.write_error(pat.id);
+                    tcx.types.err
                 }
             }
             PatKind::Ref(ref inner, mutbl) => {
@@ -223,10 +220,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     };
 
                     self.check_pat(&inner, inner_ty);
-                    self.write_ty(pat.id, rptr_ty);
+                    rptr_ty
                 } else {
                     self.check_pat(&inner, tcx.types.err);
-                    self.write_error(pat.id);
+                    tcx.types.err
                 }
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
@@ -287,9 +284,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for elt in after {
                     self.check_pat(&elt, inner_ty);
                 }
-                self.write_ty(pat.id, expected_ty);
+                expected_ty
             }
-        }
+        };
+
+        self.write_ty(pat.id, ty);
 
         // (*) In most of the cases above (literals and constants being
         // the exception), we relate types using strict equality, evewn
@@ -494,7 +493,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             for field in fields {
                 self.check_pat(&field.node.pat, self.tcx.types.err);
             }
-            return tcx.types.err;
+            return self.tcx.types.err;
         };
 
         // Type check the path.

From 180534f398b18aea5d7740153eab026074396013 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sun, 28 Aug 2016 16:17:52 +0800
Subject: [PATCH 551/768] Remove use of expr_ty from coercions code

---
 src/librustc_typeck/check/_match.rs   | 10 +++++++---
 src/librustc_typeck/check/cast.rs     |  4 ++--
 src/librustc_typeck/check/coercion.rs | 22 +++++++++++++---------
 src/librustc_typeck/check/demand.rs   |  6 +++---
 src/librustc_typeck/check/mod.rs      | 21 ++++++++++++---------
 5 files changed, 37 insertions(+), 26 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index c1a0a6f70aa44..42769a8636407 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -419,11 +419,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             _ => result_ty
         };
+
+        let mut arm_tys = Vec::new();
         for (i, arm) in arms.iter().enumerate() {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
+            arm_tys.push(arm_ty);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
@@ -453,10 +456,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     })
             } else if i == 0 {
                 // Special-case the first arm, as it has no "previous expressions".
-                self.try_coerce(&arm.body, coerce_first)
+                self.try_coerce(&arm.body, arm_ty, coerce_first)
             } else {
-                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
-                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
+                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body)
+                                            .zip(arm_tys.iter().cloned());
+                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
             };
 
             result_ty = match result {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 1fda38d8a3305..0c9da86563ab2 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             (None, Some(t_cast)) => {
                 if let ty::TyFnDef(.., f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
-                    let res = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f));
+                    let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f));
                     if !res.is_ok() {
                         return Err(CastError::NonScalar);
                     }
@@ -471,7 +471,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
     }
 
     fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
-        fcx.try_coerce(self.expr, self.cast_ty).is_ok()
+        fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
     }
 
 }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 60ca9309eea00..263a83389ea9d 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -630,9 +630,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// The expressions *must not* have any pre-existing adjustments.
     pub fn try_coerce(&self,
                       expr: &hir::Expr,
+                      expr_ty: Ty<'tcx>,
                       target: Ty<'tcx>)
                       -> RelateResult<'tcx, Ty<'tcx>> {
-        let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+        let source = self.resolve_type_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
@@ -658,14 +659,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            origin: TypeOrigin,
                                            exprs: E,
                                            prev_ty: Ty<'tcx>,
-                                           new: &'b hir::Expr)
+                                           new: &'b hir::Expr,
+                                           new_ty: Ty<'tcx>)
                                            -> RelateResult<'tcx, Ty<'tcx>>
         // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
         where E: Fn() -> I,
-              I: IntoIterator {
+              I: IntoIterator)> {
 
         let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
-        let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
+        let new_ty = self.resolve_type_vars_with_obligations(new_ty);
         debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
 
         let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
@@ -701,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 // Reify both sides and return the reified fn pointer type.
-                for expr in exprs().into_iter().chain(Some(new)) {
+                for (expr, _) in exprs().into_iter().chain(Some((new, new_ty))) {
                     // No adjustments can produce a fn item, so this should never trip.
                     assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                     self.write_adjustment(expr.id, AdjustReifyFnPointer);
@@ -735,13 +737,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Then try to coerce the previous expressions to the type of the new one.
         // This requires ensuring there are no coercions applied to *any* of the
         // previous expressions, other than noop reborrows (ignoring lifetimes).
-        for expr in exprs() {
+        for (expr, expr_ty) in exprs() {
             let noop = match self.tables.borrow().adjustments.get(&expr.id) {
                 Some(&AdjustDerefRef(AutoDerefRef {
                     autoderefs: 1,
                     autoref: Some(AutoPtr(_, mutbl_adj)),
                     unsize: None
-                })) => match self.expr_ty(expr).sty {
+                })) => match expr_ty.sty {
                     ty::TyRef(_, mt_orig) => {
                         // Reborrow that we can safely ignore.
                         mutbl_adj == mt_orig.mutbl
@@ -765,7 +767,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
+        match self.commit_if_ok(|_| apply(&mut coerce,
+                                          &|| exprs().into_iter().map(|(e, _)| e),
+                                          prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
                 if let Some(e) = first_error {
@@ -783,7 +787,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
-                    for expr in exprs() {
+                    for (expr, _) in exprs() {
                         let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
                         if let Some(AdjustNeverToAny(_)) = previous {
                             self.write_adjustment(expr.id, AdjustNeverToAny(ty));
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 1f3a83ebc1d56..d622bc7f751d7 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -53,11 +53,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Checks that the type of `expr` can be coerced to `expected`.
-    pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
+    pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
         let expected = self.resolve_type_vars_with_obligations(expected);
-        if let Err(e) = self.try_coerce(expr, expected) {
+        if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
             let origin = TypeOrigin::Misc(expr.span);
-            let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+            let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
             self.report_mismatched_types(origin, expected, expr_ty, e);
         }
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 79dd951a5d85e..b128333921356 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2567,13 +2567,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         Expectation::rvalue_hint(self, ty)
                     });
 
-                    self.check_expr_with_expectation(&arg,
-                        expected.unwrap_or(ExpectHasType(formal_ty)));
+                    let checked_ty = self.check_expr_with_expectation(&arg,
+                                            expected.unwrap_or(ExpectHasType(formal_ty)));
                     // 2. Coerce to the most detailed type that could be coerced
                     //    to, which is `expected_ty` if `rvalue_hint` returns an
                     //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
                     let coerce_ty = expected.and_then(|e| e.only_has_type(self));
-                    self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty));
+                    self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
 
                     // 3. Relate the expected type and the formal one,
                     //    if the expected type was used for the coercion.
@@ -2715,7 +2715,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     expr: &'gcx hir::Expr,
                                     expected: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.check_expr_with_hint(expr, expected);
-        self.demand_coerce(expr, expected);
+        self.demand_coerce(expr, ty, expected);
         ty
     }
 
@@ -2861,8 +2861,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
             let result = if let Some(ref then) = then_blk.expr {
-                let res = self.try_find_coercion_lub(origin, || Some(&**then),
-                                                     then_ty, else_expr);
+                let res = self.try_find_coercion_lub(origin, || Some((&**then, then_ty)),
+                                                     then_ty, else_expr, else_ty);
 
                 // In case we did perform an adjustment, we have to update
                 // the type of the block, because old trans still uses it.
@@ -3594,16 +3594,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let mut unified = self.next_ty_var();
             let coerce_to = uty.unwrap_or(unified);
 
+            let mut arg_tys = Vec::new();
             for (i, e) in args.iter().enumerate() {
                 let e_ty = self.check_expr_with_hint(e, coerce_to);
+                arg_tys.push(e_ty);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
                 let result = if i == 0 {
-                    self.try_coerce(e, coerce_to)
+                    self.try_coerce(e, e_ty, coerce_to)
                 } else {
-                    let prev_elems = || args[..i].iter().map(|e| &**e);
-                    self.try_find_coercion_lub(origin, prev_elems, unified, e)
+                    let prev_elems = || args[..i].iter().map(|e| &**e)
+                                                 .zip(arg_tys.iter().cloned());
+                    self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
                 };
 
                 match result {

From 7c8f5457d26055b26210fdd69c5ded1ecdde144a Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sun, 28 Aug 2016 17:29:54 +0800
Subject: [PATCH 552/768] Undo unnecessary bookkeeping from last commit

---
 src/librustc_typeck/check/_match.rs   |  5 +----
 src/librustc_typeck/check/coercion.rs | 14 ++++++--------
 src/librustc_typeck/check/mod.rs      |  7 ++-----
 3 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 42769a8636407..c67b98761aa6e 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -420,13 +420,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             _ => result_ty
         };
 
-        let mut arm_tys = Vec::new();
         for (i, arm) in arms.iter().enumerate() {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
-            arm_tys.push(arm_ty);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
@@ -458,8 +456,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // Special-case the first arm, as it has no "previous expressions".
                 self.try_coerce(&arm.body, arm_ty, coerce_first)
             } else {
-                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body)
-                                            .zip(arm_tys.iter().cloned());
+                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
                 self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
             };
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 263a83389ea9d..98a05989b140d 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -664,7 +664,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            -> RelateResult<'tcx, Ty<'tcx>>
         // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
         where E: Fn() -> I,
-              I: IntoIterator)> {
+              I: IntoIterator {
 
         let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
         let new_ty = self.resolve_type_vars_with_obligations(new_ty);
@@ -703,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 // Reify both sides and return the reified fn pointer type.
-                for (expr, _) in exprs().into_iter().chain(Some((new, new_ty))) {
+                for expr in exprs().into_iter().chain(Some(new)) {
                     // No adjustments can produce a fn item, so this should never trip.
                     assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                     self.write_adjustment(expr.id, AdjustReifyFnPointer);
@@ -737,13 +737,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Then try to coerce the previous expressions to the type of the new one.
         // This requires ensuring there are no coercions applied to *any* of the
         // previous expressions, other than noop reborrows (ignoring lifetimes).
-        for (expr, expr_ty) in exprs() {
+        for expr in exprs() {
             let noop = match self.tables.borrow().adjustments.get(&expr.id) {
                 Some(&AdjustDerefRef(AutoDerefRef {
                     autoderefs: 1,
                     autoref: Some(AutoPtr(_, mutbl_adj)),
                     unsize: None
-                })) => match expr_ty.sty {
+                })) => match self.node_ty(expr.id).sty {
                     ty::TyRef(_, mt_orig) => {
                         // Reborrow that we can safely ignore.
                         mutbl_adj == mt_orig.mutbl
@@ -767,9 +767,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        match self.commit_if_ok(|_| apply(&mut coerce,
-                                          &|| exprs().into_iter().map(|(e, _)| e),
-                                          prev_ty, new_ty)) {
+        match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
                 if let Some(e) = first_error {
@@ -787,7 +785,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
-                    for (expr, _) in exprs() {
+                    for expr in exprs() {
                         let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
                         if let Some(AdjustNeverToAny(_)) = previous {
                             self.write_adjustment(expr.id, AdjustNeverToAny(ty));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b128333921356..1e57cc5d6c847 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2861,7 +2861,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
             let result = if let Some(ref then) = then_blk.expr {
-                let res = self.try_find_coercion_lub(origin, || Some((&**then, then_ty)),
+                let res = self.try_find_coercion_lub(origin, || Some(&**then),
                                                      then_ty, else_expr, else_ty);
 
                 // In case we did perform an adjustment, we have to update
@@ -3594,18 +3594,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let mut unified = self.next_ty_var();
             let coerce_to = uty.unwrap_or(unified);
 
-            let mut arg_tys = Vec::new();
             for (i, e) in args.iter().enumerate() {
                 let e_ty = self.check_expr_with_hint(e, coerce_to);
-                arg_tys.push(e_ty);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
                 let result = if i == 0 {
                     self.try_coerce(e, e_ty, coerce_to)
                 } else {
-                    let prev_elems = || args[..i].iter().map(|e| &**e)
-                                                 .zip(arg_tys.iter().cloned());
+                    let prev_elems = || args[..i].iter().map(|e| &**e);
                     self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
                 };
 

From c9a340e546ac2c708d6f334a83cfbf6a38810255 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sun, 28 Aug 2016 19:37:57 +0800
Subject: [PATCH 553/768] Remove expr_ty method completely

---
 src/librustc_typeck/check/method/confirm.rs |  8 ++++----
 src/librustc_typeck/check/mod.rs            | 13 -------------
 2 files changed, 4 insertions(+), 17 deletions(-)

diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index dbf74e371df45..ab59fafb65209 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -472,7 +472,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                    i, expr, autoderef_count);
 
             if autoderef_count > 0 {
-                let mut autoderef = self.autoderef(expr.span, self.expr_ty(expr));
+                let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
                 autoderef.nth(autoderef_count).unwrap_or_else(|| {
                     span_bug!(expr.span, "expr was deref-able {} times but now isn't?",
                               autoderef_count);
@@ -532,7 +532,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                 unsize: None
                             }))), false)
                     };
-                    let index_expr_ty = self.expr_ty(&index_expr);
+                    let index_expr_ty = self.node_ty(index_expr.id);
 
                     let result = self.try_index_step(
                         ty::MethodCall::expr(expr.id),
@@ -547,7 +547,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     if let Some((input_ty, return_ty)) = result {
                         self.demand_suptype(index_expr.span, input_ty, index_expr_ty);
 
-                        let expr_ty = self.expr_ty(&expr);
+                        let expr_ty = self.node_ty(expr.id);
                         self.demand_suptype(expr.span, expr_ty, return_ty);
                     }
                 }
@@ -558,7 +558,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     if self.tables.borrow().method_map.contains_key(&method_call) {
                         let method = self.try_overloaded_deref(expr.span,
                             Some(&base_expr),
-                            self.expr_ty(&base_expr),
+                            self.node_ty(base_expr.id),
                             PreferMutLvalue);
                         let method = method.expect("re-trying deref failed");
                         self.tables.borrow_mut().method_map.insert(method_call, method);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1e57cc5d6c847..00fdcd59f7cee 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1763,19 +1763,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         t
     }
 
-    pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
-        if let Some(&adjustment::AdjustNeverToAny(ref t))
-                = self.tables.borrow().adjustments.get(&ex.id) {
-            return t;
-        }
-        match self.tables.borrow().node_types.get(&ex.id) {
-            Some(&t) => t,
-            None => {
-                bug!("no type for expr in fcx {}", self.tag());
-            }
-        }
-    }
-
     /// Apply `adjustment` to the type of `expr`
     pub fn adjust_expr_ty(&self,
                           expr: &hir::Expr,

From e1e5c14bad0e8989523cf5974d98a8257badb88d Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Wed, 31 Aug 2016 09:02:45 +0000
Subject: [PATCH 554/768] In `Parser` and `ExtCtxt`, replace fields `filename`
 and `mod_path_stack` with a single field `directory: PathBuf`.

---
 src/libsyntax/ext/base.rs           |  7 ++---
 src/libsyntax/ext/expand.rs         | 43 ++++++++++++-----------------
 src/libsyntax/ext/tt/macro_rules.rs |  3 +-
 src/libsyntax/parse/parser.rs       | 42 +++++++++++-----------------
 4 files changed, 38 insertions(+), 57 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 3b1c01319c492..b2e4aeabd9531 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -30,6 +30,7 @@ use fold::Folder;
 use feature_gate;
 
 use std::collections::{HashMap, HashSet};
+use std::path::PathBuf;
 use std::rc::Rc;
 use tokenstream;
 
@@ -602,8 +603,7 @@ pub struct ExtCtxt<'a> {
     pub derive_modes: HashMap>,
     pub recursion_count: usize,
 
-    pub filename: Option,
-    pub mod_path_stack: Vec,
+    pub directory: PathBuf,
     pub in_block: bool,
 }
 
@@ -626,8 +626,7 @@ impl<'a> ExtCtxt<'a> {
             derive_modes: HashMap::new(),
             recursion_count: 0,
 
-            filename: None,
-            mod_path_stack: Vec::new(),
+            directory: PathBuf::new(),
             in_block: false,
         }
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d06b77a5b0549..5c548533e937f 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -28,6 +28,8 @@ use visit;
 use visit::Visitor;
 use std_inject;
 
+use std::path::PathBuf;
+
 // A trait for AST nodes and AST node lists into which macro invocations may expand.
 trait MacroGenerable: Sized {
     // Expand the given MacResult using its appropriate `make_*` method.
@@ -566,7 +568,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_crate(&mut self, c: Crate) -> Crate {
-        self.cx.filename = Some(self.cx.parse_sess.codemap().span_to_filename(c.span));
+        let mut directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(c.span));
+        directory.pop();
+        self.cx.directory = directory;
         noop_fold_crate(c, self)
     }
 
@@ -591,18 +595,22 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let result;
         if let ast::ItemKind::Mod(ast::Mod { inner, .. }) = item.node {
             if item.span.contains(inner) {
-                self.push_mod_path(item.ident, &item.attrs);
+                let directory = self.cx.directory.clone();
+                self.cx.directory.push(&*{
+                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
+                        .unwrap_or(item.ident.name.as_str())
+                });
                 result = expand_item(item, self);
-                self.pop_mod_path();
+                self.cx.directory = directory;
             } else {
-                let filename = if inner != syntax_pos::DUMMY_SP {
-                    Some(self.cx.parse_sess.codemap().span_to_filename(inner))
-                } else { None };
-                let orig_filename = replace(&mut self.cx.filename, filename);
-                let orig_mod_path_stack = replace(&mut self.cx.mod_path_stack, Vec::new());
+                let mut directory = match inner {
+                    syntax_pos::DUMMY_SP => PathBuf::new(),
+                    _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
+                };
+                directory.pop();
+                let directory = replace(&mut self.cx.directory, directory);
                 result = expand_item(item, self);
-                self.cx.filename = orig_filename;
-                self.cx.mod_path_stack = orig_mod_path_stack;
+                self.cx.directory = directory;
             }
         } else {
             result = expand_item(item, self);
@@ -636,21 +644,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
-impl<'a, 'b> MacroExpander<'a, 'b> {
-    fn push_mod_path(&mut self, id: Ident, attrs: &[ast::Attribute]) {
-        let default_path = id.name.as_str();
-        let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
-            Some(d) => d,
-            None => default_path,
-        };
-        self.cx.mod_path_stack.push(file_path)
-    }
-
-    fn pop_mod_path(&mut self) {
-        self.cx.mod_path_stack.pop().unwrap();
-    }
-}
-
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index d197741e9a367..a4be84dfbf02f 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -211,8 +211,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                                            imported_from,
                                            rhs);
                 let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
-                p.filename = cx.filename.clone();
-                p.mod_path_stack = cx.mod_path_stack.clone();
+                p.directory = cx.directory.clone();
                 p.restrictions = match cx.in_block {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ec9dc1bae5ad9..6a0e40edded59 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -264,8 +264,7 @@ pub struct Parser<'a> {
     /// extra detail when the same error is seen twice
     pub obsolete_set: HashSet,
     /// Used to determine the path to externally loaded source files
-    pub filename: Option,
-    pub mod_path_stack: Vec,
+    pub directory: PathBuf,
     /// Stack of open delimiters and their spans. Used for error message.
     pub open_braces: Vec<(token::DelimToken, Span)>,
     /// Flag if this parser "owns" the directory that it is currently parsing
@@ -346,9 +345,11 @@ impl<'a> Parser<'a> {
     {
         let tok0 = rdr.real_token();
         let span = tok0.sp;
-        let filename = if span != syntax_pos::DUMMY_SP {
-            Some(sess.codemap().span_to_filename(span))
-        } else { None };
+        let mut directory = match span {
+            syntax_pos::DUMMY_SP => PathBuf::new(),
+            _ => PathBuf::from(sess.codemap().span_to_filename(span)),
+        };
+        directory.pop();
         let placeholder = TokenAndSpan {
             tok: token::Underscore,
             sp: span,
@@ -377,8 +378,7 @@ impl<'a> Parser<'a> {
             quote_depth: 0,
             parsing_token_tree: false,
             obsolete_set: HashSet::new(),
-            mod_path_stack: Vec::new(),
-            filename: filename,
+            directory: directory,
             open_braces: Vec::new(),
             owns_directory: true,
             root_module_name: None,
@@ -5306,27 +5306,24 @@ impl<'a> Parser<'a> {
             let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?;
             Ok((id, m, Some(attrs)))
         } else {
-            self.push_mod_path(id, &outer_attrs);
+            let directory = self.directory.clone();
+            self.push_directory(id, &outer_attrs);
             self.expect(&token::OpenDelim(token::Brace))?;
             let mod_inner_lo = self.span.lo;
             let attrs = self.parse_inner_attributes()?;
             let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
-            self.pop_mod_path();
+            self.directory = directory;
             Ok((id, ItemKind::Mod(m), Some(attrs)))
         }
     }
 
-    fn push_mod_path(&mut self, id: Ident, attrs: &[Attribute]) {
+    fn push_directory(&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") {
             Some(d) => d,
             None => default_path,
         };
-        self.mod_path_stack.push(file_path)
-    }
-
-    fn pop_mod_path(&mut self) {
-        self.mod_path_stack.pop().unwrap();
+        self.directory.push(&*file_path)
     }
 
     pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option {
@@ -5374,18 +5371,11 @@ impl<'a> Parser<'a> {
                    id: ast::Ident,
                    outer_attrs: &[ast::Attribute],
                    id_sp: Span) -> PResult<'a, ModulePathSuccess> {
-        let mut prefix = PathBuf::from(self.filename.as_ref().unwrap());
-        prefix.pop();
-        let mut dir_path = prefix;
-        for part in &self.mod_path_stack {
-            dir_path.push(&**part);
-        }
-
-        if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &dir_path) {
+        if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &self.directory) {
             return Ok(ModulePathSuccess { path: p, owns_directory: true });
         }
 
-        let paths = Parser::default_submod_path(id, &dir_path, self.sess.codemap());
+        let paths = Parser::default_submod_path(id, &self.directory, self.sess.codemap());
 
         if self.restrictions.contains(Restrictions::NO_NONINLINE_MOD) {
             let msg =
@@ -5400,8 +5390,8 @@ impl<'a> Parser<'a> {
         } else if !self.owns_directory {
             let mut err = self.diagnostic().struct_span_err(id_sp,
                 "cannot declare a new module at this location");
-            let this_module = match self.mod_path_stack.last() {
-                Some(name) => name.to_string(),
+            let this_module = match self.directory.file_name() {
+                Some(file_name) => file_name.to_str().unwrap().to_owned(),
                 None => self.root_module_name.as_ref().unwrap().clone(),
             };
             err.span_note(id_sp,

From 234d68b7d35687999c36bc39ffd414bca7373a48 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Tue, 30 Aug 2016 07:05:25 +0000
Subject: [PATCH 555/768] Improve `expand_type`.

---
 src/libsyntax/ext/expand.rs | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5c548533e937f..6f8af66632f04 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -489,14 +489,17 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
 }
 
 pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
-    let t = match t.node.clone() {
+    let t = match t.node {
+        ast::TyKind::Mac(_) => t.unwrap(),
+        _ => return fold::noop_fold_ty(t, fld),
+    };
+
+    match t.node {
         ast::TyKind::Mac(mac) => {
             expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
         }
-        _ => t
-    };
-
-    fold::noop_fold_ty(t, fld)
+        _ => unreachable!(),
+    }
 }
 
 /// A tree-folder that performs macro expansion

From 9b3bc7a9e9e35537823bc2a10fc078c1222ee7fd Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Wed, 31 Aug 2016 23:39:16 +0000
Subject: [PATCH 556/768] Remove `syntax::config::strip_unconfigured`, add
 `syntax::config::features`.

---
 src/librustc_driver/driver.rs | 20 +++--------
 src/libsyntax/config.rs       | 63 +++++++++++++++++++----------------
 src/libsyntax/ext/expand.rs   |  5 +--
 3 files changed, 41 insertions(+), 47 deletions(-)

diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 065ef9e0ce15f..8ed5b579ffc3f 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -551,7 +551,7 @@ pub struct ExpansionResult<'a> {
 /// Returns `None` if we're aborting after handling -W help.
 pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                            cstore: &CStore,
-                                           mut krate: ast::Crate,
+                                           krate: ast::Crate,
                                            registry: Option,
                                            crate_name: &'a str,
                                            addl_plugins: Option>,
@@ -562,21 +562,9 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
 {
     let time_passes = sess.time_passes();
 
-    // strip before anything else because crate metadata may use #[cfg_attr]
-    // and so macros can depend on configuration variables, such as
-    //
-    //   #[macro_use] #[cfg(foo)]
-    //   mod bar { macro_rules! baz!(() => {{}}) }
-    //
-    // baz! should not use this definition unless foo is enabled.
-
-    krate = time(time_passes, "configuration", || {
-        let (krate, features) =
-            syntax::config::strip_unconfigured_items(krate, &sess.parse_sess, sess.opts.test);
-        // these need to be set "early" so that expansion sees `quote` if enabled.
-        *sess.features.borrow_mut() = features;
-        krate
-    });
+    let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test);
+    // these need to be set "early" so that expansion sees `quote` if enabled.
+    *sess.features.borrow_mut() = features;
 
     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
     *sess.crate_disambiguator.borrow_mut() =
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 69a979176521b..7f6395997abe1 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -10,7 +10,6 @@
 
 use attr::HasAttrs;
 use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
-use fold::Folder;
 use {fold, attr};
 use ast;
 use codemap::{Spanned, respan};
@@ -27,6 +26,40 @@ pub struct StripUnconfigured<'a> {
     pub features: Option<&'a Features>,
 }
 
+// `cfg_attr`-process the crate's attributes and compute the crate's features.
+pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
+                -> (ast::Crate, Features) {
+    let features;
+    {
+        let mut strip_unconfigured = StripUnconfigured {
+            config: &krate.config.clone(),
+            should_test: should_test,
+            sess: sess,
+            features: None,
+        };
+
+        let unconfigured_attrs = krate.attrs.clone();
+        let err_count = sess.span_diagnostic.err_count();
+        if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
+            krate.attrs = attrs;
+        } else { // the entire crate is unconfigured
+            krate.attrs = Vec::new();
+            krate.module.items = Vec::new();
+            return (krate, Features::new());
+        }
+
+        features = get_features(&sess.span_diagnostic, &krate.attrs);
+
+        // Avoid reconfiguring malformed `cfg_attr`s
+        if err_count == sess.span_diagnostic.err_count() {
+            strip_unconfigured.features = Some(&features);
+            strip_unconfigured.configure(unconfigured_attrs);
+        }
+    }
+
+    (krate, features)
+}
+
 impl<'a> StripUnconfigured<'a> {
     fn configure(&mut self, node: T) -> Option {
         let node = self.process_cfg_attrs(node);
@@ -125,34 +158,6 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
-// Support conditional compilation by transforming the AST, stripping out
-// any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
-                                -> (ast::Crate, Features) {
-    let features;
-    {
-        let mut strip_unconfigured = StripUnconfigured {
-            config: &krate.config.clone(),
-            should_test: should_test,
-            sess: sess,
-            features: None,
-        };
-
-        let err_count = sess.span_diagnostic.err_count();
-        let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default();
-        features = get_features(&sess.span_diagnostic, &krate_attrs);
-        if err_count < sess.span_diagnostic.err_count() {
-            krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
-        }
-
-        strip_unconfigured.features = Some(&features);
-        krate = strip_unconfigured.fold_crate(krate);
-        krate.attrs = krate_attrs;
-    }
-
-    (krate, features)
-}
-
 impl<'a> fold::Folder for StripUnconfigured<'a> {
     fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
         ast::ForeignMod {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6f8af66632f04..92d053fd21b01 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -719,8 +719,9 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
     }
 
     let items = SmallVector::many(c.module.items);
-    expander.load_macros(&items);
-    c.module.items = items.into();
+    let configured = items.fold_with(&mut expander.strip_unconfigured());
+    expander.load_macros(&configured);
+    c.module.items = configured.into();
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);

From de2e67836e23405e5bdc27cefa510fa562c5298f Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sat, 27 Aug 2016 05:27:59 +0000
Subject: [PATCH 557/768] Add `Invocation` and `Expansion`, remove
 `MacroGenerable`.

---
 src/libsyntax/ext/expand.rs | 452 +++++++++++++++++++-----------------
 1 file changed, 240 insertions(+), 212 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 92d053fd21b01..485bd3ce10b4b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -30,249 +30,230 @@ use std_inject;
 
 use std::path::PathBuf;
 
-// A trait for AST nodes and AST node lists into which macro invocations may expand.
-trait MacroGenerable: Sized {
-    // Expand the given MacResult using its appropriate `make_*` method.
-    fn make_with<'a>(result: Box) -> Option;
-
-    // Fold this node or list of nodes using the given folder.
-    fn fold_with(self, folder: &mut F) -> Self;
-    fn visit_with(&self, visitor: &mut V);
+macro_rules! expansions {
+    ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
+            $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
+            $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
+        #[derive(Copy, Clone)]
+        enum ExpansionKind { OptExpr, $( $kind, )*  }
+        enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
+
+        impl ExpansionKind {
+            fn name(self) -> &'static str {
+                match self {
+                    ExpansionKind::OptExpr => "expression",
+                    $( ExpansionKind::$kind => $kind_name, )*
+                }
+            }
 
-    // The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics.
-    fn kind_name() -> &'static str;
+            fn make_from<'a>(self, result: Box) -> Option {
+                match self {
+                    ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr),
+                    $( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )*
+                }
+            }
+        }
 
-    // Return a placeholder expansion to allow compilation to continue after an erroring expansion.
-    fn dummy(span: Span) -> Self {
-        Self::make_with(DummyResult::any(span)).unwrap()
-    }
-}
+        impl Expansion {
+            fn make_opt_expr(self) -> Option> {
+                match self {
+                    Expansion::OptExpr(expr) => expr,
+                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
+                }
+            }
+            $( fn $make(self) -> $ty {
+                match self {
+                    Expansion::$kind(ast) => ast,
+                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
+                }
+            } )*
 
-macro_rules! impl_macro_generable {
-    ($($ty:ty: $kind_name:expr, .$make:ident,
-               $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
-               $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { $(
-        impl MacroGenerable for $ty {
-            fn kind_name() -> &'static str { $kind_name }
-            fn make_with<'a>(result: Box) -> Option { result.$make() }
             fn fold_with(self, folder: &mut F) -> Self {
-                $( folder.$fold(self) )*
-                $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
+                use self::Expansion::*;
+                match self {
+                    OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
+                    $($( $kind(ast) => $kind(folder.$fold(ast)), )*)*
+                    $($( $kind(ast) => {
+                        $kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect())
+                    }, )*)*
+                }
             }
+
             fn visit_with(&self, visitor: &mut V) {
-                $( visitor.$visit(self) )*
-                $( for item in self.as_slice() { visitor. $visit_elt (item) } )*
+                match *self {
+                    Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
+                    $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
+                    $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
+                        visitor.$visit_elt(ast);
+                    }, )*)*
+                    _ => {}
+                }
             }
         }
-    )* }
+    }
 }
 
-impl_macro_generable! {
-    P: "expression", .make_expr, .fold_expr, .visit_expr;
-    P:  "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    P:   "type",       .make_ty,   .fold_ty,   .visit_ty;
-    SmallVector: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
-    SmallVector>: "item",   .make_items, lift .fold_item, lift .visit_item;
-    SmallVector:
+expansions! {
+    Expr: P, "expression", .make_expr, .fold_expr, .visit_expr;
+    Pat: P,   "pattern",    .make_pat,  .fold_pat,  .visit_pat;
+    Ty: P,     "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Stmts: SmallVector, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
+    Items: SmallVector>, "item",   .make_items, lift .fold_item, lift .visit_item;
+    TraitItems: SmallVector,
         "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
-    SmallVector:
+    ImplItems: SmallVector,
         "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
 }
 
-impl MacroGenerable for Option> {
-    fn kind_name() -> &'static str { "expression" }
-    fn make_with<'a>(result: Box) -> Option {
-        result.make_expr().map(Some)
-    }
-    fn fold_with(self, folder: &mut F) -> Self {
-        self.and_then(|expr| folder.fold_opt_expr(expr))
-    }
-    fn visit_with(&self, visitor: &mut V) {
-        self.as_ref().map(|expr| visitor.visit_expr(expr));
+impl ExpansionKind {
+    fn dummy(self, span: Span) -> Expansion {
+        self.make_from(DummyResult::any(span)).unwrap()
     }
 }
 
-pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
-    match expr.node {
-        // expr_mac should really be expr_ext or something; it's the
-        // entry-point for all syntax extensions.
-        ast::ExprKind::Mac(mac) => {
-            return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld);
-        }
-        _ => P(noop_fold_expr(expr, fld)),
-    }
+pub struct Invocation {
+    span: Span,
+    attrs: Vec,
+    mac: ast::Mac,
+    ident: Option,
+    mark: Mark,
+    kind: ExpansionKind,
 }
 
-struct MacroScopePlaceholder;
-impl MacResult for MacroScopePlaceholder {
-    fn make_items(self: Box) -> Option>> {
-        Some(SmallVector::one(P(ast::Item {
-            ident: keywords::Invalid.ident(),
-            attrs: Vec::new(),
-            id: ast::DUMMY_NODE_ID,
-            node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
-                path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
-                tts: Vec::new(),
-            })),
-            vis: ast::Visibility::Inherited,
-            span: syntax_pos::DUMMY_SP,
-        })))
+pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
+    if let ast::ExprKind::Mac(mac) = expr.node {
+        let invoc = fld.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+        expand_mac_invoc(invoc, fld).make_expr()
+    } else {
+        P(noop_fold_expr(expr, fld))
     }
 }
 
 /// Expand a macro invocation. Returns the result of expansion.
-fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec, span: Span,
-                       fld: &mut MacroExpander) -> T
-    where T: MacroGenerable,
-{
-    // It would almost certainly be cleaner to pass the whole macro invocation in,
-    // rather than pulling it apart and marking the tts and the ctxt separately.
+fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { span, attrs, mac, ident, mark, kind } = invoc;
     let Mac_ { path, tts, .. } = mac.node;
-    let mark = Mark::fresh();
-
-    fn mac_result<'a>(path: &ast::Path, ident: Option, tts: Vec, mark: Mark,
-                      attrs: Vec, call_site: Span, fld: &'a mut MacroExpander)
-                      -> Option> {
-        // Detect use of feature-gated or invalid attributes on macro invoations
-        // since they will not be detected after macro expansion.
-        for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
-                                          &fld.cx.parse_sess.codemap(),
-                                          &fld.cx.ecfg.features.unwrap());
-        }
-
-        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
-            fld.cx.span_err(path.span, "expected macro name without module separators");
-            return None;
-        }
 
-        let extname = path.segments[0].identifier.name;
-        let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
-            extension
-        } else {
-            let mut err = fld.cx.struct_span_err(path.span,
-                                                 &format!("macro undefined: '{}!'", &extname));
-            fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
-            err.emit();
-            return None;
-        };
+    // Detect use of feature-gated or invalid attributes on macro invoations
+    // since they will not be detected after macro expansion.
+    for attr in attrs.iter() {
+        feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
+                                      &fld.cx.parse_sess.codemap(),
+                                      &fld.cx.ecfg.features.unwrap());
+    }
 
-        let ident = ident.unwrap_or(keywords::Invalid.ident());
-        let marked_tts = mark_tts(&tts, mark);
-        match *extension {
-            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
-                if ident.name != keywords::Invalid.name() {
-                    let msg =
-                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
-                    fld.cx.span_err(path.span, &msg);
-                    return None;
-                }
+    if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
+        fld.cx.span_err(path.span, "expected macro name without module separators");
+        return kind.dummy(span);
+    }
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: exp_span,
-                        allow_internal_unstable: allow_internal_unstable,
-                    },
-                });
+    let extname = path.segments[0].identifier.name;
+    let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
+        extension
+    } else {
+        let mut err =
+            fld.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
+        fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
+        err.emit();
+        return kind.dummy(span);
+    };
 
-                Some(expandfun.expand(fld.cx, call_site, &marked_tts))
+    let ident = ident.unwrap_or(keywords::Invalid.ident());
+    let marked_tts = mark_tts(&tts, mark);
+    let opt_expanded = match *extension {
+        NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
+            if ident.name != keywords::Invalid.name() {
+                let msg =
+                    format!("macro {}! expects no ident argument, given '{}'", extname, ident);
+                fld.cx.span_err(path.span, &msg);
+                return kind.dummy(span);
             }
 
-            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
-                if ident.name == keywords::Invalid.name() {
-                    fld.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
-                    return None;
-                };
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: exp_span,
+                    allow_internal_unstable: allow_internal_unstable,
+                },
+            });
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: tt_span,
-                        allow_internal_unstable: allow_internal_unstable,
-                    }
-                });
+            kind.make_from(expandfun.expand(fld.cx, span, &marked_tts))
+        }
 
-                Some(expander.expand(fld.cx, call_site, ident, marked_tts))
-            }
+        IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+            if ident.name == keywords::Invalid.name() {
+                fld.cx.span_err(path.span,
+                                &format!("macro {}! expects an ident argument", extname));
+                return kind.dummy(span);
+            };
 
-            MacroRulesTT => {
-                if ident.name == keywords::Invalid.name() {
-                    fld.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
-                    return None;
-                };
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: tt_span,
+                    allow_internal_unstable: allow_internal_unstable,
+                }
+            });
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: None,
-                        // `macro_rules!` doesn't directly allow unstable
-                        // (this is orthogonal to whether the macro it creates allows it)
-                        allow_internal_unstable: false,
-                    }
-                });
+            kind.make_from(expander.expand(fld.cx, span, ident, marked_tts))
+        }
 
-                let def = ast::MacroDef {
-                    ident: ident,
-                    id: ast::DUMMY_NODE_ID,
-                    span: call_site,
-                    imported_from: None,
-                    use_locally: true,
-                    body: marked_tts,
-                    export: attr::contains_name(&attrs, "macro_export"),
-                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-                    attrs: attrs,
-                };
+        MacroRulesTT => {
+            if ident.name == keywords::Invalid.name() {
+                fld.cx.span_err(path.span,
+                                &format!("macro {}! expects an ident argument", extname));
+                return kind.dummy(span);
+            };
 
-                fld.cx.insert_macro(def.clone());
-
-                // macro_rules! has a side effect, but expands to nothing.
-                // If keep_macs is true, expands to a MacEager::items instead.
-                if fld.keep_macs {
-                    Some(MacEager::items(SmallVector::one(P(ast::Item {
-                        ident: def.ident,
-                        attrs: def.attrs.clone(),
-                        id: ast::DUMMY_NODE_ID,
-                        node: ast::ItemKind::Mac(ast::Mac {
-                            span: def.span,
-                            node: ast::Mac_ {
-                                path: path.clone(),
-                                tts: def.body.clone(),
-                            }
-                        }),
-                        vis: ast::Visibility::Inherited,
-                        span: def.span,
-                    }))))
-                } else {
-                    Some(Box::new(MacroScopePlaceholder))
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: None,
+                    // `macro_rules!` doesn't directly allow unstable
+                    // (this is orthogonal to whether the macro it creates allows it)
+                    allow_internal_unstable: false,
                 }
-            }
+            });
 
-            MultiDecorator(..) | MultiModifier(..) => {
-                fld.cx.span_err(path.span,
-                                &format!("`{}` can only be used in attributes", extname));
-                None
+            let def = ast::MacroDef {
+                ident: ident,
+                id: ast::DUMMY_NODE_ID,
+                span: span,
+                imported_from: None,
+                use_locally: true,
+                body: marked_tts,
+                export: attr::contains_name(&attrs, "macro_export"),
+                allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
+                attrs: attrs,
+            };
+
+            fld.cx.insert_macro(def.clone());
+
+            // If keep_macs is true, expands to a MacEager::items instead.
+            if fld.keep_macs {
+                Some(reconstruct_macro_rules(&def, &path))
+            } else {
+                Some(macro_scope_placeholder())
             }
         }
-    }
 
-    let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) {
-        Some(result) => result,
-        None => return T::dummy(span),
-    });
+        MultiDecorator(..) | MultiModifier(..) => {
+            fld.cx.span_err(path.span,
+                            &format!("`{}` can only be used in attributes", extname));
+            return kind.dummy(span);
+        }
+    };
 
     let expanded = if let Some(expanded) = opt_expanded {
         expanded
     } else {
         let msg = format!("non-{kind} macro in {kind} position: {name}",
-                          name = path.segments[0].identifier.name, kind = T::kind_name());
+                          name = path.segments[0].identifier.name, kind = kind.name());
         fld.cx.span_err(path.span, &msg);
-        return T::dummy(span);
+        return kind.dummy(span);
     };
 
     let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
@@ -342,8 +323,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector {
         _ => return noop_fold_stmt(stmt, fld)
     };
 
-    let mut fully_expanded: SmallVector =
-        expand_mac_invoc(mac, None, attrs.into(), stmt.span, fld);
+    let invoc = fld.new_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+    let mut fully_expanded = expand_mac_invoc(invoc, fld).make_stmts();
 
     // If this is a macro invocation with a semicolon, then apply that
     // semicolon to the final statement produced by expansion.
@@ -361,11 +342,12 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
         PatKind::Mac(_) => {}
         _ => return noop_fold_pat(p, fld)
     }
-    p.and_then(|ast::Pat {node, span, ..}| {
-        match node {
-            PatKind::Mac(mac) => expand_mac_invoc(mac, None, Vec::new(), span, fld),
-            _ => unreachable!()
+    p.and_then(|p| match p.node {
+        PatKind::Mac(mac) => {
+            let invoc = fld.new_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
+            expand_mac_invoc(invoc, fld).make_pat()
         }
+        _ => unreachable!(),
     })
 }
 
@@ -380,8 +362,11 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     return SmallVector::one(Annotatable::Item(it));
                 }
                 it.and_then(|it| match it.node {
-                    ItemKind::Mac(mac) =>
-                        expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),
+                    ItemKind::Mac(mac) => {
+                        let mut invoc = fld.new_invoc(mac, it.attrs, it.span, ExpansionKind::Items);
+                        invoc.ident = Some(it.ident);
+                        expand_mac_invoc(invoc, fld).make_items()
+                    }
                     _ => unreachable!(),
                 })
             }
@@ -472,7 +457,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector {
     match ii.node {
         ast::ImplItemKind::Macro(mac) => {
-            expand_mac_invoc(mac, None, ii.attrs, ii.span, fld)
+            let invoc = fld.new_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
+            expand_mac_invoc(invoc, fld).make_impl_items()
         }
         _ => fold::noop_fold_impl_item(ii, fld)
     }
@@ -482,7 +468,8 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
                      -> SmallVector {
     match ti.node {
         ast::TraitItemKind::Macro(mac) => {
-            expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
+            let invoc = fld.new_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
+            expand_mac_invoc(invoc, fld).make_trait_items()
         }
         _ => fold::noop_fold_trait_item(ti, fld)
     }
@@ -496,7 +483,8 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
 
     match t.node {
         ast::TyKind::Mac(mac) => {
-            expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
+            let invoc = fld.new_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
+            expand_mac_invoc(invoc, fld).make_ty()
         }
         _ => unreachable!(),
     }
@@ -529,7 +517,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
     }
 
-    fn load_macros(&mut self, node: &T) {
+    fn load_macros(&mut self, node: &Expansion) {
         struct MacroLoadingVisitor<'a, 'b: 'a>{
             cx: &'a mut ExtCtxt<'b>,
             at_crate_root: bool,
@@ -567,6 +555,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             cx: self.cx,
         });
     }
+
+    fn new_invoc(&self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind)
+                 -> Invocation {
+        let mark = Mark::fresh();
+        Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -583,8 +577,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
     fn fold_opt_expr(&mut self, expr: P) -> Option> {
         expr.and_then(|expr| match expr.node {
-            ast::ExprKind::Mac(mac) =>
-                expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, self),
+            ast::ExprKind::Mac(mac) => {
+                let invoc =
+                    self.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+                expand_mac_invoc(invoc, self).make_opt_expr()
+            }
             _ => Some(expand_expr(expr, self)),
         })
     }
@@ -647,6 +644,37 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
+fn macro_scope_placeholder() -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: keywords::Invalid.ident(),
+        attrs: Vec::new(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
+            path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
+            tts: Vec::new(),
+        })),
+        vis: ast::Visibility::Inherited,
+        span: syntax_pos::DUMMY_SP,
+    })))
+}
+
+fn reconstruct_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: def.ident,
+        attrs: def.attrs.clone(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(ast::Mac {
+            span: def.span,
+            node: ast::Mac_ {
+                path: path.clone(),
+                tts: def.body.clone(),
+            }
+        }),
+        vis: ast::Visibility::Inherited,
+        span: def.span,
+    })))
+}
+
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
@@ -718,10 +746,10 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
         expander.cx.syntax_env.insert(name, extension);
     }
 
-    let items = SmallVector::many(c.module.items);
+    let items = Expansion::Items(SmallVector::many(c.module.items));
     let configured = items.fold_with(&mut expander.strip_unconfigured());
     expander.load_macros(&configured);
-    c.module.items = configured.into();
+    c.module.items = configured.make_items().into();
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);

From 3cba93f9933fe96fb77d625a480eb4cdddeed91f Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sat, 27 Aug 2016 06:27:35 +0000
Subject: [PATCH 558/768] Refactor `with_exts_frame` from a macro to a
 function.

---
 src/libsyntax/ext/expand.rs | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 485bd3ce10b4b..481278eb25745 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -270,18 +270,6 @@ fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-// eval $e with a new exts frame.
-// must be a macro so that $e isn't evaluated too early.
-macro_rules! with_exts_frame {
-    ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
-    ({$extsboxexpr.push_frame();
-      $extsboxexpr.info().macros_escape = $macros_escape;
-      let result = $e;
-      $extsboxexpr.pop_frame();
-      result
-     })
-}
-
 // When we enter a module, record it, for the sake of `module!`
 pub fn expand_item(it: P, fld: &mut MacroExpander)
                    -> SmallVector> {
@@ -378,9 +366,7 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     fld.cx.mod_push(it.ident);
                 }
                 let macro_use = contains_macro_use(fld, &it.attrs);
-                let result = with_exts_frame!(fld.cx.syntax_env,
-                                              macro_use,
-                                              noop_fold_item(it, fld));
+                let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(it, fld));
                 if valid_ident {
                     fld.cx.mod_pop();
                 }
@@ -561,6 +547,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mark = Mark::fresh();
         Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
     }
+
+    fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
+        self.cx.syntax_env.push_frame();
+        self.cx.syntax_env.info().macros_escape = macros_escape;
+        let result = f(self);
+        self.cx.syntax_env.pop_frame();
+        result
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -624,7 +618,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
     fn fold_block(&mut self, block: P) -> P {
         let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
-        let result = with_exts_frame!(self.cx.syntax_env, false, noop_fold_block(block, self));
+        let result = self.with_exts_frame(false, |this| noop_fold_block(block, this));
         self.cx.in_block = was_in_block;
         result
     }

From fca80c983d486632d2fe12aed270af332ce01598 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 2 Sep 2016 06:14:38 +0000
Subject: [PATCH 559/768] Generalize `Invocation` to include
 modifiers/decorators.

---
 src/libsyntax/ext/base.rs   |  10 --
 src/libsyntax/ext/expand.rs | 223 ++++++++++++++++++++++--------------
 2 files changed, 138 insertions(+), 95 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index b2e4aeabd9531..769a5af0262c5 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -91,16 +91,6 @@ impl Annotatable {
             _ => panic!("expected Item")
         }
     }
-
-    pub fn fold_with(self, folder: &mut F) -> SmallVector {
-        match self {
-            Annotatable::Item(item) => folder.fold_item(item).map(Annotatable::Item),
-            Annotatable::ImplItem(item) =>
-                folder.fold_impl_item(item.unwrap()).map(|item| Annotatable::ImplItem(P(item))),
-            Annotatable::TraitItem(item) =>
-                folder.fold_trait_item(item.unwrap()).map(|item| Annotatable::TraitItem(P(item))),
-        }
-    }
 }
 
 // A more flexible ItemDecorator.
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 481278eb25745..66a766a666bb4 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -109,29 +109,104 @@ impl ExpansionKind {
     fn dummy(self, span: Span) -> Expansion {
         self.make_from(DummyResult::any(span)).unwrap()
     }
+
+    fn expect_from_annotatables>(self, items: I) -> Expansion {
+        let items = items.into_iter();
+        match self {
+            ExpansionKind::Items =>
+                Expansion::Items(items.map(Annotatable::expect_item).collect()),
+            ExpansionKind::ImplItems =>
+                Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
+            ExpansionKind::TraitItems =>
+                Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
+            _ => unreachable!(),
+        }
+    }
 }
 
 pub struct Invocation {
-    span: Span,
-    attrs: Vec,
-    mac: ast::Mac,
-    ident: Option,
+    kind: InvocationKind,
+    expansion_kind: ExpansionKind,
     mark: Mark,
-    kind: ExpansionKind,
+}
+
+enum InvocationKind {
+    Bang {
+        attrs: Vec,
+        mac: ast::Mac,
+        ident: Option,
+        span: Span,
+    },
+    Attr {
+        attr: ast::Attribute,
+        item: Annotatable,
+    },
 }
 
 pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
     if let ast::ExprKind::Mac(mac) = expr.node {
-        let invoc = fld.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-        expand_mac_invoc(invoc, fld).make_expr()
+        let invoc = fld.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+        expand_invoc(invoc, fld).make_expr()
     } else {
         P(noop_fold_expr(expr, fld))
     }
 }
 
+fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    match invoc.kind {
+        InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
+        InvocationKind::Attr { .. } => expand_attr_invoc(invoc, fld),
+    }
+}
+
+fn expand_attr_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { expansion_kind: kind, .. } = invoc;
+    let (attr, item) = match invoc.kind {
+        InvocationKind::Attr { attr, item } => (attr, item),
+        _ => unreachable!(),
+    };
+
+    let extension = match fld.cx.syntax_env.find(intern(&attr.name())) {
+        Some(extension) => extension,
+        None => unreachable!(),
+    };
+
+    attr::mark_used(&attr);
+    fld.cx.bt_push(ExpnInfo {
+        call_site: attr.span,
+        callee: NameAndSpan {
+            format: MacroAttribute(intern(&attr.name())),
+            span: Some(attr.span),
+            allow_internal_unstable: false,
+        }
+    });
+
+    let modified = match *extension {
+        MultiModifier(ref mac) => {
+            kind.expect_from_annotatables(mac.expand(fld.cx, attr.span, &attr.node.value, item))
+        }
+        MultiDecorator(ref mac) => {
+            let mut items = Vec::new();
+            mac.expand(fld.cx, attr.span, &attr.node.value, &item, &mut |item| items.push(item));
+            items.push(item);
+            kind.expect_from_annotatables(items)
+        }
+        _ => unreachable!(),
+    };
+
+    fld.cx.bt_pop();
+
+    let configured = modified.fold_with(&mut fld.strip_unconfigured());
+    configured.fold_with(fld)
+}
+
 /// Expand a macro invocation. Returns the result of expansion.
-fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    let Invocation { span, attrs, mac, ident, mark, kind } = invoc;
+fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { mark, expansion_kind: kind, .. } = invoc;
+    let (attrs, mac, ident, span) = match invoc.kind {
+        InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
+        _ => unreachable!(),
+    };
     let Mac_ { path, tts, .. } = mac.node;
 
     // Detect use of feature-gated or invalid attributes on macro invoations
@@ -270,11 +345,8 @@ fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-// When we enter a module, record it, for the sake of `module!`
-pub fn expand_item(it: P, fld: &mut MacroExpander)
-                   -> SmallVector> {
-    expand_annotatable(Annotatable::Item(it), fld)
-        .into_iter().map(|i| i.expect_item()).collect()
+pub fn expand_item(it: P, fld: &mut MacroExpander) -> SmallVector> {
+    expand_annotatable(Annotatable::Item(it), fld).make_items()
 }
 
 // does this attribute list contain "macro_use" ?
@@ -311,8 +383,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector {
         _ => return noop_fold_stmt(stmt, fld)
     };
 
-    let invoc = fld.new_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-    let mut fully_expanded = expand_mac_invoc(invoc, fld).make_stmts();
+    let invoc = fld.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+    let mut fully_expanded = expand_invoc(invoc, fld).make_stmts();
 
     // If this is a macro invocation with a semicolon, then apply that
     // semicolon to the final statement produced by expansion.
@@ -332,14 +404,14 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
     }
     p.and_then(|p| match p.node {
         PatKind::Mac(mac) => {
-            let invoc = fld.new_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
-            expand_mac_invoc(invoc, fld).make_pat()
+            let invoc = fld.new_bang_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
+            expand_invoc(invoc, fld).make_pat()
         }
         _ => unreachable!(),
     })
 }
 
-fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector {
+fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> Expansion {
     match a {
         Annotatable::Item(it) => match it.node {
             ast::ItemKind::Mac(..) => {
@@ -347,13 +419,15 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
                     _ => unreachable!(),
                 } {
-                    return SmallVector::one(Annotatable::Item(it));
+                    return Expansion::Items(SmallVector::one(it));
                 }
                 it.and_then(|it| match it.node {
                     ItemKind::Mac(mac) => {
-                        let mut invoc = fld.new_invoc(mac, it.attrs, it.span, ExpansionKind::Items);
-                        invoc.ident = Some(it.ident);
-                        expand_mac_invoc(invoc, fld).make_items()
+                        let invoc =
+                            fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                                mac: mac, attrs: it.attrs, ident: Some(it.ident), span: it.span,
+                            });
+                        expand_invoc(invoc, fld)
                     }
                     _ => unreachable!(),
                 })
@@ -370,31 +444,24 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                 if valid_ident {
                     fld.cx.mod_pop();
                 }
-                result
+                Expansion::Items(result)
             },
-            _ => noop_fold_item(it, fld),
-        }.into_iter().map(|i| Annotatable::Item(i)).collect(),
-
-        Annotatable::TraitItem(it) => {
-            expand_trait_item(it.unwrap(), fld).into_iter().
-                map(|it| Annotatable::TraitItem(P(it))).collect()
-        }
+            _ => Expansion::Items(noop_fold_item(it, fld)),
+        },
 
-        Annotatable::ImplItem(ii) => {
-            expand_impl_item(ii.unwrap(), fld).into_iter().
-                map(|ii| Annotatable::ImplItem(P(ii))).collect()
-        }
+        Annotatable::TraitItem(it) => Expansion::TraitItems(expand_trait_item(it.unwrap(), fld)),
+        Annotatable::ImplItem(ii) => Expansion::ImplItems(expand_impl_item(ii.unwrap(), fld)),
     }
 }
 
-fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVector {
-    let mut multi_modifier = None;
+fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> Expansion {
+    let mut attr = None;
     item = item.map_attrs(|mut attrs| {
         for i in 0..attrs.len() {
             if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
                 match *extension {
                     MultiModifier(..) | MultiDecorator(..) => {
-                        multi_modifier = Some((attrs.remove(i), extension));
+                        attr = Some(attrs.remove(i));
                         break;
                     }
                     _ => {}
@@ -404,38 +471,16 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe
         attrs
     });
 
-    match multi_modifier {
-        None => expand_multi_modified(item, fld),
-        Some((attr, extension)) => {
-            attr::mark_used(&attr);
-            fld.cx.bt_push(ExpnInfo {
-                call_site: attr.span,
-                callee: NameAndSpan {
-                    format: MacroAttribute(intern(&attr.name())),
-                    span: Some(attr.span),
-                    allow_internal_unstable: false,
-                }
-            });
-
-            let modified = match *extension {
-                MultiModifier(ref mac) => mac.expand(fld.cx, attr.span, &attr.node.value, item),
-                MultiDecorator(ref mac) => {
-                    let mut items = Vec::new();
-                    mac.expand(fld.cx, attr.span, &attr.node.value, &item,
-                               &mut |item| items.push(item));
-                    items.push(item);
-                    items
-                }
-                _ => unreachable!(),
-            };
-
-            fld.cx.bt_pop();
-            let configured = modified.into_iter().flat_map(|it| {
-                it.fold_with(&mut fld.strip_unconfigured())
-            }).collect::>();
-
-            configured.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect()
-        }
+    if let Some(attr) = attr {
+        let kind = match item {
+            Annotatable::Item(_) => ExpansionKind::Items,
+            Annotatable::ImplItem(_) => ExpansionKind::ImplItems,
+            Annotatable::TraitItem(_) => ExpansionKind::TraitItems,
+        };
+        let invoc = fld.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item });
+        expand_invoc(invoc, fld)
+    } else {
+        expand_multi_modified(item, fld)
     }
 }
 
@@ -443,8 +488,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector {
     match ii.node {
         ast::ImplItemKind::Macro(mac) => {
-            let invoc = fld.new_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
-            expand_mac_invoc(invoc, fld).make_impl_items()
+            let invoc = fld.new_bang_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
+            expand_invoc(invoc, fld).make_impl_items()
         }
         _ => fold::noop_fold_impl_item(ii, fld)
     }
@@ -454,8 +499,8 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
                      -> SmallVector {
     match ti.node {
         ast::TraitItemKind::Macro(mac) => {
-            let invoc = fld.new_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
-            expand_mac_invoc(invoc, fld).make_trait_items()
+            let invoc = fld.new_bang_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
+            expand_invoc(invoc, fld).make_trait_items()
         }
         _ => fold::noop_fold_trait_item(ti, fld)
     }
@@ -469,8 +514,8 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
 
     match t.node {
         ast::TyKind::Mac(mac) => {
-            let invoc = fld.new_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
-            expand_mac_invoc(invoc, fld).make_ty()
+            let invoc = fld.new_bang_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
+            expand_invoc(invoc, fld).make_ty()
         }
         _ => unreachable!(),
     }
@@ -542,10 +587,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         });
     }
 
-    fn new_invoc(&self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind)
+    fn new_invoc(&self, expansion_kind: ExpansionKind, kind: InvocationKind)
                  -> Invocation {
-        let mark = Mark::fresh();
-        Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
+        Invocation { mark: Mark::fresh(), kind: kind, expansion_kind: expansion_kind }
+    }
+
+    fn new_bang_invoc(
+        &self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind,
+    ) -> Invocation {
+        self.new_invoc(kind, InvocationKind::Bang {
+            attrs: attrs,
+            mac: mac,
+            ident: None,
+            span: span,
+        })
     }
 
     fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
@@ -573,8 +628,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         expr.and_then(|expr| match expr.node {
             ast::ExprKind::Mac(mac) => {
                 let invoc =
-                    self.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-                expand_mac_invoc(invoc, self).make_opt_expr()
+                    self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+                expand_invoc(invoc, self).make_opt_expr()
             }
             _ => Some(expand_expr(expr, self)),
         })
@@ -624,13 +679,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector {
-        expand_annotatable(Annotatable::TraitItem(P(i)), self)
-            .into_iter().map(|i| i.expect_trait_item()).collect()
+        expand_annotatable(Annotatable::TraitItem(P(i)), self).make_trait_items()
     }
 
     fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector {
-        expand_annotatable(Annotatable::ImplItem(P(i)), self)
-            .into_iter().map(|i| i.expect_impl_item()).collect()
+        expand_annotatable(Annotatable::ImplItem(P(i)), self).make_impl_items()
     }
 
     fn fold_ty(&mut self, ty: P) -> P {

From 8be8cf854017e3b41324158868e9097fa6cdcc4d Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sun, 28 Aug 2016 03:11:33 +0000
Subject: [PATCH 560/768] Refactor away `expand_item`.

---
 src/libsyntax/ext/expand.rs | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 66a766a666bb4..687c5e2fdfb8e 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -345,10 +345,6 @@ fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-pub fn expand_item(it: P, fld: &mut MacroExpander) -> SmallVector> {
-    expand_annotatable(Annotatable::Item(it), fld).make_items()
-}
-
 // does this attribute list contain "macro_use" ?
 fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
     for attr in attrs {
@@ -649,7 +645,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                     ::attr::first_attr_value_str_by_name(&item.attrs, "path")
                         .unwrap_or(item.ident.name.as_str())
                 });
-                result = expand_item(item, self);
+                result = expand_annotatable(Annotatable::Item(item), self).make_items();
                 self.cx.directory = directory;
             } else {
                 let mut directory = match inner {
@@ -658,11 +654,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                 };
                 directory.pop();
                 let directory = replace(&mut self.cx.directory, directory);
-                result = expand_item(item, self);
+                result = expand_annotatable(Annotatable::Item(item), self).make_items();
                 self.cx.directory = directory;
             }
         } else {
-            result = expand_item(item, self);
+            result = expand_annotatable(Annotatable::Item(item), self).make_items();
         }
         result
     }

From 2a83574c6af52419af9f723bcc9a9427942a6be8 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sun, 28 Aug 2016 03:16:03 +0000
Subject: [PATCH 561/768] Refactor out `expand_item` (with better semantics
 than before).

---
 src/libsyntax/ext/expand.rs | 75 +++++++++++++++++++------------------
 1 file changed, 39 insertions(+), 36 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 687c5e2fdfb8e..1b9af0aa46776 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -409,42 +409,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
 
 fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> Expansion {
     match a {
-        Annotatable::Item(it) => match it.node {
-            ast::ItemKind::Mac(..) => {
-                if match it.node {
-                    ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
-                    _ => unreachable!(),
-                } {
-                    return Expansion::Items(SmallVector::one(it));
-                }
-                it.and_then(|it| match it.node {
-                    ItemKind::Mac(mac) => {
-                        let invoc =
-                            fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
-                                mac: mac, attrs: it.attrs, ident: Some(it.ident), span: it.span,
-                            });
-                        expand_invoc(invoc, fld)
-                    }
-                    _ => unreachable!(),
-                })
-            }
-            ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
-                let valid_ident =
-                    it.ident.name != keywords::Invalid.name();
-
-                if valid_ident {
-                    fld.cx.mod_push(it.ident);
-                }
-                let macro_use = contains_macro_use(fld, &it.attrs);
-                let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(it, fld));
-                if valid_ident {
-                    fld.cx.mod_pop();
-                }
-                Expansion::Items(result)
-            },
-            _ => Expansion::Items(noop_fold_item(it, fld)),
-        },
-
+        Annotatable::Item(it) => Expansion::Items(expand_item(it, fld)),
         Annotatable::TraitItem(it) => Expansion::TraitItems(expand_trait_item(it.unwrap(), fld)),
         Annotatable::ImplItem(ii) => Expansion::ImplItems(expand_impl_item(ii.unwrap(), fld)),
     }
@@ -480,6 +445,44 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> Expansi
     }
 }
 
+fn expand_item(item: P, fld: &mut MacroExpander) -> SmallVector> {
+    match item.node {
+        ast::ItemKind::Mac(..) => {
+            if match item.node {
+                ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
+                _ => unreachable!(),
+            } {
+                return SmallVector::one(item);
+            }
+            item.and_then(|item| match item.node {
+                ItemKind::Mac(mac) => {
+                    let invoc =
+                        fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                            mac: mac, attrs: item.attrs, ident: Some(item.ident), span: item.span,
+                        });
+                    expand_invoc(invoc, fld).make_items()
+                }
+                _ => unreachable!(),
+            })
+        }
+        ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
+            let valid_ident =
+                item.ident.name != keywords::Invalid.name();
+
+            if valid_ident {
+                fld.cx.mod_push(item.ident);
+            }
+            let macro_use = contains_macro_use(fld, &item.attrs);
+            let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
+            if valid_ident {
+                fld.cx.mod_pop();
+            }
+            result
+        },
+        _ => noop_fold_item(item, fld),
+    }
+}
+
 fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector {
     match ii.node {

From 503a10b34a89995ebea6b7a28aa2465038c99627 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sun, 28 Aug 2016 03:49:56 +0000
Subject: [PATCH 562/768] Clean up module processing.

---
 src/libsyntax/ext/expand.rs | 54 ++++++++++++++-----------------------
 1 file changed, 20 insertions(+), 34 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 1b9af0aa46776..3e169131ec8dc 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -465,18 +465,28 @@ fn expand_item(item: P, fld: &mut MacroExpander) -> SmallVector unreachable!(),
             })
         }
-        ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
-            let valid_ident =
-                item.ident.name != keywords::Invalid.name();
+        ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
+            fld.cx.mod_push(item.ident);
+            let macro_use = contains_macro_use(fld, &item.attrs);
 
-            if valid_ident {
-                fld.cx.mod_push(item.ident);
+            let directory = fld.cx.directory.clone();
+            if item.span.contains(inner) {
+                fld.cx.directory.push(&*{
+                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
+                        .unwrap_or(item.ident.name.as_str())
+                });
+            } else {
+                fld.cx.directory = match inner {
+                    syntax_pos::DUMMY_SP => PathBuf::new(),
+                    _ => PathBuf::from(fld.cx.parse_sess.codemap().span_to_filename(inner)),
+                };
+                fld.cx.directory.pop();
             }
-            let macro_use = contains_macro_use(fld, &item.attrs);
+
             let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
-            if valid_ident {
-                fld.cx.mod_pop();
-            }
+            fld.cx.directory = directory;
+
+            fld.cx.mod_pop();
             result
         },
         _ => noop_fold_item(item, fld),
@@ -639,31 +649,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_item(&mut self, item: P) -> SmallVector> {
-        use std::mem::replace;
-        let result;
-        if let ast::ItemKind::Mod(ast::Mod { inner, .. }) = item.node {
-            if item.span.contains(inner) {
-                let directory = self.cx.directory.clone();
-                self.cx.directory.push(&*{
-                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
-                        .unwrap_or(item.ident.name.as_str())
-                });
-                result = expand_annotatable(Annotatable::Item(item), self).make_items();
-                self.cx.directory = directory;
-            } else {
-                let mut directory = match inner {
-                    syntax_pos::DUMMY_SP => PathBuf::new(),
-                    _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
-                };
-                directory.pop();
-                let directory = replace(&mut self.cx.directory, directory);
-                result = expand_annotatable(Annotatable::Item(item), self).make_items();
-                self.cx.directory = directory;
-            }
-        } else {
-            result = expand_annotatable(Annotatable::Item(item), self).make_items();
-        }
-        result
+        expand_annotatable(Annotatable::Item(item), self).make_items()
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {

From 4ed2c0ea7cfc1cc952cc66e78e1b7117367de2c4 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Tue, 30 Aug 2016 23:03:52 +0000
Subject: [PATCH 563/768] Refactor `expand_*` into `expander.fold_*`.

---
 src/libsyntax/ext/expand.rs | 408 +++++++++++++++++-------------------
 1 file changed, 194 insertions(+), 214 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 3e169131ec8dc..d3f8618aace95 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast::{Block, Crate, Ident, Mac_, PatKind};
-use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
+use ast::{MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
 use attr::{self, HasAttrs};
@@ -143,15 +143,6 @@ enum InvocationKind {
     },
 }
 
-pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
-    if let ast::ExprKind::Mac(mac) = expr.node {
-        let invoc = fld.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-        expand_invoc(invoc, fld).make_expr()
-    } else {
-        P(noop_fold_expr(expr, fld))
-    }
-}
-
 fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     match invoc.kind {
         InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
@@ -345,191 +336,6 @@ fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-// does this attribute list contain "macro_use" ?
-fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
-    for attr in attrs {
-        let mut is_use = attr.check_name("macro_use");
-        if attr.check_name("macro_escape") {
-            let mut err =
-                fld.cx.struct_span_warn(attr.span,
-                                        "macro_escape is a deprecated synonym for macro_use");
-            is_use = true;
-            if let ast::AttrStyle::Inner = attr.node.style {
-                err.help("consider an outer attribute, \
-                          #[macro_use] mod ...").emit();
-            } else {
-                err.emit();
-            }
-        };
-
-        if is_use {
-            if !attr.is_word() {
-              fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
-            }
-            return true;
-        }
-    }
-    false
-}
-
-/// Expand a stmt
-fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector {
-    let (mac, style, attrs) = match stmt.node {
-        StmtKind::Mac(mac) => mac.unwrap(),
-        _ => return noop_fold_stmt(stmt, fld)
-    };
-
-    let invoc = fld.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-    let mut fully_expanded = expand_invoc(invoc, fld).make_stmts();
-
-    // If this is a macro invocation with a semicolon, then apply that
-    // semicolon to the final statement produced by expansion.
-    if style == MacStmtStyle::Semicolon {
-        if let Some(stmt) = fully_expanded.pop() {
-            fully_expanded.push(stmt.add_trailing_semicolon());
-        }
-    }
-
-    fully_expanded
-}
-
-fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
-    match p.node {
-        PatKind::Mac(_) => {}
-        _ => return noop_fold_pat(p, fld)
-    }
-    p.and_then(|p| match p.node {
-        PatKind::Mac(mac) => {
-            let invoc = fld.new_bang_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
-            expand_invoc(invoc, fld).make_pat()
-        }
-        _ => unreachable!(),
-    })
-}
-
-fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> Expansion {
-    match a {
-        Annotatable::Item(it) => Expansion::Items(expand_item(it, fld)),
-        Annotatable::TraitItem(it) => Expansion::TraitItems(expand_trait_item(it.unwrap(), fld)),
-        Annotatable::ImplItem(ii) => Expansion::ImplItems(expand_impl_item(ii.unwrap(), fld)),
-    }
-}
-
-fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> Expansion {
-    let mut attr = None;
-    item = item.map_attrs(|mut attrs| {
-        for i in 0..attrs.len() {
-            if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
-                match *extension {
-                    MultiModifier(..) | MultiDecorator(..) => {
-                        attr = Some(attrs.remove(i));
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-        }
-        attrs
-    });
-
-    if let Some(attr) = attr {
-        let kind = match item {
-            Annotatable::Item(_) => ExpansionKind::Items,
-            Annotatable::ImplItem(_) => ExpansionKind::ImplItems,
-            Annotatable::TraitItem(_) => ExpansionKind::TraitItems,
-        };
-        let invoc = fld.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item });
-        expand_invoc(invoc, fld)
-    } else {
-        expand_multi_modified(item, fld)
-    }
-}
-
-fn expand_item(item: P, fld: &mut MacroExpander) -> SmallVector> {
-    match item.node {
-        ast::ItemKind::Mac(..) => {
-            if match item.node {
-                ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
-                _ => unreachable!(),
-            } {
-                return SmallVector::one(item);
-            }
-            item.and_then(|item| match item.node {
-                ItemKind::Mac(mac) => {
-                    let invoc =
-                        fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
-                            mac: mac, attrs: item.attrs, ident: Some(item.ident), span: item.span,
-                        });
-                    expand_invoc(invoc, fld).make_items()
-                }
-                _ => unreachable!(),
-            })
-        }
-        ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
-            fld.cx.mod_push(item.ident);
-            let macro_use = contains_macro_use(fld, &item.attrs);
-
-            let directory = fld.cx.directory.clone();
-            if item.span.contains(inner) {
-                fld.cx.directory.push(&*{
-                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
-                        .unwrap_or(item.ident.name.as_str())
-                });
-            } else {
-                fld.cx.directory = match inner {
-                    syntax_pos::DUMMY_SP => PathBuf::new(),
-                    _ => PathBuf::from(fld.cx.parse_sess.codemap().span_to_filename(inner)),
-                };
-                fld.cx.directory.pop();
-            }
-
-            let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
-            fld.cx.directory = directory;
-
-            fld.cx.mod_pop();
-            result
-        },
-        _ => noop_fold_item(item, fld),
-    }
-}
-
-fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
-                 -> SmallVector {
-    match ii.node {
-        ast::ImplItemKind::Macro(mac) => {
-            let invoc = fld.new_bang_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
-            expand_invoc(invoc, fld).make_impl_items()
-        }
-        _ => fold::noop_fold_impl_item(ii, fld)
-    }
-}
-
-fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
-                     -> SmallVector {
-    match ti.node {
-        ast::TraitItemKind::Macro(mac) => {
-            let invoc = fld.new_bang_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
-            expand_invoc(invoc, fld).make_trait_items()
-        }
-        _ => fold::noop_fold_trait_item(ti, fld)
-    }
-}
-
-pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
-    let t = match t.node {
-        ast::TyKind::Mac(_) => t.unwrap(),
-        _ => return fold::noop_fold_ty(t, fld),
-    };
-
-    match t.node {
-        ast::TyKind::Mac(mac) => {
-            let invoc = fld.new_bang_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
-            expand_invoc(invoc, fld).make_ty()
-        }
-        _ => unreachable!(),
-    }
-}
-
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
@@ -612,6 +418,56 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         })
     }
 
+    fn new_attr_invoc(&self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
+                      -> Invocation {
+        self.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item })
+    }
+
+    // If `item` is an attr invocation, remove and return the macro attribute.
+    fn classify_item(&self, mut item: T) -> (T, Option) {
+        let mut attr = None;
+        item = item.map_attrs(|mut attrs| {
+            for i in 0..attrs.len() {
+                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
+                    match *extension {
+                        MultiModifier(..) | MultiDecorator(..) => {
+                            attr = Some(attrs.remove(i));
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            attrs
+        });
+        (item, attr)
+    }
+
+    // does this attribute list contain "macro_use" ?
+    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+        for attr in attrs {
+            let mut is_use = attr.check_name("macro_use");
+            if attr.check_name("macro_escape") {
+                let msg = "macro_escape is a deprecated synonym for macro_use";
+                let mut err = self.cx.struct_span_warn(attr.span, msg);
+                is_use = true;
+                if let ast::AttrStyle::Inner = attr.node.style {
+                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
+                } else {
+                    err.emit();
+                }
+            };
+
+            if is_use {
+                if !attr.is_word() {
+                    self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
+                }
+                return true;
+            }
+        }
+        false
+    }
+
     fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
         self.cx.syntax_env.push_frame();
         self.cx.syntax_env.info().macros_escape = macros_escape;
@@ -630,30 +486,59 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_expr(&mut self, expr: P) -> P {
-        expr.and_then(|expr| expand_expr(expr, self))
+        let expr = expr.unwrap();
+        if let ast::ExprKind::Mac(mac) = expr.node {
+            let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+            expand_invoc(invoc, self).make_expr()
+        } else {
+            P(noop_fold_expr(expr, self))
+        }
     }
 
     fn fold_opt_expr(&mut self, expr: P) -> Option> {
-        expr.and_then(|expr| match expr.node {
-            ast::ExprKind::Mac(mac) => {
-                let invoc =
-                    self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-                expand_invoc(invoc, self).make_opt_expr()
-            }
-            _ => Some(expand_expr(expr, self)),
-        })
+        let expr = expr.unwrap();
+        if let ast::ExprKind::Mac(mac) = expr.node {
+            let invoc =
+                self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+            expand_invoc(invoc, self).make_opt_expr()
+        } else {
+            Some(P(noop_fold_expr(expr, self)))
+        }
     }
 
     fn fold_pat(&mut self, pat: P) -> P {
-        expand_pat(pat, self)
-    }
+        match pat.node {
+            PatKind::Mac(_) => {}
+            _ => return noop_fold_pat(pat, self)
+        }
 
-    fn fold_item(&mut self, item: P) -> SmallVector> {
-        expand_annotatable(Annotatable::Item(item), self).make_items()
+        pat.and_then(|pat| match pat.node {
+            PatKind::Mac(mac) => {
+                let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
+                expand_invoc(invoc, self).make_pat()
+            }
+            _ => unreachable!(),
+        })
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {
-        expand_stmt(stmt, self)
+        let (mac, style, attrs) = match stmt.node {
+            StmtKind::Mac(mac) => mac.unwrap(),
+            _ => return noop_fold_stmt(stmt, self)
+        };
+
+        let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+        let mut fully_expanded = expand_invoc(invoc, self).make_stmts();
+
+        // If this is a macro invocation with a semicolon, then apply that
+        // semicolon to the final statement produced by expansion.
+        if style == MacStmtStyle::Semicolon {
+            if let Some(stmt) = fully_expanded.pop() {
+                fully_expanded.push(stmt.add_trailing_semicolon());
+            }
+        }
+
+        fully_expanded
     }
 
     fn fold_block(&mut self, block: P) -> P {
@@ -663,16 +548,111 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         result
     }
 
-    fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector {
-        expand_annotatable(Annotatable::TraitItem(P(i)), self).make_trait_items()
+    fn fold_item(&mut self, item: P) -> SmallVector> {
+        let (item, attr) = self.classify_item(item);
+        if let Some(attr) = attr {
+            let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
+            return expand_invoc(invoc, self).make_items();
+        }
+
+        match item.node {
+            ast::ItemKind::Mac(..) => {
+                if match item.node {
+                    ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
+                    _ => unreachable!(),
+                } {
+                    return SmallVector::one(item);
+                }
+
+                item.and_then(|item| match item.node {
+                    ItemKind::Mac(mac) => {
+                        let invoc = self.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                            mac: mac,
+                            attrs: item.attrs,
+                            ident: Some(item.ident),
+                            span: item.span,
+                        });
+                        expand_invoc(invoc, self).make_items()
+                    }
+                    _ => unreachable!(),
+                })
+            }
+            ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
+                self.cx.mod_push(item.ident);
+                let macro_use = self.contains_macro_use(&item.attrs);
+
+                let directory = self.cx.directory.clone();
+                if item.span.contains(inner) {
+                    self.cx.directory.push(&*{
+                        ::attr::first_attr_value_str_by_name(&item.attrs, "path")
+                            .unwrap_or(item.ident.name.as_str())
+                    });
+                } else {
+                    self.cx.directory = match inner {
+                        syntax_pos::DUMMY_SP => PathBuf::new(),
+                        _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
+                    };
+                    self.cx.directory.pop();
+                }
+                let result = self.with_exts_frame(macro_use, |this| noop_fold_item(item, this));
+                self.cx.directory = directory;
+
+                self.cx.mod_pop();
+                result
+            },
+            _ => noop_fold_item(item, self),
+        }
     }
 
-    fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector {
-        expand_annotatable(Annotatable::ImplItem(P(i)), self).make_impl_items()
+    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector {
+        let (item, attr) = self.classify_item(item);
+        if let Some(attr) = attr {
+            let item = Annotatable::TraitItem(P(item));
+            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
+            return expand_invoc(invoc, self).make_trait_items();
+        }
+
+        match item.node {
+            ast::TraitItemKind::Macro(mac) => {
+                let ast::TraitItem { attrs, span, .. } = item;
+                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
+                expand_invoc(invoc, self).make_trait_items()
+            }
+            _ => fold::noop_fold_trait_item(item, self),
+        }
+    }
+
+    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector {
+        let (item, attr) = self.classify_item(item);
+        if let Some(attr) = attr {
+            let item = Annotatable::ImplItem(P(item));
+            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
+            return expand_invoc(invoc, self).make_impl_items();
+        }
+
+        match item.node {
+            ast::ImplItemKind::Macro(mac) => {
+                let ast::ImplItem { attrs, span, .. } = item;
+                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
+                expand_invoc(invoc, self).make_impl_items()
+            }
+            _ => fold::noop_fold_impl_item(item, self)
+        }
     }
 
     fn fold_ty(&mut self, ty: P) -> P {
-        expand_type(ty, self)
+        let ty = match ty.node {
+            ast::TyKind::Mac(_) => ty.unwrap(),
+            _ => return fold::noop_fold_ty(ty, self),
+        };
+
+        match ty.node {
+            ast::TyKind::Mac(mac) => {
+                let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
+                expand_invoc(invoc, self).make_ty()
+            }
+            _ => unreachable!(),
+        }
     }
 }
 

From 79fa9eb643cfbb807813afed6f825f6654ee7662 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Thu, 1 Sep 2016 06:44:54 +0000
Subject: [PATCH 564/768] Refactor `SyntaxEnv`.

---
 src/libsyntax/ext/base.rs           | 169 ++++++++++++++++------------
 src/libsyntax/ext/expand.rs         |  64 ++++-------
 src/libsyntax/ext/source_util.rs    |   8 +-
 src/libsyntax/ext/tt/macro_rules.rs |   4 +-
 4 files changed, 119 insertions(+), 126 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 769a5af0262c5..fe2806891b85e 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -24,6 +24,7 @@ use parse::parser;
 use parse::token;
 use parse::token::{InternedString, intern, str_to_ident};
 use ptr::P;
+use std_inject;
 use util::small_vector::SmallVector;
 use util::lev_distance::find_best_match_for_name;
 use fold::Folder;
@@ -463,19 +464,6 @@ pub enum SyntaxExtension {
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
 
-pub struct BlockInfo {
-    /// Should macros escape from this scope?
-    pub macros_escape: bool,
-}
-
-impl BlockInfo {
-    pub fn new() -> BlockInfo {
-        BlockInfo {
-            macros_escape: false,
-        }
-    }
-}
-
 /// The base map of methods for expanding syntax extension
 /// AST nodes into full ASTs
 fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
@@ -586,15 +574,11 @@ pub struct ExtCtxt<'a> {
     pub crate_root: Option<&'static str>,
     pub loader: &'a mut MacroLoader,
 
-    pub mod_path: Vec ,
     pub exported_macros: Vec,
 
     pub syntax_env: SyntaxEnv,
     pub derive_modes: HashMap>,
     pub recursion_count: usize,
-
-    pub directory: PathBuf,
-    pub in_block: bool,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -602,22 +586,17 @@ impl<'a> ExtCtxt<'a> {
                ecfg: expand::ExpansionConfig<'a>,
                loader: &'a mut MacroLoader)
                -> ExtCtxt<'a> {
-        let env = initial_syntax_expander_table(&ecfg);
         ExtCtxt {
+            syntax_env: initial_syntax_expander_table(&ecfg),
             parse_sess: parse_sess,
             cfg: cfg,
             backtrace: NO_EXPANSION,
-            mod_path: Vec::new(),
             ecfg: ecfg,
             crate_root: None,
             exported_macros: Vec::new(),
             loader: loader,
-            syntax_env: env,
             derive_modes: HashMap::new(),
             recursion_count: 0,
-
-            directory: PathBuf::new(),
-            in_block: false,
         }
     }
 
@@ -666,14 +645,6 @@ impl<'a> ExtCtxt<'a> {
         last_macro.expect("missing expansion backtrace")
     }
 
-    pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
-    pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
-    pub fn mod_path(&self) -> Vec {
-        let mut v = Vec::new();
-        v.push(token::str_to_ident(&self.ecfg.crate_name));
-        v.extend(self.mod_path.iter().cloned());
-        return v;
-    }
     pub fn bt_push(&mut self, ei: ExpnInfo) {
         self.recursion_count += 1;
         if self.recursion_count > self.ecfg.recursion_limit {
@@ -818,6 +789,30 @@ impl<'a> ExtCtxt<'a> {
             }
         }
     }
+
+    pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) {
+        if std_inject::no_core(&krate) {
+            self.crate_root = None;
+        } else if std_inject::no_std(&krate) {
+            self.crate_root = Some("core");
+        } else {
+            self.crate_root = Some("std");
+        }
+
+        // User extensions must be added before expander.load_macros is called,
+        // so that macros from external crates shadow user defined extensions.
+        for (name, extension) in user_exts {
+            self.syntax_env.insert(name, extension);
+        }
+
+        self.syntax_env.current_module = Module(0);
+        let mut paths = ModulePaths {
+            mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
+            directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
+        };
+        paths.directory.pop();
+        self.syntax_env.module_data[0].paths = Rc::new(paths);
+    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
@@ -904,79 +899,103 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 ///
 /// This environment maps Names to SyntaxExtensions.
 pub struct SyntaxEnv {
-    chain: Vec,
+    module_data: Vec,
+    current_module: Module,
+
     /// All bang-style macro/extension names
     /// encountered so far; to be used for diagnostics in resolve
     pub names: HashSet,
 }
 
-// impl question: how to implement it? Initially, the
-// env will contain only macros, so it might be painful
-// to add an empty frame for every context. Let's just
-// get it working, first....
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct Module(u32);
 
-// NB! the mutability of the underlying maps means that
-// if expansion is out-of-order, a deeper scope may be
-// able to refer to a macro that was added to an enclosing
-// scope lexically later than the deeper scope.
+struct ModuleData {
+    parent: Module,
+    paths: Rc,
+    macros: HashMap>,
+    macros_escape: bool,
+    in_block: bool,
+}
 
-struct MapChainFrame {
-    info: BlockInfo,
-    map: HashMap>,
+#[derive(Clone)]
+pub struct ModulePaths {
+    pub mod_path: Vec,
+    pub directory: PathBuf,
 }
 
 impl SyntaxEnv {
     fn new() -> SyntaxEnv {
-        let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()};
-        map.push_frame();
-        map
+        let mut env = SyntaxEnv {
+            current_module: Module(0),
+            module_data: Vec::new(),
+            names: HashSet::new(),
+        };
+        let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() });
+        env.add_module(false, false, paths);
+        env
     }
 
-    pub fn push_frame(&mut self) {
-        self.chain.push(MapChainFrame {
-            info: BlockInfo::new(),
-            map: HashMap::new(),
-        });
+    fn data(&self, module: Module) -> &ModuleData {
+        &self.module_data[module.0 as usize]
     }
 
-    pub fn pop_frame(&mut self) {
-        assert!(self.chain.len() > 1, "too many pops on MapChain!");
-        self.chain.pop();
+    pub fn set_current_module(&mut self, module: Module) -> Module {
+        ::std::mem::replace(&mut self.current_module, module)
     }
 
-    fn find_escape_frame(&mut self) -> &mut MapChainFrame {
-        for (i, frame) in self.chain.iter_mut().enumerate().rev() {
-            if !frame.info.macros_escape || i == 0 {
-                return frame
-            }
-        }
-        unreachable!()
+    pub fn paths(&self) -> Rc {
+        self.data(self.current_module).paths.clone()
+    }
+
+    pub fn in_block(&self) -> bool {
+        self.data(self.current_module).in_block
     }
 
-    pub fn find(&self, k: Name) -> Option> {
-        for frame in self.chain.iter().rev() {
-            if let Some(v) = frame.map.get(&k) {
-                return Some(v.clone());
+    pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc)
+                      -> Module {
+        let data = ModuleData {
+            parent: self.current_module,
+            paths: paths,
+            macros: HashMap::new(),
+            macros_escape: macros_escape,
+            in_block: in_block,
+        };
+
+        self.module_data.push(data);
+        Module(self.module_data.len() as u32 - 1)
+    }
+
+    pub fn find(&self, name: Name) -> Option> {
+        let mut module = self.current_module;
+        let mut module_data;
+        loop {
+            module_data = self.data(module);
+            if let Some(ext) = module_data.macros.get(&name) {
+                return Some(ext.clone());
             }
+            if module == module_data.parent {
+                return None;
+            }
+            module = module_data.parent;
         }
-        None
     }
 
-    pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
-        if let NormalTT(..) = v {
-            self.names.insert(k);
+    pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
+        if let NormalTT(..) = ext {
+            self.names.insert(name);
         }
-        self.find_escape_frame().map.insert(k, Rc::new(v));
-    }
 
-    pub fn info(&mut self) -> &mut BlockInfo {
-        let last_chain_index = self.chain.len() - 1;
-        &mut self.chain[last_chain_index].info
+        let mut module = self.current_module;
+        while self.data(module).macros_escape {
+            module = self.data(module).parent;
+        }
+        self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
     }
 
     pub fn is_crate_root(&mut self) -> bool {
         // The first frame is pushed in `SyntaxEnv::new()` and the second frame is
         // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
-        self.chain.len() <= 2
+        self.current_module.0 <= 1
     }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d3f8618aace95..a713196032c86 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -26,9 +26,9 @@ use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
 use visit;
 use visit::Visitor;
-use std_inject;
 
 use std::path::PathBuf;
+use std::rc::Rc;
 
 macro_rules! expansions {
     ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
@@ -467,24 +467,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
         false
     }
-
-    fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
-        self.cx.syntax_env.push_frame();
-        self.cx.syntax_env.info().macros_escape = macros_escape;
-        let result = f(self);
-        self.cx.syntax_env.pop_frame();
-        result
-    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
-    fn fold_crate(&mut self, c: Crate) -> Crate {
-        let mut directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(c.span));
-        directory.pop();
-        self.cx.directory = directory;
-        noop_fold_crate(c, self)
-    }
-
     fn fold_expr(&mut self, expr: P) -> P {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
@@ -542,9 +527,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_block(&mut self, block: P) -> P {
-        let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
-        let result = self.with_exts_frame(false, |this| noop_fold_block(block, this));
-        self.cx.in_block = was_in_block;
+        let paths = self.cx.syntax_env.paths();
+        let module = self.cx.syntax_env.add_module(false, true, paths);
+        let orig_module = self.cx.syntax_env.set_current_module(module);
+
+        let result = noop_fold_block(block, self);
+        self.cx.syntax_env.set_current_module(orig_module);
         result
     }
 
@@ -578,26 +566,27 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                 })
             }
             ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
-                self.cx.mod_push(item.ident);
-                let macro_use = self.contains_macro_use(&item.attrs);
-
-                let directory = self.cx.directory.clone();
+                let mut paths = (*self.cx.syntax_env.paths()).clone();
+                paths.mod_path.push(item.ident);
                 if item.span.contains(inner) {
-                    self.cx.directory.push(&*{
+                    paths.directory.push(&*{
                         ::attr::first_attr_value_str_by_name(&item.attrs, "path")
                             .unwrap_or(item.ident.name.as_str())
                     });
                 } else {
-                    self.cx.directory = match inner {
+                    paths.directory = match inner {
                         syntax_pos::DUMMY_SP => PathBuf::new(),
                         _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
                     };
-                    self.cx.directory.pop();
+                    paths.directory.pop();
                 }
-                let result = self.with_exts_frame(macro_use, |this| noop_fold_item(item, this));
-                self.cx.directory = directory;
 
-                self.cx.mod_pop();
+                let macro_use = self.contains_macro_use(&item.attrs);
+                let in_block = self.cx.syntax_env.in_block();
+                let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
+                let module = self.cx.syntax_env.set_current_module(module);
+                let result = noop_fold_item(item, self);
+                self.cx.syntax_env.set_current_module(module);
                 result
             },
             _ => noop_fold_item(item, self),
@@ -744,19 +733,7 @@ pub fn expand_crate(cx: &mut ExtCtxt,
 pub fn expand_crate_with_expander(expander: &mut MacroExpander,
                                   user_exts: Vec,
                                   mut c: Crate) -> Crate {
-    if std_inject::no_core(&c) {
-        expander.cx.crate_root = None;
-    } else if std_inject::no_std(&c) {
-        expander.cx.crate_root = Some("core");
-    } else {
-        expander.cx.crate_root = Some("std");
-    }
-
-    // User extensions must be added before expander.load_macros is called,
-    // so that macros from external crates shadow user defined extensions.
-    for (name, extension) in user_exts {
-        expander.cx.syntax_env.insert(name, extension);
-    }
+    expander.cx.initialize(user_exts, &c);
 
     let items = Expansion::Items(SmallVector::many(c.module.items));
     let configured = items.fold_with(&mut expander.strip_unconfigured());
@@ -765,12 +742,11 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);
-    ret.exported_macros = expander.cx.exported_macros.clone();
-
     if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
         expander.cx.parse_sess.span_diagnostic.abort_if_errors();
     }
 
+    ret.exported_macros = expander.cx.exported_macros.clone();
     ret
 }
 
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 97cb09991ec40..105b226111738 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -74,11 +74,9 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre
 pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
                   -> Box {
     base::check_zero_tts(cx, sp, tts, "module_path!");
-    let string = cx.mod_path()
-                   .iter()
-                   .map(|x| x.to_string())
-                   .collect::>()
-                   .join("::");
+    let paths = cx.syntax_env.paths();
+    let string = paths.mod_path.iter().map(|x| x.to_string()).collect::>().join("::");
+
     base::MacEager::expr(cx.expr_str(
             sp,
             token::intern_and_get_ident(&string[..])))
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index a4be84dfbf02f..ed80ec9cbc49e 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                                            imported_from,
                                            rhs);
                 let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
-                p.directory = cx.directory.clone();
-                p.restrictions = match cx.in_block {
+                p.directory = cx.syntax_env.paths().directory.clone();
+                p.restrictions = match cx.syntax_env.in_block() {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
                 };

From 7a3ae576fa729e0465719f97aa7bb80c9721b446 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Thu, 1 Sep 2016 07:01:45 +0000
Subject: [PATCH 565/768] Refactor `expand_invoc(.., fld)` ->
 `self.expand_invoc(..)`.

---
 src/libsyntax/ext/expand.rs | 419 ++++++++++++++++++------------------
 1 file changed, 212 insertions(+), 207 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index a713196032c86..17b2b2d25b990 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -143,199 +143,6 @@ enum InvocationKind {
     },
 }
 
-fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    match invoc.kind {
-        InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
-        InvocationKind::Attr { .. } => expand_attr_invoc(invoc, fld),
-    }
-}
-
-fn expand_attr_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    let Invocation { expansion_kind: kind, .. } = invoc;
-    let (attr, item) = match invoc.kind {
-        InvocationKind::Attr { attr, item } => (attr, item),
-        _ => unreachable!(),
-    };
-
-    let extension = match fld.cx.syntax_env.find(intern(&attr.name())) {
-        Some(extension) => extension,
-        None => unreachable!(),
-    };
-
-    attr::mark_used(&attr);
-    fld.cx.bt_push(ExpnInfo {
-        call_site: attr.span,
-        callee: NameAndSpan {
-            format: MacroAttribute(intern(&attr.name())),
-            span: Some(attr.span),
-            allow_internal_unstable: false,
-        }
-    });
-
-    let modified = match *extension {
-        MultiModifier(ref mac) => {
-            kind.expect_from_annotatables(mac.expand(fld.cx, attr.span, &attr.node.value, item))
-        }
-        MultiDecorator(ref mac) => {
-            let mut items = Vec::new();
-            mac.expand(fld.cx, attr.span, &attr.node.value, &item, &mut |item| items.push(item));
-            items.push(item);
-            kind.expect_from_annotatables(items)
-        }
-        _ => unreachable!(),
-    };
-
-    fld.cx.bt_pop();
-
-    let configured = modified.fold_with(&mut fld.strip_unconfigured());
-    configured.fold_with(fld)
-}
-
-/// Expand a macro invocation. Returns the result of expansion.
-fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    let Invocation { mark, expansion_kind: kind, .. } = invoc;
-    let (attrs, mac, ident, span) = match invoc.kind {
-        InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
-        _ => unreachable!(),
-    };
-    let Mac_ { path, tts, .. } = mac.node;
-
-    // Detect use of feature-gated or invalid attributes on macro invoations
-    // since they will not be detected after macro expansion.
-    for attr in attrs.iter() {
-        feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
-                                      &fld.cx.parse_sess.codemap(),
-                                      &fld.cx.ecfg.features.unwrap());
-    }
-
-    if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
-        fld.cx.span_err(path.span, "expected macro name without module separators");
-        return kind.dummy(span);
-    }
-
-    let extname = path.segments[0].identifier.name;
-    let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
-        extension
-    } else {
-        let mut err =
-            fld.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
-        fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
-        err.emit();
-        return kind.dummy(span);
-    };
-
-    let ident = ident.unwrap_or(keywords::Invalid.ident());
-    let marked_tts = mark_tts(&tts, mark);
-    let opt_expanded = match *extension {
-        NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
-            if ident.name != keywords::Invalid.name() {
-                let msg =
-                    format!("macro {}! expects no ident argument, given '{}'", extname, ident);
-                fld.cx.span_err(path.span, &msg);
-                return kind.dummy(span);
-            }
-
-            fld.cx.bt_push(ExpnInfo {
-                call_site: span,
-                callee: NameAndSpan {
-                    format: MacroBang(extname),
-                    span: exp_span,
-                    allow_internal_unstable: allow_internal_unstable,
-                },
-            });
-
-            kind.make_from(expandfun.expand(fld.cx, span, &marked_tts))
-        }
-
-        IdentTT(ref expander, tt_span, allow_internal_unstable) => {
-            if ident.name == keywords::Invalid.name() {
-                fld.cx.span_err(path.span,
-                                &format!("macro {}! expects an ident argument", extname));
-                return kind.dummy(span);
-            };
-
-            fld.cx.bt_push(ExpnInfo {
-                call_site: span,
-                callee: NameAndSpan {
-                    format: MacroBang(extname),
-                    span: tt_span,
-                    allow_internal_unstable: allow_internal_unstable,
-                }
-            });
-
-            kind.make_from(expander.expand(fld.cx, span, ident, marked_tts))
-        }
-
-        MacroRulesTT => {
-            if ident.name == keywords::Invalid.name() {
-                fld.cx.span_err(path.span,
-                                &format!("macro {}! expects an ident argument", extname));
-                return kind.dummy(span);
-            };
-
-            fld.cx.bt_push(ExpnInfo {
-                call_site: span,
-                callee: NameAndSpan {
-                    format: MacroBang(extname),
-                    span: None,
-                    // `macro_rules!` doesn't directly allow unstable
-                    // (this is orthogonal to whether the macro it creates allows it)
-                    allow_internal_unstable: false,
-                }
-            });
-
-            let def = ast::MacroDef {
-                ident: ident,
-                id: ast::DUMMY_NODE_ID,
-                span: span,
-                imported_from: None,
-                use_locally: true,
-                body: marked_tts,
-                export: attr::contains_name(&attrs, "macro_export"),
-                allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-                attrs: attrs,
-            };
-
-            fld.cx.insert_macro(def.clone());
-
-            // If keep_macs is true, expands to a MacEager::items instead.
-            if fld.keep_macs {
-                Some(reconstruct_macro_rules(&def, &path))
-            } else {
-                Some(macro_scope_placeholder())
-            }
-        }
-
-        MultiDecorator(..) | MultiModifier(..) => {
-            fld.cx.span_err(path.span,
-                            &format!("`{}` can only be used in attributes", extname));
-            return kind.dummy(span);
-        }
-    };
-
-    let expanded = if let Some(expanded) = opt_expanded {
-        expanded
-    } else {
-        let msg = format!("non-{kind} macro in {kind} position: {name}",
-                          name = path.segments[0].identifier.name, kind = kind.name());
-        fld.cx.span_err(path.span, &msg);
-        return kind.dummy(span);
-    };
-
-    let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
-    let configured = marked.fold_with(&mut fld.strip_unconfigured());
-    fld.load_macros(&configured);
-
-    let fully_expanded = if fld.single_step {
-        configured
-    } else {
-        configured.fold_with(fld)
-    };
-
-    fld.cx.bt_pop();
-    fully_expanded
-}
-
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
@@ -467,6 +274,204 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
         false
     }
+
+    fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
+        match invoc.kind {
+            InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
+            InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc),
+        }
+    }
+
+    fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
+        let Invocation { expansion_kind: kind, .. } = invoc;
+        let (attr, item) = match invoc.kind {
+            InvocationKind::Attr { attr, item } => (attr, item),
+            _ => unreachable!(),
+        };
+
+        let extension = match self.cx.syntax_env.find(intern(&attr.name())) {
+            Some(extension) => extension,
+            None => unreachable!(),
+        };
+
+        attr::mark_used(&attr);
+        self.cx.bt_push(ExpnInfo {
+            call_site: attr.span,
+            callee: NameAndSpan {
+                format: MacroAttribute(intern(&attr.name())),
+                span: Some(attr.span),
+                allow_internal_unstable: false,
+            }
+        });
+
+        let modified = match *extension {
+            MultiModifier(ref mac) => {
+                let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
+                kind.expect_from_annotatables(item)
+            }
+            MultiDecorator(ref mac) => {
+                let mut items = Vec::new();
+                mac.expand(self.cx, attr.span, &attr.node.value, &item,
+                           &mut |item| items.push(item));
+                items.push(item);
+                kind.expect_from_annotatables(items)
+            }
+            _ => unreachable!(),
+        };
+
+        self.cx.bt_pop();
+
+        let configured = modified.fold_with(&mut self.strip_unconfigured());
+        configured.fold_with(self)
+    }
+
+    /// Expand a macro invocation. Returns the result of expansion.
+    fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
+        let Invocation { mark, expansion_kind: kind, .. } = invoc;
+        let (attrs, mac, ident, span) = match invoc.kind {
+            InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
+            _ => unreachable!(),
+        };
+        let Mac_ { path, tts, .. } = mac.node;
+
+        // Detect use of feature-gated or invalid attributes on macro invoations
+        // since they will not be detected after macro expansion.
+        for attr in attrs.iter() {
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess.span_diagnostic,
+                                          &self.cx.parse_sess.codemap(),
+                                          &self.cx.ecfg.features.unwrap());
+        }
+
+        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
+            self.cx.span_err(path.span, "expected macro name without module separators");
+            return kind.dummy(span);
+        }
+
+        let extname = path.segments[0].identifier.name;
+        let extension = if let Some(extension) = self.cx.syntax_env.find(extname) {
+            extension
+        } else {
+            let mut err =
+                self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
+            self.cx.suggest_macro_name(&extname.as_str(), &mut err);
+            err.emit();
+            return kind.dummy(span);
+        };
+
+        let ident = ident.unwrap_or(keywords::Invalid.ident());
+        let marked_tts = mark_tts(&tts, mark);
+        let opt_expanded = match *extension {
+            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
+                if ident.name != keywords::Invalid.name() {
+                    let msg =
+                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
+                    self.cx.span_err(path.span, &msg);
+                    return kind.dummy(span);
+                }
+
+                self.cx.bt_push(ExpnInfo {
+                    call_site: span,
+                    callee: NameAndSpan {
+                        format: MacroBang(extname),
+                        span: exp_span,
+                        allow_internal_unstable: allow_internal_unstable,
+                    },
+                });
+
+                kind.make_from(expandfun.expand(self.cx, span, &marked_tts))
+            }
+
+            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+                if ident.name == keywords::Invalid.name() {
+                    self.cx.span_err(path.span,
+                                    &format!("macro {}! expects an ident argument", extname));
+                    return kind.dummy(span);
+                };
+
+                self.cx.bt_push(ExpnInfo {
+                    call_site: span,
+                    callee: NameAndSpan {
+                        format: MacroBang(extname),
+                        span: tt_span,
+                        allow_internal_unstable: allow_internal_unstable,
+                    }
+                });
+
+                kind.make_from(expander.expand(self.cx, span, ident, marked_tts))
+            }
+
+            MacroRulesTT => {
+                if ident.name == keywords::Invalid.name() {
+                    self.cx.span_err(path.span,
+                                    &format!("macro {}! expects an ident argument", extname));
+                    return kind.dummy(span);
+                };
+
+                self.cx.bt_push(ExpnInfo {
+                    call_site: span,
+                    callee: NameAndSpan {
+                        format: MacroBang(extname),
+                        span: None,
+                        // `macro_rules!` doesn't directly allow unstable
+                        // (this is orthogonal to whether the macro it creates allows it)
+                        allow_internal_unstable: false,
+                    }
+                });
+
+                let def = ast::MacroDef {
+                    ident: ident,
+                    id: ast::DUMMY_NODE_ID,
+                    span: span,
+                    imported_from: None,
+                    use_locally: true,
+                    body: marked_tts,
+                    export: attr::contains_name(&attrs, "macro_export"),
+                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
+                    attrs: attrs,
+                };
+
+                self.cx.insert_macro(def.clone());
+
+                // If keep_macs is true, expands to a MacEager::items instead.
+                if self.keep_macs {
+                    Some(reconstruct_macro_rules(&def, &path))
+                } else {
+                    Some(macro_scope_placeholder())
+                }
+            }
+
+            MultiDecorator(..) | MultiModifier(..) => {
+                self.cx.span_err(path.span,
+                                 &format!("`{}` can only be used in attributes", extname));
+                return kind.dummy(span);
+            }
+        };
+
+        let expanded = if let Some(expanded) = opt_expanded {
+            expanded
+        } else {
+            let msg = format!("non-{kind} macro in {kind} position: {name}",
+                              name = path.segments[0].identifier.name, kind = kind.name());
+            self.cx.span_err(path.span, &msg);
+            return kind.dummy(span);
+        };
+
+        let marked = expanded.fold_with(&mut Marker {
+            mark: mark,
+            expn_id: Some(self.cx.backtrace())
+        });
+        let configured = marked.fold_with(&mut self.strip_unconfigured());
+        self.load_macros(&configured);
+
+        let fully_expanded = if self.single_step {
+            configured
+        } else {
+            configured.fold_with(self)
+        };
+
+        self.cx.bt_pop();
+        fully_expanded
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -474,7 +479,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
             let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-            expand_invoc(invoc, self).make_expr()
+            self.expand_invoc(invoc).make_expr()
         } else {
             P(noop_fold_expr(expr, self))
         }
@@ -485,7 +490,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         if let ast::ExprKind::Mac(mac) = expr.node {
             let invoc =
                 self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-            expand_invoc(invoc, self).make_opt_expr()
+            self.expand_invoc(invoc).make_opt_expr()
         } else {
             Some(P(noop_fold_expr(expr, self)))
         }
@@ -494,13 +499,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_pat(&mut self, pat: P) -> P {
         match pat.node {
             PatKind::Mac(_) => {}
-            _ => return noop_fold_pat(pat, self)
+            _ => return noop_fold_pat(pat, self),
         }
 
         pat.and_then(|pat| match pat.node {
             PatKind::Mac(mac) => {
                 let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
-                expand_invoc(invoc, self).make_pat()
+                self.expand_invoc(invoc).make_pat()
             }
             _ => unreachable!(),
         })
@@ -509,11 +514,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {
         let (mac, style, attrs) = match stmt.node {
             StmtKind::Mac(mac) => mac.unwrap(),
-            _ => return noop_fold_stmt(stmt, self)
+            _ => return noop_fold_stmt(stmt, self),
         };
 
         let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-        let mut fully_expanded = expand_invoc(invoc, self).make_stmts();
+        let mut fully_expanded = self.expand_invoc(invoc).make_stmts();
 
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
@@ -540,7 +545,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
-            return expand_invoc(invoc, self).make_items();
+            return self.expand_invoc(invoc).make_items();
         }
 
         match item.node {
@@ -560,7 +565,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                             ident: Some(item.ident),
                             span: item.span,
                         });
-                        expand_invoc(invoc, self).make_items()
+                        self.expand_invoc(invoc).make_items()
                     }
                     _ => unreachable!(),
                 })
@@ -598,14 +603,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         if let Some(attr) = attr {
             let item = Annotatable::TraitItem(P(item));
             let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
-            return expand_invoc(invoc, self).make_trait_items();
+            return self.expand_invoc(invoc).make_trait_items();
         }
 
         match item.node {
             ast::TraitItemKind::Macro(mac) => {
                 let ast::TraitItem { attrs, span, .. } = item;
                 let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
-                expand_invoc(invoc, self).make_trait_items()
+                self.expand_invoc(invoc).make_trait_items()
             }
             _ => fold::noop_fold_trait_item(item, self),
         }
@@ -616,16 +621,16 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         if let Some(attr) = attr {
             let item = Annotatable::ImplItem(P(item));
             let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
-            return expand_invoc(invoc, self).make_impl_items();
+            return self.expand_invoc(invoc).make_impl_items();
         }
 
         match item.node {
             ast::ImplItemKind::Macro(mac) => {
                 let ast::ImplItem { attrs, span, .. } = item;
                 let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
-                expand_invoc(invoc, self).make_impl_items()
+                self.expand_invoc(invoc).make_impl_items()
             }
-            _ => fold::noop_fold_impl_item(item, self)
+            _ => fold::noop_fold_impl_item(item, self),
         }
     }
 
@@ -638,7 +643,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         match ty.node {
             ast::TyKind::Mac(mac) => {
                 let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
-                expand_invoc(invoc, self).make_ty()
+                self.expand_invoc(invoc).make_ty()
             }
             _ => unreachable!(),
         }

From c07ff8d26a6d5c8728419ae4e870b3a65940efbc Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Mon, 29 Aug 2016 05:32:41 +0000
Subject: [PATCH 566/768] Add module `ext::placeholders` with  `placeholder()`
 and `PlaceholderExpander`.

---
 src/libsyntax/ext/expand.rs       |  48 ++-------
 src/libsyntax/ext/placeholders.rs | 172 ++++++++++++++++++++++++++++++
 src/libsyntax/lib.rs              |   1 +
 3 files changed, 182 insertions(+), 39 deletions(-)
 create mode 100644 src/libsyntax/ext/placeholders.rs

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 17b2b2d25b990..c5fc149bb7e8b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -12,8 +12,9 @@ use ast::{Block, Crate, Ident, Mac_, PatKind};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
+use ext::placeholders;
 use attr::{self, HasAttrs};
-use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
+use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
 use ext::base::*;
@@ -35,8 +36,8 @@ macro_rules! expansions {
             $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
             $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
         #[derive(Copy, Clone)]
-        enum ExpansionKind { OptExpr, $( $kind, )*  }
-        enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
+        pub enum ExpansionKind { OptExpr, $( $kind, )*  }
+        pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
 
         impl ExpansionKind {
             fn name(self) -> &'static str {
@@ -55,20 +56,20 @@ macro_rules! expansions {
         }
 
         impl Expansion {
-            fn make_opt_expr(self) -> Option> {
+            pub fn make_opt_expr(self) -> Option> {
                 match self {
                     Expansion::OptExpr(expr) => expr,
                     _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
                 }
             }
-            $( fn $make(self) -> $ty {
+            $( pub fn $make(self) -> $ty {
                 match self {
                     Expansion::$kind(ast) => ast,
                     _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
                 }
             } )*
 
-            fn fold_with(self, folder: &mut F) -> Self {
+            pub fn fold_with(self, folder: &mut F) -> Self {
                 use self::Expansion::*;
                 match self {
                     OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
@@ -434,9 +435,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
                 // If keep_macs is true, expands to a MacEager::items instead.
                 if self.keep_macs {
-                    Some(reconstruct_macro_rules(&def, &path))
+                    Some(placeholders::reconstructed_macro_rules(&def, &path))
                 } else {
-                    Some(macro_scope_placeholder())
+                    Some(placeholders::macro_scope_placeholder())
                 }
             }
 
@@ -650,37 +651,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
-fn macro_scope_placeholder() -> Expansion {
-    Expansion::Items(SmallVector::one(P(ast::Item {
-        ident: keywords::Invalid.ident(),
-        attrs: Vec::new(),
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
-            path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
-            tts: Vec::new(),
-        })),
-        vis: ast::Visibility::Inherited,
-        span: syntax_pos::DUMMY_SP,
-    })))
-}
-
-fn reconstruct_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
-    Expansion::Items(SmallVector::one(P(ast::Item {
-        ident: def.ident,
-        attrs: def.attrs.clone(),
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ItemKind::Mac(ast::Mac {
-            span: def.span,
-            node: ast::Mac_ {
-                path: path.clone(),
-                tts: def.body.clone(),
-            }
-        }),
-        vis: ast::Visibility::Inherited,
-        span: def.span,
-    })))
-}
-
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
new file mode 100644
index 0000000000000..f1665bdde7510
--- /dev/null
+++ b/src/libsyntax/ext/placeholders.rs
@@ -0,0 +1,172 @@
+// 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.
+
+use ast;
+use codemap::{DUMMY_SP, dummy_spanned};
+use ext::expand::{Expansion, ExpansionKind};
+use fold::*;
+use parse::token::keywords;
+use ptr::P;
+use util::small_vector::SmallVector;
+
+use std::collections::HashMap;
+
+pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
+    fn mac_placeholder() -> ast::Mac {
+        dummy_spanned(ast::Mac_ {
+            path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() },
+            tts: Vec::new(),
+        })
+    }
+
+    let ident = keywords::Invalid.ident();
+    let attrs = Vec::new();
+    let vis = ast::Visibility::Inherited;
+    let span = DUMMY_SP;
+    let expr_placeholder = || P(ast::Expr {
+        id: id, span: span,
+        attrs: ast::ThinVec::new(),
+        node: ast::ExprKind::Mac(mac_placeholder()),
+    });
+
+    match kind {
+        ExpansionKind::Expr => Expansion::Expr(expr_placeholder()),
+        ExpansionKind::OptExpr => Expansion::OptExpr(Some(expr_placeholder())),
+        ExpansionKind::Items => Expansion::Items(SmallVector::one(P(ast::Item {
+            id: id, span: span, ident: ident, vis: vis, attrs: attrs,
+            node: ast::ItemKind::Mac(mac_placeholder()),
+        }))),
+        ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem {
+            id: id, span: span, ident: ident, attrs: attrs,
+            node: ast::TraitItemKind::Macro(mac_placeholder()),
+        })),
+        ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem {
+            id: id, span: span, ident: ident, vis: vis, attrs: attrs,
+            node: ast::ImplItemKind::Macro(mac_placeholder()),
+            defaultness: ast::Defaultness::Final,
+        })),
+        ExpansionKind::Pat => Expansion::Pat(P(ast::Pat {
+            id: id, span: span, node: ast::PatKind::Mac(mac_placeholder()),
+        })),
+        ExpansionKind::Ty => Expansion::Ty(P(ast::Ty {
+            id: id, span: span, node: ast::TyKind::Mac(mac_placeholder()),
+        })),
+        ExpansionKind::Stmts => Expansion::Stmts(SmallVector::one({
+            let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new()));
+            ast::Stmt { id: id, span: span, node: ast::StmtKind::Mac(mac) }
+        })),
+    }
+}
+
+pub fn macro_scope_placeholder() -> Expansion {
+    placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
+}
+
+pub struct PlaceholderExpander {
+    expansions: HashMap,
+}
+
+impl PlaceholderExpander {
+    pub fn new(expansions: HashMap) -> Self {
+        PlaceholderExpander {
+            expansions: expansions,
+        }
+    }
+
+    pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
+        let expansion = self.expansions.remove(&id).unwrap();
+        expansion.fold_with(self)
+    }
+}
+
+impl Folder for PlaceholderExpander {
+    fn fold_item(&mut self, item: P) -> SmallVector> {
+        match item.node {
+            // Scope placeholder
+            ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item),
+            ast::ItemKind::Mac(_) => self.remove(item.id).make_items(),
+            _ => noop_fold_item(item, self),
+        }
+    }
+
+    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector {
+        match item.node {
+            ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
+            _ => noop_fold_trait_item(item, self),
+        }
+    }
+
+    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector {
+        match item.node {
+            ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
+            _ => noop_fold_impl_item(item, self),
+        }
+    }
+
+    fn fold_expr(&mut self, expr: P) -> P {
+        match expr.node {
+            ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
+            _ => expr.map(|expr| noop_fold_expr(expr, self)),
+        }
+    }
+
+    fn fold_opt_expr(&mut self, expr: P) -> Option> {
+        match expr.node {
+            ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(),
+            _ => noop_fold_opt_expr(expr, self),
+        }
+    }
+
+    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {
+        let (style, mut expansion) = match stmt.node {
+            ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()),
+            _ => return noop_fold_stmt(stmt, self),
+        };
+
+        if style == ast::MacStmtStyle::Semicolon {
+            if let Some(stmt) = expansion.pop() {
+                expansion.push(stmt.add_trailing_semicolon());
+            }
+        }
+
+        expansion
+    }
+
+    fn fold_pat(&mut self, pat: P) -> P {
+        match pat.node {
+            ast::PatKind::Mac(_) => self.remove(pat.id).make_pat(),
+            _ => noop_fold_pat(pat, self),
+        }
+    }
+
+    fn fold_ty(&mut self, ty: P) -> P {
+        match ty.node {
+            ast::TyKind::Mac(_) => self.remove(ty.id).make_ty(),
+            _ => noop_fold_ty(ty, self),
+        }
+    }
+}
+
+pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: def.ident,
+        attrs: def.attrs.clone(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(ast::Mac {
+            span: def.span,
+            node: ast::Mac_ {
+                path: path.clone(),
+                tts: def.body.clone(),
+            }
+        }),
+        vis: ast::Visibility::Inherited,
+        span: def.span,
+    })))
+}
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 65bc9f34c9061..42201231247af 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -126,6 +126,7 @@ pub mod ext {
     pub mod base;
     pub mod build;
     pub mod expand;
+    pub mod placeholders;
     pub mod hygiene;
     pub mod proc_macro_shim;
     pub mod quote;

From d986bbe674d4fd554342771e7c031b3d22f9a800 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 2 Sep 2016 09:12:47 +0000
Subject: [PATCH 567/768] Implement stackless expansion.

---
 src/libsyntax/ext/base.rs    |  25 +--
 src/libsyntax/ext/expand.rs  | 333 +++++++++++++++++++----------------
 src/libsyntax/ext/hygiene.rs |   4 +
 src/libsyntax/test.rs        |   7 +-
 4 files changed, 191 insertions(+), 178 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index fe2806891b85e..edd38ea23e2fd 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -646,7 +646,6 @@ impl<'a> ExtCtxt<'a> {
     }
 
     pub fn bt_push(&mut self, ei: ExpnInfo) {
-        self.recursion_count += 1;
         if self.recursion_count > self.ecfg.recursion_limit {
             self.span_fatal(ei.call_site,
                             &format!("recursion limit reached while expanding the macro `{}`",
@@ -660,17 +659,7 @@ impl<'a> ExtCtxt<'a> {
             callee: ei.callee
         });
     }
-    pub fn bt_pop(&mut self) {
-        match self.backtrace {
-            NO_EXPANSION => self.bug("tried to pop without a push"),
-            expn_id => {
-                self.recursion_count -= 1;
-                self.backtrace = self.codemap().with_expn_info(expn_id, |expn_info| {
-                    expn_info.map_or(NO_EXPANSION, |ei| ei.call_site.expn_id)
-                });
-            }
-        }
-    }
+    pub fn bt_pop(&mut self) {}
 
     pub fn insert_macro(&mut self, def: ast::MacroDef) {
         if def.export {
@@ -799,8 +788,6 @@ impl<'a> ExtCtxt<'a> {
             self.crate_root = Some("std");
         }
 
-        // User extensions must be added before expander.load_macros is called,
-        // so that macros from external crates shadow user defined extensions.
         for (name, extension) in user_exts {
             self.syntax_env.insert(name, extension);
         }
@@ -900,7 +887,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 /// This environment maps Names to SyntaxExtensions.
 pub struct SyntaxEnv {
     module_data: Vec,
-    current_module: Module,
+    pub current_module: Module,
 
     /// All bang-style macro/extension names
     /// encountered so far; to be used for diagnostics in resolve
@@ -940,10 +927,6 @@ impl SyntaxEnv {
         &self.module_data[module.0 as usize]
     }
 
-    pub fn set_current_module(&mut self, module: Module) -> Module {
-        ::std::mem::replace(&mut self.current_module, module)
-    }
-
     pub fn paths(&self) -> Rc {
         self.data(self.current_module).paths.clone()
     }
@@ -994,8 +977,6 @@ impl SyntaxEnv {
     }
 
     pub fn is_crate_root(&mut self) -> bool {
-        // The first frame is pushed in `SyntaxEnv::new()` and the second frame is
-        // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
-        self.current_module.0 <= 1
+        self.current_module == Module(0)
     }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index c5fc149bb7e8b..5624c2634661a 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -12,7 +12,7 @@ use ast::{Block, Crate, Ident, Mac_, PatKind};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
-use ext::placeholders;
+use ext::placeholders::{self, placeholder, PlaceholderExpander};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
@@ -28,11 +28,13 @@ use util::small_vector::SmallVector;
 use visit;
 use visit::Visitor;
 
+use std::collections::HashMap;
+use std::mem;
 use std::path::PathBuf;
 use std::rc::Rc;
 
 macro_rules! expansions {
-    ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
+    ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
             $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
             $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
         #[derive(Copy, Clone)]
@@ -91,18 +93,32 @@ macro_rules! expansions {
                 }
             }
         }
+
+        impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
+            fn fold_opt_expr(&mut self, expr: P) -> Option> {
+                self.expand(Expansion::OptExpr(Some(expr))).make_opt_expr()
+            }
+            $($(fn $fold(&mut self, node: $ty) -> $ty {
+                self.expand(Expansion::$kind(node)).$make()
+            })*)*
+            $($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty {
+                self.expand(Expansion::$kind(SmallVector::one(node))).$make()
+            })*)*
+        }
     }
 }
 
 expansions! {
-    Expr: P, "expression", .make_expr, .fold_expr, .visit_expr;
-    Pat: P,   "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    Ty: P,     "type",       .make_ty,   .fold_ty,   .visit_ty;
-    Stmts: SmallVector, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
-    Items: SmallVector>, "item",   .make_items, lift .fold_item, lift .visit_item;
-    TraitItems: SmallVector,
+    Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr;
+    Pat: P   [], "pattern",    .make_pat,  .fold_pat,  .visit_pat;
+    Ty: P     [], "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Stmts: SmallVector [SmallVector, ast::Stmt],
+        "statement",  .make_stmts,       lift .fold_stmt,       lift .visit_stmt;
+    Items: SmallVector> [SmallVector, P],
+        "item",       .make_items,       lift .fold_item,       lift .visit_item;
+    TraitItems: SmallVector [SmallVector, ast::TraitItem],
         "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
-    ImplItems: SmallVector,
+    ImplItems: SmallVector [SmallVector, ast::ImplItem],
         "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
 }
 
@@ -129,6 +145,9 @@ pub struct Invocation {
     kind: InvocationKind,
     expansion_kind: ExpansionKind,
     mark: Mark,
+    module: Module,
+    backtrace: ExpnId,
+    depth: usize,
 }
 
 enum InvocationKind {
@@ -144,7 +163,6 @@ enum InvocationKind {
     },
 }
 
-/// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
     pub single_step: bool,
@@ -162,13 +180,57 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
     }
 
-    fn strip_unconfigured(&mut self) -> StripUnconfigured {
-        StripUnconfigured {
+    fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+        let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+
+        let items = Expansion::Items(SmallVector::many(krate.module.items));
+        krate.module.items = self.expand(items).make_items().into();
+        krate.exported_macros = self.cx.exported_macros.clone();
+
+        if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
+            self.cx.parse_sess.span_diagnostic.abort_if_errors();
+        }
+
+        krate
+    }
+
+    // Fully expand all the invocations in `expansion`.
+    fn expand(&mut self, expansion: Expansion) -> Expansion {
+        let (expansion, mut invocations) = self.collect_invocations(expansion);
+        invocations.reverse();
+
+        let mut expansions = HashMap::new();
+        while let Some(invoc) = invocations.pop() {
+            let Invocation { mark, module, depth, backtrace, .. } = invoc;
+            self.cx.syntax_env.current_module = module;
+            self.cx.recursion_count = depth;
+            self.cx.backtrace = backtrace;
+
+            let expansion = self.expand_invoc(invoc);
+
+            self.cx.syntax_env.current_module = module;
+            self.cx.recursion_count = depth + 1;
+            let (expansion, new_invocations) = self.collect_invocations(expansion);
+
+            expansions.insert(mark.as_u32(), expansion);
+            if !self.single_step {
+                invocations.extend(new_invocations.into_iter().rev());
+            }
+        }
+
+        expansion.fold_with(&mut PlaceholderExpander::new(expansions))
+    }
+
+    fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) {
+        let expansion = expansion.fold_with(&mut StripUnconfigured {
             config: &self.cx.cfg,
             should_test: self.cx.ecfg.should_test,
             sess: self.cx.parse_sess,
             features: self.cx.ecfg.features,
-        }
+        });
+        self.load_macros(&expansion);
+        let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() };
+        (expansion.fold_with(&mut collector), collector.invocations)
     }
 
     fn load_macros(&mut self, node: &Expansion) {
@@ -210,72 +272,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         });
     }
 
-    fn new_invoc(&self, expansion_kind: ExpansionKind, kind: InvocationKind)
-                 -> Invocation {
-        Invocation { mark: Mark::fresh(), kind: kind, expansion_kind: expansion_kind }
-    }
-
-    fn new_bang_invoc(
-        &self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind,
-    ) -> Invocation {
-        self.new_invoc(kind, InvocationKind::Bang {
-            attrs: attrs,
-            mac: mac,
-            ident: None,
-            span: span,
-        })
-    }
-
-    fn new_attr_invoc(&self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
-                      -> Invocation {
-        self.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item })
-    }
-
-    // If `item` is an attr invocation, remove and return the macro attribute.
-    fn classify_item(&self, mut item: T) -> (T, Option) {
-        let mut attr = None;
-        item = item.map_attrs(|mut attrs| {
-            for i in 0..attrs.len() {
-                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
-                    match *extension {
-                        MultiModifier(..) | MultiDecorator(..) => {
-                            attr = Some(attrs.remove(i));
-                            break;
-                        }
-                        _ => {}
-                    }
-                }
-            }
-            attrs
-        });
-        (item, attr)
-    }
-
-    // does this attribute list contain "macro_use" ?
-    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
-        for attr in attrs {
-            let mut is_use = attr.check_name("macro_use");
-            if attr.check_name("macro_escape") {
-                let msg = "macro_escape is a deprecated synonym for macro_use";
-                let mut err = self.cx.struct_span_warn(attr.span, msg);
-                is_use = true;
-                if let ast::AttrStyle::Inner = attr.node.style {
-                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
-                } else {
-                    err.emit();
-                }
-            };
-
-            if is_use {
-                if !attr.is_word() {
-                    self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
-                }
-                return true;
-            }
-        }
-        false
-    }
-
     fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
         match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
@@ -305,7 +301,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
         });
 
-        let modified = match *extension {
+        match *extension {
             MultiModifier(ref mac) => {
                 let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
                 kind.expect_from_annotatables(item)
@@ -318,12 +314,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 kind.expect_from_annotatables(items)
             }
             _ => unreachable!(),
-        };
-
-        self.cx.bt_pop();
-
-        let configured = modified.fold_with(&mut self.strip_unconfigured());
-        configured.fold_with(self)
+        }
     }
 
     /// Expand a macro invocation. Returns the result of expansion.
@@ -457,30 +448,94 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return kind.dummy(span);
         };
 
-        let marked = expanded.fold_with(&mut Marker {
+        expanded.fold_with(&mut Marker {
+            mark: mark,
+            expn_id: Some(self.cx.backtrace()),
+        })
+    }
+}
+
+struct InvocationCollector<'a, 'b: 'a> {
+    cx: &'a mut ExtCtxt<'b>,
+    invocations: Vec,
+}
+
+impl<'a, 'b> InvocationCollector<'a, 'b> {
+    fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion {
+        let mark = Mark::fresh();
+        self.invocations.push(Invocation {
+            kind: kind,
+            expansion_kind: expansion_kind,
             mark: mark,
-            expn_id: Some(self.cx.backtrace())
+            module: self.cx.syntax_env.current_module,
+            backtrace: self.cx.backtrace,
+            depth: self.cx.recursion_count,
         });
-        let configured = marked.fold_with(&mut self.strip_unconfigured());
-        self.load_macros(&configured);
+        placeholder(expansion_kind, mark.as_u32())
+    }
 
-        let fully_expanded = if self.single_step {
-            configured
-        } else {
-            configured.fold_with(self)
-        };
+    fn collect_bang(
+        &mut self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind,
+    ) -> Expansion {
+        self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span })
+    }
 
-        self.cx.bt_pop();
-        fully_expanded
+    fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
+                    -> Expansion {
+        self.collect(kind, InvocationKind::Attr { attr: attr, item: item })
+    }
+
+    // If `item` is an attr invocation, remove and return the macro attribute.
+    fn classify_item(&self, mut item: T) -> (T, Option) {
+        let mut attr = None;
+        item = item.map_attrs(|mut attrs| {
+            for i in 0..attrs.len() {
+                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
+                    match *extension {
+                        MultiModifier(..) | MultiDecorator(..) => {
+                            attr = Some(attrs.remove(i));
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            attrs
+        });
+        (item, attr)
+    }
+
+    // does this attribute list contain "macro_use" ?
+    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+        for attr in attrs {
+            let mut is_use = attr.check_name("macro_use");
+            if attr.check_name("macro_escape") {
+                let msg = "macro_escape is a deprecated synonym for macro_use";
+                let mut err = self.cx.struct_span_warn(attr.span, msg);
+                is_use = true;
+                if let ast::AttrStyle::Inner = attr.node.style {
+                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
+                } else {
+                    err.emit();
+                }
+            };
+
+            if is_use {
+                if !attr.is_word() {
+                    self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
+                }
+                return true;
+            }
+        }
+        false
     }
 }
 
-impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
+impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     fn fold_expr(&mut self, expr: P) -> P {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
-            let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-            self.expand_invoc(invoc).make_expr()
+            self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr()
         } else {
             P(noop_fold_expr(expr, self))
         }
@@ -489,9 +544,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_opt_expr(&mut self, expr: P) -> Option> {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
-            let invoc =
-                self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-            self.expand_invoc(invoc).make_opt_expr()
+            self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr)
+                .make_opt_expr()
         } else {
             Some(P(noop_fold_expr(expr, self)))
         }
@@ -504,10 +558,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         }
 
         pat.and_then(|pat| match pat.node {
-            PatKind::Mac(mac) => {
-                let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
-                self.expand_invoc(invoc).make_pat()
-            }
+            PatKind::Mac(mac) =>
+                self.collect_bang(mac, Vec::new(), pat.span, ExpansionKind::Pat).make_pat(),
             _ => unreachable!(),
         })
     }
@@ -518,35 +570,34 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
             _ => return noop_fold_stmt(stmt, self),
         };
 
-        let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-        let mut fully_expanded = self.expand_invoc(invoc).make_stmts();
+        let mut placeholder =
+            self.collect_bang(mac, attrs.into(), stmt.span, ExpansionKind::Stmts).make_stmts();
 
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
         if style == MacStmtStyle::Semicolon {
-            if let Some(stmt) = fully_expanded.pop() {
-                fully_expanded.push(stmt.add_trailing_semicolon());
+            if let Some(stmt) = placeholder.pop() {
+                placeholder.push(stmt.add_trailing_semicolon());
             }
         }
 
-        fully_expanded
+        placeholder
     }
 
     fn fold_block(&mut self, block: P) -> P {
         let paths = self.cx.syntax_env.paths();
         let module = self.cx.syntax_env.add_module(false, true, paths);
-        let orig_module = self.cx.syntax_env.set_current_module(module);
-
+        let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module);
         let result = noop_fold_block(block, self);
-        self.cx.syntax_env.set_current_module(orig_module);
+        self.cx.syntax_env.current_module = orig_module;
         result
     }
 
     fn fold_item(&mut self, item: P) -> SmallVector> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
-            let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
-            return self.expand_invoc(invoc).make_items();
+            let item = Annotatable::Item(item);
+            return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
         }
 
         match item.node {
@@ -560,13 +611,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
                 item.and_then(|item| match item.node {
                     ItemKind::Mac(mac) => {
-                        let invoc = self.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                        self.collect(ExpansionKind::Items, InvocationKind::Bang {
                             mac: mac,
                             attrs: item.attrs,
                             ident: Some(item.ident),
                             span: item.span,
-                        });
-                        self.expand_invoc(invoc).make_items()
+                        }).make_items()
                     }
                     _ => unreachable!(),
                 })
@@ -590,9 +640,9 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                 let macro_use = self.contains_macro_use(&item.attrs);
                 let in_block = self.cx.syntax_env.in_block();
                 let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
-                let module = self.cx.syntax_env.set_current_module(module);
+                let module = mem::replace(&mut self.cx.syntax_env.current_module, module);
                 let result = noop_fold_item(item, self);
-                self.cx.syntax_env.set_current_module(module);
+                self.cx.syntax_env.current_module = module;
                 result
             },
             _ => noop_fold_item(item, self),
@@ -603,15 +653,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let item = Annotatable::TraitItem(P(item));
-            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
-            return self.expand_invoc(invoc).make_trait_items();
+            return self.collect_attr(attr, item, ExpansionKind::TraitItems).make_trait_items()
         }
 
         match item.node {
             ast::TraitItemKind::Macro(mac) => {
                 let ast::TraitItem { attrs, span, .. } = item;
-                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
-                self.expand_invoc(invoc).make_trait_items()
+                self.collect_bang(mac, attrs, span, ExpansionKind::TraitItems).make_trait_items()
             }
             _ => fold::noop_fold_trait_item(item, self),
         }
@@ -621,15 +669,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let item = Annotatable::ImplItem(P(item));
-            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
-            return self.expand_invoc(invoc).make_impl_items();
+            return self.collect_attr(attr, item, ExpansionKind::ImplItems).make_impl_items();
         }
 
         match item.node {
             ast::ImplItemKind::Macro(mac) => {
                 let ast::ImplItem { attrs, span, .. } = item;
-                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
-                self.expand_invoc(invoc).make_impl_items()
+                self.collect_bang(mac, attrs, span, ExpansionKind::ImplItems).make_impl_items()
             }
             _ => fold::noop_fold_impl_item(item, self),
         }
@@ -642,10 +688,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         };
 
         match ty.node {
-            ast::TyKind::Mac(mac) => {
-                let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
-                self.expand_invoc(invoc).make_ty()
-            }
+            ast::TyKind::Mac(mac) =>
+                self.collect_bang(mac, Vec::new(), ty.span, ExpansionKind::Ty).make_ty(),
             _ => unreachable!(),
         }
     }
@@ -699,30 +743,17 @@ impl<'feat> ExpansionConfig<'feat> {
 pub fn expand_crate(cx: &mut ExtCtxt,
                     user_exts: Vec,
                     c: Crate) -> Crate {
-    let mut expander = MacroExpander::new(cx, false, false);
-    expand_crate_with_expander(&mut expander, user_exts, c)
+    cx.initialize(user_exts, &c);
+    cx.expander().expand_crate(c)
 }
 
 // Expands crate using supplied MacroExpander - allows for
 // non-standard expansion behaviour (e.g. step-wise).
 pub fn expand_crate_with_expander(expander: &mut MacroExpander,
                                   user_exts: Vec,
-                                  mut c: Crate) -> Crate {
+                                  c: Crate) -> Crate {
     expander.cx.initialize(user_exts, &c);
-
-    let items = Expansion::Items(SmallVector::many(c.module.items));
-    let configured = items.fold_with(&mut expander.strip_unconfigured());
-    expander.load_macros(&configured);
-    c.module.items = configured.make_items().into();
-
-    let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
-    let mut ret = expander.fold_crate(c);
-    if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
-        expander.cx.parse_sess.span_diagnostic.abort_if_errors();
-    }
-
-    ret.exported_macros = expander.cx.exported_macros.clone();
-    ret
+    expander.expand_crate(c)
 }
 
 // A Marker adds the given mark to the syntax context and
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
index ade165e0ef9c8..27e8eab62e114 100644
--- a/src/libsyntax/ext/hygiene.rs
+++ b/src/libsyntax/ext/hygiene.rs
@@ -40,6 +40,10 @@ impl Mark {
             ::std::mem::replace(&mut data.next_mark, next_mark)
         })
     }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
 }
 
 struct HygieneData {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 6155ad729a289..3108296e778a2 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -300,14 +300,11 @@ fn generate_test_harness(sess: &ParseSess,
         }
     });
 
-    let mut fold = TestHarnessGenerator {
+    TestHarnessGenerator {
         cx: cx,
         tests: Vec::new(),
         tested_submods: Vec::new(),
-    };
-    let res = fold.fold_crate(krate);
-    fold.cx.ext_cx.bt_pop();
-    return res;
+    }.fold_crate(krate)
 }
 
 /// Craft a span that will be ignored by the stability lint's

From 2c88b4b7908b8451e9c3a3c8d9c8ea43fa78c52a Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 2 Sep 2016 02:20:03 +0000
Subject: [PATCH 568/768] Load macros from `extern crate`s in the
 `InvocationCollector` fold.

---
 src/libsyntax/ext/expand.rs | 84 ++++++++++---------------------------
 1 file changed, 22 insertions(+), 62 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5624c2634661a..0986d32ff56ac 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -25,8 +25,6 @@ use parse::token::{intern, keywords};
 use ptr::P;
 use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
-use visit;
-use visit::Visitor;
 
 use std::collections::HashMap;
 use std::mem;
@@ -35,8 +33,7 @@ use std::rc::Rc;
 
 macro_rules! expansions {
     ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
-            $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
-            $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
+            $(.$fold:ident)*  $(lift .$fold_elt:ident)*;)*) => {
         #[derive(Copy, Clone)]
         pub enum ExpansionKind { OptExpr, $( $kind, )*  }
         pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
@@ -81,17 +78,6 @@ macro_rules! expansions {
                     }, )*)*
                 }
             }
-
-            fn visit_with(&self, visitor: &mut V) {
-                match *self {
-                    Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
-                    $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
-                    $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
-                        visitor.$visit_elt(ast);
-                    }, )*)*
-                    _ => {}
-                }
-            }
         }
 
         impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -109,17 +95,17 @@ macro_rules! expansions {
 }
 
 expansions! {
-    Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr;
-    Pat: P   [], "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    Ty: P     [], "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Expr: P [], "expression", .make_expr, .fold_expr;
+    Pat: P   [], "pattern",    .make_pat,  .fold_pat;
+    Ty: P     [], "type",       .make_ty,   .fold_ty;
     Stmts: SmallVector [SmallVector, ast::Stmt],
-        "statement",  .make_stmts,       lift .fold_stmt,       lift .visit_stmt;
+        "statement",  .make_stmts,       lift .fold_stmt;
     Items: SmallVector> [SmallVector, P],
-        "item",       .make_items,       lift .fold_item,       lift .visit_item;
+        "item",       .make_items,       lift .fold_item;
     TraitItems: SmallVector [SmallVector, ast::TraitItem],
-        "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
+        "trait item", .make_trait_items, lift .fold_trait_item;
     ImplItems: SmallVector [SmallVector, ast::ImplItem],
-        "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
+        "impl item",  .make_impl_items,  lift .fold_impl_item;
 }
 
 impl ExpansionKind {
@@ -228,50 +214,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             sess: self.cx.parse_sess,
             features: self.cx.ecfg.features,
         });
-        self.load_macros(&expansion);
         let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() };
         (expansion.fold_with(&mut collector), collector.invocations)
     }
 
-    fn load_macros(&mut self, node: &Expansion) {
-        struct MacroLoadingVisitor<'a, 'b: 'a>{
-            cx: &'a mut ExtCtxt<'b>,
-            at_crate_root: bool,
-        }
-
-        impl<'a, 'b> Visitor for MacroLoadingVisitor<'a, 'b> {
-            fn visit_mac(&mut self, _: &ast::Mac) {}
-            fn visit_item(&mut self, item: &ast::Item) {
-                if let ast::ItemKind::ExternCrate(..) = item.node {
-                    // We need to error on `#[macro_use] extern crate` when it isn't at the
-                    // crate root, because `$crate` won't work properly.
-                    for def in self.cx.loader.load_crate(item, self.at_crate_root) {
-                        match def {
-                            LoadedMacro::Def(def) => self.cx.insert_macro(def),
-                            LoadedMacro::CustomDerive(name, ext) => {
-                                self.cx.insert_custom_derive(&name, ext, item.span);
-                            }
-                        }
-                    }
-                } else {
-                    let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
-                    visit::walk_item(self, item);
-                    self.at_crate_root = at_crate_root;
-                }
-            }
-            fn visit_block(&mut self, block: &ast::Block) {
-                let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
-                visit::walk_block(self, block);
-                self.at_crate_root = at_crate_root;
-            }
-        }
-
-        node.visit_with(&mut MacroLoadingVisitor {
-            at_crate_root: self.cx.syntax_env.is_crate_root(),
-            cx: self.cx,
-        });
-    }
-
     fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
         match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
@@ -645,6 +591,20 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 self.cx.syntax_env.current_module = module;
                 result
             },
+            ast::ItemKind::ExternCrate(..) => {
+                // We need to error on `#[macro_use] extern crate` when it isn't at the
+                // crate root, because `$crate` won't work properly.
+                let is_crate_root = self.cx.syntax_env.is_crate_root();
+                for def in self.cx.loader.load_crate(&*item, is_crate_root) {
+                    match def {
+                        LoadedMacro::Def(def) => self.cx.insert_macro(def),
+                        LoadedMacro::CustomDerive(name, ext) => {
+                            self.cx.insert_custom_derive(&name, ext, item.span);
+                        }
+                    }
+                }
+                SmallVector::one(item)
+            },
             _ => noop_fold_item(item, self),
         }
     }

From 09e6a983805c5f4f7cbb7e244f1fa48c2f91ec95 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" 
Date: Mon, 5 Sep 2016 12:56:29 +0200
Subject: [PATCH 569/768] Fix issue #36036.

We were treating an associated type as unsized even when the concrete
instantiation was actually sized. Fix is to normalize before checking
if it is sized.
---
 src/librustc/ty/layout.rs                     |  2 +-
 .../issue-36036-associated-type-layout.rs     | 36 +++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)
 create mode 100644 src/test/run-pass/issue-36036-associated-type-layout.rs

diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 9270057b54415..276fc708eed1b 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -856,10 +856,10 @@ impl<'a, 'gcx, 'tcx> Layout {
             ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
             ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
                 let non_zero = !ty.is_unsafe_ptr();
+                let pointee = normalize_associated_type(infcx, pointee);
                 if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
                     Scalar { value: Pointer, non_zero: non_zero }
                 } else {
-                    let pointee = normalize_associated_type(infcx, pointee);
                     let unsized_part = tcx.struct_tail(pointee);
                     let meta = match unsized_part.sty {
                         ty::TySlice(_) | ty::TyStr => {
diff --git a/src/test/run-pass/issue-36036-associated-type-layout.rs b/src/test/run-pass/issue-36036-associated-type-layout.rs
new file mode 100644
index 0000000000000..4ee3be0eb7b81
--- /dev/null
+++ b/src/test/run-pass/issue-36036-associated-type-layout.rs
@@ -0,0 +1,36 @@
+// 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.
+
+// Issue 36036: computing the layout of a type composed from another
+// trait's associated type caused compiler to ICE when the associated
+// type was allowed to be unsized, even though the known instantiated
+// type is itself sized.
+
+#![allow(dead_code)]
+
+trait Context {
+    type Container: ?Sized;
+}
+
+impl Context for u16 {
+    type Container = u8;
+}
+
+struct Wrapper {
+    container: &'static C::Container
+}
+
+fn foobar(_: Wrapper) {}
+
+static VALUE: u8 = 0;
+
+fn main() {
+    foobar(Wrapper { container: &VALUE });
+}

From d53ea97bfc149da4cdd0fb1fd1beab08295ae45d Mon Sep 17 00:00:00 2001
From: Gavin Baker 
Date: Tue, 30 Aug 2016 11:04:55 +1000
Subject: [PATCH 570/768] E0516 Update error format #36108 - fixes #36108 -
 part of #35233

---
 src/librustc/hir/check_attr.rs | 18 ++++++++++++------
 src/librustc_typeck/astconv.rs |  7 +++++--
 src/test/compile-fail/E0516.rs |  1 +
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index a2d4239388ace..6997b5d770226 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -56,18 +56,21 @@ impl<'a> CheckAttrVisitor<'a> {
 
         let mut conflicting_reprs = 0;
         for word in words {
+
             let name = match word.name() {
                 Some(word) => word,
                 None => continue,
             };
 
-            let message = match &*name {
+            let word: &str = &word.name();
+            let (message, label) = match word {
                 "C" => {
                     conflicting_reprs += 1;
                     if target != Target::Struct &&
                             target != Target::Union &&
                             target != Target::Enum {
-                        "attribute should be applied to struct, enum or union"
+                                ("attribute should be applied to struct, enum or union",
+                                 "a struct, enum or union")
                     } else {
                         continue
                     }
@@ -85,7 +88,8 @@ impl<'a> CheckAttrVisitor<'a> {
                 "simd" => {
                     conflicting_reprs += 1;
                     if target != Target::Struct {
-                        "attribute should be applied to struct"
+                        ("attribute should be applied to struct",
+                         "a struct")
                     } else {
                         continue
                     }
@@ -95,15 +99,17 @@ impl<'a> CheckAttrVisitor<'a> {
                 "isize" | "usize" => {
                     conflicting_reprs += 1;
                     if target != Target::Enum {
-                        "attribute should be applied to enum"
+                        ("attribute should be applied to enum",
+                         "an enum")
                     } else {
                         continue
                     }
                 }
                 _ => continue,
             };
-
-            span_err!(self.sess, attr.span, E0517, "{}", message);
+            struct_span_err!(self.sess, attr.span, E0517, "{}", message)
+                .span_label(attr.span, &format!("requires {}", label))
+                .emit();
         }
         if conflicting_reprs > 1 {
             span_warn!(self.sess, attr.span, E0566,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5925d222b4466..334b7a5063a3a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1769,8 +1769,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 }
             }
             hir::TyTypeof(ref _e) => {
-                span_err!(tcx.sess, ast_ty.span, E0516,
-                      "`typeof` is a reserved keyword but unimplemented");
+                struct_span_err!(tcx.sess, ast_ty.span, E0516,
+                                 "`typeof` is a reserved keyword but unimplemented")
+                    .span_label(ast_ty.span, &format!("reserved keyword"))
+                    .emit();
+
                 tcx.types.err
             }
             hir::TyInfer => {
diff --git a/src/test/compile-fail/E0516.rs b/src/test/compile-fail/E0516.rs
index a5f609de8497e..be2b89c5f396e 100644
--- a/src/test/compile-fail/E0516.rs
+++ b/src/test/compile-fail/E0516.rs
@@ -10,4 +10,5 @@
 
 fn main() {
     let x: typeof(92) = 92; //~ ERROR E0516
+                            //~| reserved keyword
 }

From 8bcd6a33bebb8177781ae07ea1fc0d4a9a679627 Mon Sep 17 00:00:00 2001
From: Gavin Baker 
Date: Tue, 30 Aug 2016 11:30:46 +1000
Subject: [PATCH 571/768] E0517 Update error format #36109

- Fixes #36109
- Part of #35233
---
 src/librustc/hir/check_attr.rs | 6 +++---
 src/test/compile-fail/E0517.rs | 4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 6997b5d770226..a3ab5f949e7d3 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -62,8 +62,7 @@ impl<'a> CheckAttrVisitor<'a> {
                 None => continue,
             };
 
-            let word: &str = &word.name();
-            let (message, label) = match word {
+            let (message, label) = match &*name {
                 "C" => {
                     conflicting_reprs += 1;
                     if target != Target::Struct &&
@@ -80,7 +79,8 @@ impl<'a> CheckAttrVisitor<'a> {
                     // can be used to modify another repr hint
                     if target != Target::Struct &&
                             target != Target::Union {
-                        "attribute should be applied to struct or union"
+                                ("attribute should be applied to struct or union",
+                                 "a struct or union")
                     } else {
                         continue
                     }
diff --git a/src/test/compile-fail/E0517.rs b/src/test/compile-fail/E0517.rs
index be06e809915b5..b79cb2c44af39 100644
--- a/src/test/compile-fail/E0517.rs
+++ b/src/test/compile-fail/E0517.rs
@@ -9,15 +9,19 @@
 // except according to those terms.
 
 #[repr(C)] //~ ERROR E0517
+           //~| requires a struct, enum or union
 type Foo = u8;
 
 #[repr(packed)] //~ ERROR E0517
+                //~| requires a struct
 enum Foo2 {Bar, Baz}
 
 #[repr(u8)] //~ ERROR E0517
+            //~| requires an enum
 struct Foo3 {bar: bool, baz: bool}
 
 #[repr(C)] //~ ERROR E0517
+           //~| requires a struct, enum or union
 impl Foo3 {
 }
 

From cd56d47da3a2c2ed2eb2a1e4e54ca471c2c9172a Mon Sep 17 00:00:00 2001
From: Gavin Baker 
Date: Tue, 30 Aug 2016 11:44:25 +1000
Subject: [PATCH 572/768] E0518 Update error format #36111

- Fixes #36111
- Part of #35233
---
 src/librustc/hir/check_attr.rs | 4 +++-
 src/test/compile-fail/E0518.rs | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index a3ab5f949e7d3..8ba52cdb64f5f 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -42,7 +42,9 @@ struct CheckAttrVisitor<'a> {
 impl<'a> CheckAttrVisitor<'a> {
     fn check_inline(&self, attr: &ast::Attribute, target: Target) {
         if target != Target::Fn {
-            span_err!(self.sess, attr.span, E0518, "attribute should be applied to function");
+            struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
+                .span_label(attr.span, &format!("requires a function"))
+                .emit();
         }
     }
 
diff --git a/src/test/compile-fail/E0518.rs b/src/test/compile-fail/E0518.rs
index 8518bb4a6be3f..f9494e0bcb531 100644
--- a/src/test/compile-fail/E0518.rs
+++ b/src/test/compile-fail/E0518.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 
 #[inline(always)] //~ ERROR E0518
+                  //~| requires a function
 struct Foo;
 
 #[inline(never)] //~ ERROR E0518
+                 //~| requires a function
 impl Foo {
 }
 

From 046c7f23680f9a8f24209be4097656f91ade0bbb Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Mon, 5 Sep 2016 10:19:00 -0700
Subject: [PATCH 573/768] Add test for unused field in union

---
 .../union/union-lint-dead-code.rs             | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 src/test/compile-fail/union/union-lint-dead-code.rs

diff --git a/src/test/compile-fail/union/union-lint-dead-code.rs b/src/test/compile-fail/union/union-lint-dead-code.rs
new file mode 100644
index 0000000000000..7a552c8f8b76a
--- /dev/null
+++ b/src/test/compile-fail/union/union-lint-dead-code.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(untagged_unions)]
+#![deny(dead_code)]
+
+union Foo {
+    x: usize,
+    b: bool, //~ ERROR: field is never used
+    _unused: u16,
+}
+
+fn field_read(f: Foo) -> usize {
+    unsafe { f.x }
+}
+
+fn main() {
+    let _ = field_read(Foo { x: 2 });
+}

From e8c5dc48063f5290af195f66ae718f78cd6cee9e Mon Sep 17 00:00:00 2001
From: Cobrand 
Date: Tue, 30 Aug 2016 00:33:29 +0200
Subject: [PATCH 574/768] Updated E0527 to new error format

* Closes #36113
---
 src/librustc_typeck/check/_match.rs | 9 ++++++---
 src/test/compile-fail/E0527.rs      | 4 +++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index c67b98761aa6e..17fb683391982 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -233,9 +233,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let min_len = before.len() + after.len();
                         if slice.is_none() {
                             if min_len != size {
-                                span_err!(tcx.sess, pat.span, E0527,
-                                          "pattern requires {} elements but array has {}",
-                                          min_len, size);
+                                struct_span_err!(
+                                    tcx.sess, pat.span, E0527,
+                                    "pattern requires {} elements but array has {}",
+                                    min_len, size)
+                                    .span_label(pat.span, &format!("expected {} elements",size))
+                                    .emit();
                             }
                             (inner_ty, tcx.types.err)
                         } else if let Some(rest) = size.checked_sub(min_len) {
diff --git a/src/test/compile-fail/E0527.rs b/src/test/compile-fail/E0527.rs
index f03f35a57104f..0b664094a40d7 100644
--- a/src/test/compile-fail/E0527.rs
+++ b/src/test/compile-fail/E0527.rs
@@ -13,7 +13,9 @@
 fn main() {
     let r = &[1, 2, 3, 4];
     match r {
-        &[a, b] => { //~ ERROR E0527
+        &[a, b] => {
+            //~^ ERROR E0527
+            //~| NOTE expected 4 elements
             println!("a={}, b={}", a, b);
         }
     }

From 915bbdac580b26e2d47baa1ca3fd21349c4f4b0b Mon Sep 17 00:00:00 2001
From: Piotr Jawniak 
Date: Sun, 4 Sep 2016 18:35:35 +0200
Subject: [PATCH 575/768] rustdoc: Filter more incorrect methods inherited
 through Deref

Old code filtered out only static methods. This code also excludes
&mut self methods if there is no DerefMut implementation
---
 src/librustdoc/clean/mod.rs       |  6 +++
 src/librustdoc/core.rs            |  2 +
 src/librustdoc/html/render.rs     | 87 +++++++++++++++++++++----------
 src/librustdoc/test.rs            |  1 +
 src/test/rustdoc/issue-35169-2.rs | 45 ++++++++++++++++
 src/test/rustdoc/issue-35169.rs   | 40 ++++++++++++++
 6 files changed, 154 insertions(+), 27 deletions(-)
 create mode 100644 src/test/rustdoc/issue-35169-2.rs
 create mode 100644 src/test/rustdoc/issue-35169.rs

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f8ec5a55e7d4c..36b03ce8a2da7 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -134,6 +134,8 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> {
         if let Some(t) = cx.tcx_opt() {
             cx.deref_trait_did.set(t.lang_items.deref_trait());
             cx.renderinfo.borrow_mut().deref_trait_did = cx.deref_trait_did.get();
+            cx.deref_mut_trait_did.set(t.lang_items.deref_mut_trait());
+            cx.renderinfo.borrow_mut().deref_mut_trait_did = cx.deref_mut_trait_did.get();
         }
 
         let mut externs = Vec::new();
@@ -1117,6 +1119,10 @@ impl FnDecl {
     pub fn has_self(&self) -> bool {
         return self.inputs.values.len() > 0 && self.inputs.values[0].name == "self";
     }
+
+    pub fn self_type(&self) -> Option {
+        self.inputs.values.get(0).and_then(|v| v.to_self())
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 26f792a1fdf99..8c5bd9fe3e62b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -53,6 +53,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
     pub input: Input,
     pub populated_crate_impls: RefCell>,
     pub deref_trait_did: Cell>,
+    pub deref_mut_trait_did: Cell>,
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
     // the access levels from crateanalysis.
@@ -180,6 +181,7 @@ pub fn run_core(search_paths: SearchPaths,
             input: input,
             populated_crate_impls: RefCell::new(FnvHashSet()),
             deref_trait_did: Cell::new(None),
+            deref_mut_trait_did: Cell::new(None),
             access_levels: RefCell::new(access_levels),
             external_traits: RefCell::new(FnvHashMap()),
             renderinfo: RefCell::new(Default::default()),
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 6f66ce88df7a5..c38f0a9584b14 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -64,7 +64,7 @@ use rustc::hir;
 use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc_data_structures::flock;
 
-use clean::{self, Attributes, GetDefId};
+use clean::{self, Attributes, GetDefId, SelfTy, Mutability};
 use doctree;
 use fold::DocFolder;
 use html::escape::Escape;
@@ -266,6 +266,7 @@ pub struct Cache {
     seen_mod: bool,
     stripped_mod: bool,
     deref_trait_did: Option,
+    deref_mut_trait_did: Option,
 
     // In rare case where a structure is defined in one module but implemented
     // in another, if the implementing module is parsed before defining module,
@@ -283,6 +284,7 @@ pub struct RenderInfo {
     pub external_paths: ::core::ExternalPaths,
     pub external_typarams: FnvHashMap,
     pub deref_trait_did: Option,
+    pub deref_mut_trait_did: Option,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -508,6 +510,7 @@ pub fn run(mut krate: clean::Crate,
         external_paths,
         external_typarams,
         deref_trait_did,
+        deref_mut_trait_did,
     } = renderinfo;
 
     let external_paths = external_paths.into_iter()
@@ -532,6 +535,7 @@ pub fn run(mut krate: clean::Crate,
         orphan_methods: Vec::new(),
         traits: mem::replace(&mut krate.external_traits, FnvHashMap()),
         deref_trait_did: deref_trait_did,
+        deref_mut_trait_did: deref_mut_trait_did,
         typarams: external_typarams,
     };
 
@@ -2604,7 +2608,13 @@ impl<'a> AssocItemLink<'a> {
 
 enum AssocItemRender<'a> {
     All,
-    DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
+    DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+enum RenderMode {
+    Normal,
+    ForDeref { mut_: bool },
 }
 
 fn render_assoc_items(w: &mut fmt::Formatter,
@@ -2621,19 +2631,19 @@ fn render_assoc_items(w: &mut fmt::Formatter,
         i.inner_impl().trait_.is_none()
     });
     if !non_trait.is_empty() {
-        let render_header = match what {
+        let render_mode = match what {
             AssocItemRender::All => {
                 write!(w, "

Methods

")?; - true + RenderMode::Normal } - AssocItemRender::DerefFor { trait_, type_ } => { + AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { write!(w, "

Methods from \ {}<Target={}>

", trait_, type_)?; - false + RenderMode::ForDeref { mut_: deref_mut_ } } }; for i in &non_trait { - render_impl(w, cx, i, AssocItemLink::Anchor(None), render_header, + render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode, containing_item.stable_since())?; } } @@ -2645,21 +2655,25 @@ fn render_assoc_items(w: &mut fmt::Formatter, t.inner_impl().trait_.def_id() == c.deref_trait_did }); if let Some(impl_) = deref_impl { - render_deref_methods(w, cx, impl_, containing_item)?; + let has_deref_mut = traits.iter().find(|t| { + t.inner_impl().trait_.def_id() == c.deref_mut_trait_did + }).is_some(); + render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?; } write!(w, "

Trait \ Implementations

")?; for i in &traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); - render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?; + render_impl(w, cx, i, assoc_link, + RenderMode::Normal, containing_item.stable_since())?; } } Ok(()) } fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, - container_item: &clean::Item) -> fmt::Result { + container_item: &clean::Item, deref_mut: bool) -> fmt::Result { let deref_type = impl_.inner_impl().trait_.as_ref().unwrap(); let target = impl_.inner_impl().items.iter().filter_map(|item| { match item.inner { @@ -2667,7 +2681,8 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, _ => None, } }).next().expect("Expected associated type binding"); - let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target }; + let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target, + deref_mut_: deref_mut }; if let Some(did) = target.def_id() { render_assoc_items(w, cx, container_item, did, what) } else { @@ -2681,12 +2696,9 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, } } -// Render_header is false when we are rendering a `Deref` impl and true -// otherwise. If render_header is false, we will avoid rendering static -// methods, since they are not accessible for the type implementing `Deref` fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink, - render_header: bool, outer_version: Option<&str>) -> fmt::Result { - if render_header { + render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result { + if render_mode == RenderMode::Normal { write!(w, "

{}", i.inner_impl())?; write!(w, "")?; let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); @@ -2707,22 +2719,43 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, - link: AssocItemLink, render_static: bool, + link: AssocItemLink, render_mode: RenderMode, is_default_item: bool, outer_version: Option<&str>, trait_: Option<&clean::Trait>) -> fmt::Result { let item_type = item_type(item); let name = item.name.as_ref().unwrap(); - let is_static = match item.inner { - clean::MethodItem(ref method) => !method.decl.has_self(), - clean::TyMethodItem(ref method) => !method.decl.has_self(), - _ => false + let render_method_item: bool = match render_mode { + RenderMode::Normal => true, + RenderMode::ForDeref { mut_: deref_mut_ } => { + let self_type_opt = match item.inner { + clean::MethodItem(ref method) => method.decl.self_type(), + clean::TyMethodItem(ref method) => method.decl.self_type(), + _ => None + }; + + if let Some(self_ty) = self_type_opt { + let by_mut_ref = match self_ty { + SelfTy::SelfBorrowed(_lifetime, mutability) => { + mutability == Mutability::Mutable + }, + SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { + mutability == Mutability::Mutable + }, + _ => false, + }; + + deref_mut_ || !by_mut_ref + } else { + false + } + }, }; match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { // Only render when the method is not static or we allow static methods - if !is_static || render_static { + if render_method_item { let id = derive_id(format!("{}.{}", item_type, name)); let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; @@ -2770,7 +2803,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi _ => panic!("can't make docs for trait item with name {:?}", item.name) } - if !is_static || render_static { + if render_method_item || render_mode == RenderMode::Normal { if !is_default_item { if let Some(t) = trait_ { // The trait item may have been stripped so we might not @@ -2803,7 +2836,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "
")?; for trait_item in &i.inner_impl().items { - doc_impl_item(w, cx, trait_item, link, render_header, + doc_impl_item(w, cx, trait_item, link, render_mode, false, outer_version, trait_)?; } @@ -2811,7 +2844,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi cx: &Context, t: &clean::Trait, i: &clean::Impl, - render_static: bool, + render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result { for trait_item in &t.items { let n = trait_item.name.clone(); @@ -2821,7 +2854,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi let did = i.trait_.as_ref().unwrap().def_id().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods); - doc_impl_item(w, cx, trait_item, assoc_link, render_static, true, + doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true, outer_version, None)?; } Ok(()) @@ -2830,7 +2863,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi // If we've implemented a trait, then also emit documentation for all // default items which weren't overridden in the implementation block. if let Some(t) = trait_ { - render_default_items(w, cx, t, &i.inner_impl(), render_header, outer_version)?; + render_default_items(w, cx, t, &i.inner_impl(), render_mode, outer_version)?; } write!(w, "
")?; Ok(()) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index beed1dc9f9e71..73278ad9fac4e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -110,6 +110,7 @@ pub fn run(input: &str, external_traits: RefCell::new(FnvHashMap()), populated_crate_impls: RefCell::new(FnvHashSet()), deref_trait_did: Cell::new(None), + deref_mut_trait_did: Cell::new(None), access_levels: Default::default(), renderinfo: Default::default(), }; diff --git a/src/test/rustdoc/issue-35169-2.rs b/src/test/rustdoc/issue-35169-2.rs new file mode 100644 index 0000000000000..d738fb2925964 --- /dev/null +++ b/src/test/rustdoc/issue-35169-2.rs @@ -0,0 +1,45 @@ +// 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. + +use std::ops::Deref; +use std::ops::DerefMut; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn by_ref(&self) {} + pub fn by_explicit_ref(self: &Foo) {} + pub fn by_mut_ref(&mut self) {} + pub fn by_explicit_mut_ref(self: &mut Foo) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +impl DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Foo { loop {} } +} + +// @has issue_35169_2/Bar.t.html +// @has issue_35169_2/struct.Bar.html +// @has - '//*[@id="by_ref.v"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)' +// @has - '//*[@id="by_explicit_ref.v"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="by_mut_ref.v"]' 'fn by_mut_ref(&mut self)' +// @has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)' +// @has - '//*[@id="by_explicit_mut_ref.v"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' diff --git a/src/test/rustdoc/issue-35169.rs b/src/test/rustdoc/issue-35169.rs new file mode 100644 index 0000000000000..8764e4a390f76 --- /dev/null +++ b/src/test/rustdoc/issue-35169.rs @@ -0,0 +1,40 @@ +// 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. + +use std::ops::Deref; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn by_ref(&self) {} + pub fn by_explicit_ref(self: &Foo) {} + pub fn by_mut_ref(&mut self) {} + pub fn by_explicit_mut_ref(self: &mut Foo) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +// @has issue_35169/Bar.t.html +// @has issue_35169/struct.Bar.html +// @has - '//*[@id="by_ref.v"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)' +// @has - '//*[@id="by_explicit_ref.v"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)' +// @!has - '//*[@id="by_mut_ref.v"]' 'fn by_mut_ref(&mut self)' +// @!has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)' +// @!has - '//*[@id="by_explicit_mut_ref.v"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' From 92a1848d7725495676d8db1cadca50836787eccd Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 6 Sep 2016 12:44:26 +1200 Subject: [PATCH 576/768] save-analysis: some refinement to the value string for variables --- src/librustc_save_analysis/dump_visitor.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a695a07066205..df657cadcbe1b 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -982,15 +982,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_pat(&p); for &(id, ref p, immut, _) in &collector.collected_paths { - let mut value = if immut == ast::Mutability::Immutable { - value.to_string() - } else { - "".to_string() + let mut value = match immut { + ast::Mutability::Immutable => value.to_string(), + _ => String::new(), }; let types = self.tcx.node_types(); - let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new()); - value.push_str(": "); - value.push_str(&typ); + let typ = match types.get(&id) { + Some(typ) => { + let typ = typ.to_string(); + if !value.is_empty() { + value.push_str(": "); + } + value.push_str(&typ); + typ + } + None => String::new(), + }; + // Get the span only for the name of the variable (I hope the path // is only ever a variable name, but who knows?). let sub_span = self.span.span_for_last_ident(p.span); From 41ee2e9124245071dbc890b8617fd6c75391477f Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 5 Sep 2016 21:48:02 -0400 Subject: [PATCH 577/768] resolve: Suggest `use self` when import resolves Improves errors messages by replacing "Maybe a missing `extern crate`" messages with "Did you mean `self::...`" when the `self` import would succeed. --- src/librustc_resolve/resolve_imports.rs | 16 +++++++++++++++- src/test/compile-fail/unresolved-import.rs | 9 +++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 875d6745f6b2e..622d705485efd 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -587,7 +587,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let module = match module_result { Success(module) => module, Indeterminate => return Indeterminate, - Failed(err) => return Failed(err), + Failed(err) => { + let self_module = self.current_module.clone(); + + let resolve_from_self_result = self.resolve_module_path_from_root( + &self_module, &module_path, 0, Some(span)); + + return match resolve_from_self_result { + Success(_) => { + let msg = format!("Did you mean `self::{}`?", + &names_to_string(module_path)); + Failed(Some((span, msg))) + }, + _ => Failed(err), + }; + }, }; let (name, value_result, type_result) = match directive.subclass { diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index d1254f3f5241b..6421599cacb24 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -35,3 +35,12 @@ mod food { } } } + +mod m { + enum MyEnum { + MyVariant + } + + use MyEnum::*; //~ ERROR unresolved import `MyEnum::*` [E0432] + //~^ Did you mean `self::MyEnum`? +} From 288e7caf19b415007787f47424c9e00913cb7803 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 5 Sep 2016 23:08:21 -0400 Subject: [PATCH 578/768] show `self` suggestion when items are in the block --- src/librustc_resolve/resolve_imports.rs | 14 ++++++-------- src/test/compile-fail/unresolved-import.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 622d705485efd..90c17866583a7 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -588,18 +588,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Success(module) => module, Indeterminate => return Indeterminate, Failed(err) => { - let self_module = self.current_module.clone(); + let self_module = self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; let resolve_from_self_result = self.resolve_module_path_from_root( &self_module, &module_path, 0, Some(span)); - return match resolve_from_self_result { - Success(_) => { - let msg = format!("Did you mean `self::{}`?", - &names_to_string(module_path)); - Failed(Some((span, msg))) - }, - _ => Failed(err), + return if let Success(_) = resolve_from_self_result { + let msg = format!("Did you mean `self::{}`?", &names_to_string(module_path)); + Failed(Some((span, msg))) + } else { + Failed(err) }; }, }; diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index 6421599cacb24..0a9a437569730 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -44,3 +44,14 @@ mod m { use MyEnum::*; //~ ERROR unresolved import `MyEnum::*` [E0432] //~^ Did you mean `self::MyEnum`? } + +mod items { + enum Enum { + Variant + } + + use Enum::*; //~ ERROR unresolved import `Enum::*` [E0432] + //~^ Did you mean `self::Enum`? + + fn item() {} +} From 32674b3f1ae0408ca7cb0369eca2efd2f893e908 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 04:55:12 +0000 Subject: [PATCH 579/768] Avoid false positive unused import warnings. --- src/librustc_resolve/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0420fa8026884..cefa37c9fc3b8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1276,16 +1276,17 @@ impl<'a> Resolver<'a> { self.used_crates.insert(krate); } - if let NameBindingKind::Import { directive, .. } = binding.kind { - self.used_imports.insert((directive.id, ns)); - self.add_to_glob_map(directive.id, name); - } - if binding.ambiguity().is_some() { self.ambiguity_errors.push((span, name, binding)); return true; } + if let NameBindingKind::Import { directive, binding } = binding.kind { + self.used_imports.insert((directive.id, ns)); + self.add_to_glob_map(directive.id, name); + self.record_use(name, ns, binding, span); + } + false } From 07f8cb28dc713b8754ed8b51fd9eb07a2f6325ba Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 05:10:50 +0000 Subject: [PATCH 580/768] Add regression test. --- src/test/compile-fail/imports/unused.rs | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/compile-fail/imports/unused.rs diff --git a/src/test/compile-fail/imports/unused.rs b/src/test/compile-fail/imports/unused.rs new file mode 100644 index 0000000000000..4ec9987df4208 --- /dev/null +++ b/src/test/compile-fail/imports/unused.rs @@ -0,0 +1,38 @@ +// 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. + +#![feature(pub_restricted, item_like_imports)] +#![deny(unused)] + +mod foo { + fn f() {} + + mod m1 { + pub(super) use super::f; //~ ERROR unused + } + + mod m2 { + #[allow(unused)] + use super::m1::*; // (despite this glob import) + } + + mod m3 { + pub(super) use super::f; // Check that this is counted as used (c.f. #36249). + } + + pub mod m4 { + use super::m3::*; + pub fn g() { f(); } + } +} + +fn main() { + foo::m4::g(); +} From 888a968139986847623bc40b5a7dc308cf44f988 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 05:27:58 +0000 Subject: [PATCH 581/768] Add field `used: Cell` to variant `NameBindingKind::Import`. --- src/librustc_resolve/lib.rs | 38 +++++++++++-------------- src/librustc_resolve/resolve_imports.rs | 1 + 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index cefa37c9fc3b8..f3044e1847d1b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -871,6 +871,7 @@ enum NameBindingKind<'a> { Import { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, + used: Cell, }, Ambiguity { b1: &'a NameBinding<'a>, @@ -938,14 +939,6 @@ impl<'a> NameBinding<'a> { _ => true, } } - - fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> { - match self.kind { - NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)), - NameBindingKind::Import { binding, .. } => binding.ambiguity(), - _ => None, - } - } } /// Interns the names of the primitive types. @@ -1064,7 +1057,7 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, - ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>)>, + ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>, &'a NameBinding<'a>)>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1276,18 +1269,20 @@ impl<'a> Resolver<'a> { self.used_crates.insert(krate); } - if binding.ambiguity().is_some() { - self.ambiguity_errors.push((span, name, binding)); - return true; - } - - if let NameBindingKind::Import { directive, binding } = binding.kind { - self.used_imports.insert((directive.id, ns)); - self.add_to_glob_map(directive.id, name); - self.record_use(name, ns, binding, span); + match binding.kind { + NameBindingKind::Import { directive, binding, ref used } if !used.get() => { + used.set(true); + self.used_imports.insert((directive.id, ns)); + self.add_to_glob_map(directive.id, name); + self.record_use(name, ns, binding, span) + } + NameBindingKind::Import { .. } => false, + NameBindingKind::Ambiguity { b1, b2 } => { + self.ambiguity_errors.push((span, name, b1, b2)); + true + } + _ => false } - - false } fn add_to_glob_map(&mut self, id: NodeId, name: Name) { @@ -3307,9 +3302,8 @@ impl<'a> Resolver<'a> { fn report_errors(&self) { let mut reported_spans = FnvHashSet(); - for &(span, name, binding) in &self.ambiguity_errors { + for &(span, name, b1, b2) in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } - let (b1, b2) = binding.ambiguity().unwrap(); let msg1 = format!("`{}` could resolve to the name imported here", name); let msg2 = format!("`{}` could also resolve to the name imported here", name); self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 875d6745f6b2e..85c03683c8dc7 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -308,6 +308,7 @@ impl<'a> Resolver<'a> { kind: NameBindingKind::Import { binding: binding, directive: directive, + used: Cell::new(false), }, span: directive.span, vis: vis, From ff3a6449512e9e6fd1ea455c64cd02a7fa4cc7e2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 03:47:11 +0000 Subject: [PATCH 582/768] Add struct `AmbiguityError`. --- src/librustc_resolve/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f3044e1847d1b..c5b505fba38e9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -879,9 +879,15 @@ enum NameBindingKind<'a> { } } -#[derive(Clone, Debug)] struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); +struct AmbiguityError<'a> { + span: Span, + name: Name, + b1: &'a NameBinding<'a>, + b2: &'a NameBinding<'a>, +} + impl<'a> NameBinding<'a> { fn module(&self) -> Result, bool /* true if an error has already been reported */> { match self.kind { @@ -1057,7 +1063,7 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, - ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>, &'a NameBinding<'a>)>, + ambiguity_errors: Vec>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1278,7 +1284,8 @@ impl<'a> Resolver<'a> { } NameBindingKind::Import { .. } => false, NameBindingKind::Ambiguity { b1, b2 } => { - self.ambiguity_errors.push((span, name, b1, b2)); + let ambiguity_error = AmbiguityError { span: span, name: name, b1: b1, b2: b2 }; + self.ambiguity_errors.push(ambiguity_error); true } _ => false @@ -3302,7 +3309,7 @@ impl<'a> Resolver<'a> { fn report_errors(&self) { let mut reported_spans = FnvHashSet(); - for &(span, name, b1, b2) in &self.ambiguity_errors { + for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } let msg1 = format!("`{}` could resolve to the name imported here", name); let msg2 = format!("`{}` could also resolve to the name imported here", name); From 8df4a768a7e98a594bd7a2d70a7bdcec14bc0518 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 6 Sep 2016 01:04:41 -0500 Subject: [PATCH 583/768] rustbuild: per target musl-root config.toml now accepts a target.$TARGET.musl-root key that lets you override the "build" musl-root value, which is set via the --musl-root flag or via the build.musl-root key. With this change, it's now possible to compile std for several musl targets at once. Here's are the sample commands to do such thing: ``` $ configure \ --enable-rustbuild \ --target=x86_64-unknown-linux-musl,arm-unknown-linux-musleabi \ --musl-root=/musl/x86_64-unknown-linux-musl/ $ edit config.toml && tail config.toml [target.arm-unknown-linux-musleabi] musl-root = "/x-tools/arm-unknown-linux-musleabi/arm-unknown-linux-musleabi/sysroot/usr" $ make ``` --- src/bootstrap/compile.rs | 5 +++-- src/bootstrap/config.rs | 2 ++ src/bootstrap/sanity.rs | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 302ac68460c69..e14317b23b4d1 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -59,8 +59,9 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("JEMALLOC_OVERRIDE", jemalloc); } } - if let Some(ref p) = build.config.musl_root { - if target.contains("musl") { + if target.contains("musl") { + if let Some(p) = build.config.target_config[target].musl_root.as_ref() + .or(build.config.musl_root.as_ref()) { cargo.env("MUSL_ROOT", p); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a8..4a158b42187f6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -76,6 +76,7 @@ pub struct Config { // misc pub channel: String, + // Fallback musl-root for all targets pub musl_root: Option, pub prefix: Option, pub codegen_tests: bool, @@ -89,6 +90,7 @@ pub struct Target { pub cc: Option, pub cxx: Option, pub ndk: Option, + pub musl_root: Option, } /// Structure of the `config.toml` file that configuration is read from. diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c0d303c0ea9ae..f1d7f869a9657 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -111,8 +111,9 @@ pub fn check(build: &mut Build) { // Make sure musl-root is valid if specified if target.contains("musl") && !target.contains("mips") { - match build.config.musl_root { - Some(ref root) => { + match build.config.target_config[target].musl_root.as_ref() + .or(build.config.musl_root.as_ref()) { + Some(root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { panic!("couldn't find libc.a in musl dir: {}", root.join("lib").display()); @@ -123,8 +124,9 @@ pub fn check(build: &mut Build) { } } None => { - panic!("when targeting MUSL the build.musl-root option \ - must be specified in config.toml") + panic!("when targeting MUSL either the build.musl-root \ + option or the target.$TARGET.musl-root one must \ + be specified in config.toml") } } } From 0520698be30eeabd72e66d4b8fa540f727820c33 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 8 Aug 2016 01:04:51 +0300 Subject: [PATCH 584/768] Count and report time taken by MIR passes --- src/librustc/mir/transform.rs | 17 +++++++++-------- src/librustc_mir/transform/dump_mir.rs | 4 ++-- src/librustc_mir/transform/simplify_branches.rs | 2 +- src/librustc_mir/transform/simplify_cfg.rs | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 57601e6750432..8cd5f5844d21c 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -15,7 +15,9 @@ use mir::mir_map::MirMap; use mir::repr::{Mir, Promoted}; use ty::TyCtxt; use syntax::ast::NodeId; +use util::common::time; +use std::borrow::Cow; use std::fmt; /// Where a specific Mir comes from. @@ -72,12 +74,12 @@ impl<'a, 'tcx> MirSource { /// Various information about pass. pub trait Pass { // fn should_run(Session) to check if pass should run? - fn name(&self) -> &str { + fn name<'a>(&self) -> Cow<'static, str> { let name = unsafe { ::std::intrinsics::type_name::() }; if let Some(tail) = name.rfind(":") { - &name[tail+1..] + Cow::from(&name[tail+1..]) } else { - name + Cow::from(name) } } fn disambiguator<'a>(&'a self) -> Option> { None } @@ -162,11 +164,10 @@ impl<'a, 'tcx> Passes { } pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { - for pass in &mut self.plugin_passes { - pass.run_pass(tcx, map, &mut self.pass_hooks); - } - for pass in &mut self.passes { - pass.run_pass(tcx, map, &mut self.pass_hooks); + let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self; + for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) { + time(tcx.sess.time_passes(), &*pass.name(), + || pass.run_pass(tcx, map, pass_hooks)); } } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 642adeee5cd63..694b017bbd706 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -26,7 +26,7 @@ impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> { } impl<'b> Pass for Marker<'b> { - fn name(&self) -> &str { self.0 } + fn name(&self) -> ::std::borrow::Cow<'static, str> { String::from(self.0).into() } } pub struct Disambiguator<'a> { @@ -58,7 +58,7 @@ impl<'tcx> MirPassHook<'tcx> for DumpMir { { pretty::dump_mir( tcx, - pass.name(), + &*pass.name(), &Disambiguator { pass: pass, is_after: is_after diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index b4960c677a16e..407e21616102c 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -62,5 +62,5 @@ impl<'l> Pass for SimplifyBranches<'l> { } // avoid calling `type_name` - it contains `<'static>` - fn name(&self) -> &str { "SimplifyBranches" } + fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyBranches".into() } } diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index c0e7e54050adf..8e1b7b44976f3 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -64,7 +64,7 @@ impl<'l> Pass for SimplifyCfg<'l> { } // avoid calling `type_name` - it contains `<'static>` - fn name(&self) -> &str { "SimplifyCfg" } + fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyCfg".into() } } pub struct CfgSimplifier<'a, 'tcx: 'a> { From dc0e9c0b1222dc9ee0be8040635605e0c21fdbcd Mon Sep 17 00:00:00 2001 From: ggomez Date: Tue, 6 Sep 2016 16:31:18 +0200 Subject: [PATCH 585/768] Add missing urls --- src/libstd/collections/hash/map.rs | 60 +++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 14da36ca4834e..4eb2c8f064414 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -206,7 +206,7 @@ fn test_resize_policy() { /// require this behavior you can create your own hashing function using /// [BuildHasherDefault](../hash/struct.BuildHasherDefault.html). /// -/// It is required that the keys implement the `Eq` and `Hash` traits, although +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. /// If you implement these yourself, it is important that the following /// property holds: @@ -218,9 +218,9 @@ fn test_resize_policy() { /// In other words, if two keys are equal, their hashes must be equal. /// /// It is a logic error for a key to be modified in such a way that the key's -/// hash, as determined by the `Hash` trait, or its equality, as determined by -/// the `Eq` trait, changes while it is in the map. This is normally only -/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// /// Relevant papers/articles: /// @@ -298,8 +298,14 @@ fn test_resize_policy() { /// *stat += random_stat_buff(); /// ``` /// -/// The easiest way to use `HashMap` with a custom type as key is to derive `Eq` and `Hash`. -/// We must also derive `PartialEq`. +/// The easiest way to use `HashMap` with a custom type as key is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`Cell`]: ../../std/cell/struct.Cell.html /// /// ``` /// use std::collections::HashMap; @@ -525,7 +531,7 @@ impl HashMap } impl HashMap { - /// Creates an empty HashMap. + /// Creates an empty `HashMap`. /// /// # Examples /// @@ -539,7 +545,7 @@ impl HashMap { Default::default() } - /// Creates an empty hash map with the given initial capacity. + /// Creates an empty `HashMap` with the given initial capacity. /// /// # Examples /// @@ -557,7 +563,7 @@ impl HashMap { impl HashMap where K: Eq + Hash, S: BuildHasher { - /// Creates an empty hashmap which will use the given hash builder to hash + /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. /// /// The created map has the default initial capacity. @@ -587,7 +593,7 @@ impl HashMap } } - /// Creates an empty HashMap with space for at least `capacity` + /// Creates an empty `HashMap` with space for at least `capacity` /// elements, using `hasher` to hash the keys. /// /// Warning: `hasher` is normally randomly generated, and @@ -677,7 +683,7 @@ impl HashMap /// Resizes the internal vectors to a new capacity. It's your responsibility to: /// 1) Make sure the new capacity is enough for all the elements, accounting /// for the load factor. - /// 2) Ensure new_capacity is a power of two or zero. + /// 2) Ensure `new_capacity` is a power of two or zero. fn resize(&mut self, new_capacity: usize) { assert!(self.table.size() <= new_capacity); assert!(new_capacity.is_power_of_two() || new_capacity == 0); @@ -1040,9 +1046,12 @@ impl HashMap /// Returns a reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1063,9 +1072,12 @@ impl HashMap /// Returns true if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1086,9 +1098,12 @@ impl HashMap /// Returns a mutable reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1143,9 +1158,12 @@ impl HashMap /// was previously in the map. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1904,12 +1922,15 @@ impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap } } -/// `RandomState` is the default state for `HashMap` types. +/// `RandomState` is the default state for [`HashMap`] types. /// /// A particular instance `RandomState` will create the same instances of -/// `Hasher`, but the hashers created by two different `RandomState` +/// [`Hasher`], but the hashers created by two different `RandomState` /// instances are unlikely to produce the same result for the same values. /// +/// [`HashMap`]: struct.HashMap.html +/// [`Hasher`]: ../../hash/trait.Hasher.html +/// /// # Examples /// /// ``` @@ -1980,10 +2001,13 @@ impl BuildHasher for RandomState { } } -/// The default `Hasher` used by `RandomState`. +/// The default [`Hasher`] used by [`RandomState`]. /// /// The internal algorithm is not specified, and so it and its hashes should /// not be relied upon over releases. +/// +/// [`RandomState`]: struct.RandomState.html +/// [`Hasher`]: ../../hash/trait.Hasher.html #[unstable(feature = "hashmap_default_hasher", issue = "0")] pub struct DefaultHasher(SipHasher13); From 79644ac3c4fe1b27dc64e0b172d3fca80a88335c Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Tue, 6 Sep 2016 07:41:20 -0700 Subject: [PATCH 586/768] adding a check to sanity to look for the nodejs command --- src/bootstrap/sanity.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c0d303c0ea9ae..ae7f2e018f9f9 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -75,6 +75,12 @@ pub fn check(build: &mut Build) { need_cmd("python".as_ref()); + // If a manual nodejs was added to the config, + // of if a nodejs install is detected through bootstrap.py, use it. + if build.config.nodejs.is_some() { + need_cmd("nodejs".as_ref()) + } + // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. for target in build.config.target.iter() { From 5415b34ca6077b45a241c51ef2a227993a644d26 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 06:49:44 -0400 Subject: [PATCH 587/768] write to inherent_impls during the visitor The goal here is to avoid writing to the `inherent_impls` map from within the general `Coherence` task, and instead write to it as we visit. Writing to it from the Coherence task is actually an information leak; it happened to be safe because Coherence read from `DepNode::Krate`, but that was very coarse. I removed the `Rc` here because, upon manual inspection, nobody clones the data in this table, and it meant that we can accumulate the data in place. That said, the pattern that is used for the inherent impls map is *generally* an anti-pattern (that is, holding the borrow lock for the duration of using the contents), so it'd probably be better to clone (and I doubt that would be expensive -- how many inherent impls does a typical type have?). --- src/librustc/dep_graph/dep_tracking_map.rs | 11 +++++++ src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 24 ++------------- src/test/incremental/krate-inherent.rs | 34 ++++++++++++++++++++++ 5 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 src/test/incremental/krate-inherent.rs diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 88cd1efd3459a..51f7890c7a2f4 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -80,6 +80,17 @@ impl DepTrackingMap { pub fn keys(&self) -> Vec { self.map.keys().cloned().collect() } + + /// Append `elem` to the vector stored for `k`, creating a new vector if needed. + /// This is considered a write to `k`. + pub fn push(&mut self, k: M::Key, elem: E) + where M: DepTrackingMapConfig> + { + self.write(&k); + self.map.entry(k) + .or_insert(Vec::new()) + .push(elem); + } } impl MemoizationMap for RefCell> { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 0e8bea86178f3..5772d16c6d43d 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -39,7 +39,7 @@ dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } -dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc> } +dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dfe24d5627bf1..78358ce534d99 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2665,7 +2665,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.impl_items.borrow_mut().insert(impl_def_id, impl_items); } - self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); + self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); self.populated_external_types.borrow_mut().insert(type_id); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d2b7f07b9ce6c..57d3c46af9306 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -32,10 +32,7 @@ use rustc::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; use CrateCtxt; use rustc::infer::{self, InferCtxt, TypeOrigin}; -use std::cell::RefCell; -use std::rc::Rc; use syntax_pos::Span; -use util::nodemap::{DefIdMap, FnvHashMap}; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::hir::intravisit; @@ -49,7 +46,6 @@ mod unsafety; struct CoherenceChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { crate_context: &'a CrateCtxt<'a, 'gcx>, inference_context: InferCtxt<'a, 'gcx, 'tcx>, - inherent_impls: RefCell>>>>, } struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { @@ -109,15 +105,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { DepNode::CoherenceCheckImpl, &mut CoherenceCheckVisitor { cc: self }); - // Copy over the inherent impls we gathered up during the walk into - // the tcx. - let mut tcx_inherent_impls = - self.crate_context.tcx.inherent_impls.borrow_mut(); - for (k, v) in self.inherent_impls.borrow().iter() { - tcx_inherent_impls.insert((*k).clone(), - Rc::new((*v.borrow()).clone())); - } - // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since // the coherence tables contain the trait -> type mappings. @@ -175,14 +162,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { - if let Some(implementation_list) = self.inherent_impls.borrow().get(&base_def_id) { - implementation_list.borrow_mut().push(impl_def_id); - return; - } - - self.inherent_impls.borrow_mut().insert( - base_def_id, - Rc::new(RefCell::new(vec!(impl_def_id)))); + let tcx = self.crate_context.tcx; + tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id); } fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) { @@ -556,7 +537,6 @@ pub fn check_coherence(ccx: &CrateCtxt) { CoherenceChecker { crate_context: ccx, inference_context: infcx, - inherent_impls: RefCell::new(FnvHashMap()), }.check(); }); unsafety::check(ccx.tcx); diff --git a/src/test/incremental/krate-inherent.rs b/src/test/incremental/krate-inherent.rs new file mode 100644 index 0000000000000..ac6cc3e9826f1 --- /dev/null +++ b/src/test/incremental/krate-inherent.rs @@ -0,0 +1,34 @@ +// 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. + +// revisions: rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![rustc_partition_reused(module="krate_inherent-x", cfg="rpass2")] + +fn main() { } + +mod x { + struct Foo; + impl Foo { + fn foo(&self) { } + } + + fn method() { + let x: Foo = Foo; + x.foo(); // inherent methods used to add an edge from Krate + } +} + +#[cfg(rpass1)] +fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` + From c6363b801316c1d8279f55a6be44746d71018ceb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 07:35:49 -0400 Subject: [PATCH 588/768] ignore dep-graph when loading inlined HIR We touch the krate to adjust the maps, but we don't expose that data widely. --- src/librustc/hir/map/mod.rs | 2 ++ src/test/incremental/krate-inlined.rs | 29 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/incremental/krate-inlined.rs diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 3ffc95e64f5a7..5c302d927a718 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -927,6 +927,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { + let _ignore = map.forest.dep_graph.in_ignore(); + let mut fld = IdAndSpanUpdater::new(fold_ops); let ii = match ii { II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d), diff --git a/src/test/incremental/krate-inlined.rs b/src/test/incremental/krate-inlined.rs new file mode 100644 index 0000000000000..3680658984792 --- /dev/null +++ b/src/test/incremental/krate-inlined.rs @@ -0,0 +1,29 @@ +// 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. + +// revisions: rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")] + +fn main() { } + +mod x { + fn method() { + // use some methods that require inlining HIR from another crate: + let mut v = vec![]; + v.push(1); + } +} + +#[cfg(rpass1)] +fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` From 753590f0c52c0ca54e7b80c1cc90f72bb8bbc8fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 07:36:54 -0400 Subject: [PATCH 589/768] add a debugging mechanism to forbid edges It is useful to track down an errant edge that is being added. This is not a perfect mechanism, since it doesn't consider (e.g.) if we are in an ignored task, but it's helpful enough for now. --- src/librustc/dep_graph/graph.rs | 18 +++++++++++++++++- src/librustc/dep_graph/raii.rs | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index bb027b11b45af..ca441c4bc3ff2 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -38,6 +38,10 @@ struct DepGraphData { /// Work-products that we generate in this run. work_products: RefCell, WorkProduct>>, + + /// Tracks nodes that are forbidden to read/write; see + /// `DepGraph::forbid`. Used for debugging only. + forbidden: RefCell>>, } impl DepGraph { @@ -46,7 +50,8 @@ impl DepGraph { data: Rc::new(DepGraphData { thread: DepGraphThreadData::new(enabled), previous_work_products: RefCell::new(FnvHashMap()), - work_products: RefCell::new(FnvHashMap()) + work_products: RefCell::new(FnvHashMap()), + forbidden: RefCell::new(Vec::new()), }) } } @@ -70,6 +75,15 @@ impl DepGraph { raii::DepTask::new(&self.data.thread, key) } + /// Debugging aid -- forbid reads/writes to `key` while the return + /// value is in scope. Note that this is only available when debug + /// assertions are enabled -- you should not check in code that + /// invokes this function. + #[cfg(debug_assertions)] + pub fn forbid<'graph>(&'graph self, key: DepNode) -> raii::Forbid<'graph> { + raii::Forbid::new(&self.data.forbidden, key) + } + pub fn with_ignore(&self, op: OP) -> R where OP: FnOnce() -> R { @@ -85,10 +99,12 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { + debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Read(v)); } pub fn write(&self, v: DepNode) { + debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Write(v)); } diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index c43d493d17675..b344eb486240b 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -9,6 +9,7 @@ // except according to those terms. use hir::def_id::DefId; +use std::cell::RefCell; use super::DepNode; use super::thread::{DepGraphThreadData, DepMessage}; @@ -47,3 +48,20 @@ impl<'graph> Drop for IgnoreTask<'graph> { self.data.enqueue(DepMessage::PopIgnore); } } + +pub struct Forbid<'graph> { + forbidden: &'graph RefCell>> +} + +impl<'graph> Forbid<'graph> { + pub fn new(forbidden: &'graph RefCell>>, node: DepNode) -> Self { + forbidden.borrow_mut().push(node); + Forbid { forbidden: forbidden } + } +} + +impl<'graph> Drop for Forbid<'graph> { + fn drop(&mut self) { + self.forbidden.borrow_mut().pop(); + } +} From 2a84449169b3c882e101a68eb156800fe8ff24c3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 11:00:55 -0400 Subject: [PATCH 590/768] allow testing DepNode::Krate edges directly --- src/librustc_incremental/assert_dep_graph.rs | 158 +++++++++---------- src/test/incremental/krate-inlined.rs | 12 +- 2 files changed, 78 insertions(+), 92 deletions(-) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index bd96ae69ffbc8..b28454cddb247 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -26,19 +26,20 @@ //! used to check when paths exist or do not. //! //! The full form of the `rustc_if_this_changed` annotation is -//! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and -//! defaults to `"id"` if omitted. +//! `#[rustc_if_this_changed("foo")]`, which will report a +//! source node of `foo(def_id)`. The `"foo"` is optional and +//! defaults to `"Hir"` if omitted. //! //! Example: //! //! ``` -//! #[rustc_if_this_changed] +//! #[rustc_if_this_changed(Hir)] //! fn foo() { } //! -//! #[rustc_then_this_would_need("trans")] //~ ERROR no path from `foo` +//! #[rustc_then_this_would_need(trans)] //~ ERROR no path from `foo` //! fn bar() { } //! -//! #[rustc_then_this_would_need("trans")] //~ ERROR OK +//! #[rustc_then_this_would_need(trans)] //~ ERROR OK //! fn baz() { foo(); } //! ``` @@ -47,7 +48,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; +use rustc_data_structures::fnv::FnvHashSet; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc::hir; use rustc::hir::intravisit::Visitor; @@ -61,7 +62,6 @@ use syntax_pos::Span; const IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; const THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; -const ID: &'static str = "id"; pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); @@ -80,8 +80,9 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // Find annotations supplied by user (if any). let (if_this_changed, then_this_would_need) = { let mut visitor = IfThisChanged { tcx: tcx, - if_this_changed: FnvHashMap(), - then_this_would_need: FnvHashMap() }; + if_this_changed: vec![], + then_this_would_need: vec![] }; + visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs); tcx.map.krate().visit_all_items(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -97,58 +98,51 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { check_paths(tcx, &if_this_changed, &then_this_would_need); } -type SourceHashMap = - FnvHashMap)>>; -type TargetHashMap = - FnvHashMap)>>; +type Sources = Vec<(Span, DefId, DepNode)>; +type Targets = Vec<(Span, InternedString, ast::NodeId, DepNode)>; struct IfThisChanged<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - if_this_changed: SourceHashMap, - then_this_would_need: TargetHashMap, + if_this_changed: Sources, + then_this_would_need: Targets, } impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { - fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) { - for attr in self.tcx.get_attrs(def_id).iter() { + fn argument(&self, attr: &ast::Attribute) -> Option { + let mut value = None; + for list_item in attr.meta_item_list().unwrap_or_default() { + match list_item.word() { + Some(word) if value.is_none() => + value = Some(word.name().clone()), + _ => + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node), + } + } + value + } + + fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) { + let def_id = self.tcx.map.local_def_id(node_id); + for attr in attrs { if attr.check_name(IF_THIS_CHANGED) { - let mut id = None; - for list_item in attr.meta_item_list().unwrap_or_default() { - match list_item.word() { - Some(word) if id.is_none() => { - id = Some(word.name().clone()) - }, - _ => { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node) + let dep_node_interned = self.argument(attr); + let dep_node = match dep_node_interned { + None => DepNode::Hir(def_id), + Some(ref n) => { + match DepNode::from_label_string(&n[..], def_id) { + Ok(n) => n, + Err(()) => { + self.tcx.sess.span_fatal( + attr.span, + &format!("unrecognized DepNode variant {:?}", n)); + } } } - } - - let id = id.unwrap_or(InternedString::new(ID)); - self.if_this_changed.entry(id) - .or_insert(FnvHashSet()) - .insert((attr.span, def_id, DepNode::Hir(def_id))); + }; + self.if_this_changed.push((attr.span, def_id, dep_node)); } else if attr.check_name(THEN_THIS_WOULD_NEED) { - let mut dep_node_interned = None; - let mut id = None; - for list_item in attr.meta_item_list().unwrap_or_default() { - match list_item.word() { - Some(word) if dep_node_interned.is_none() => { - dep_node_interned = Some(word.name().clone()); - }, - Some(word) if id.is_none() => { - id = Some(word.name().clone()) - }, - _ => { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node) - } - } - } - + let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { Some(ref n) => { match DepNode::from_label_string(&n[..], def_id) { @@ -166,11 +160,10 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { &format!("missing DepNode variant")); } }; - let id = id.unwrap_or(InternedString::new(ID)); - self.then_this_would_need - .entry(id) - .or_insert(FnvHashSet()) - .insert((attr.span, dep_node_interned.clone().unwrap(), node_id, dep_node)); + self.then_this_would_need.push((attr.span, + dep_node_interned.clone().unwrap(), + node_id, + dep_node)); } } } @@ -178,47 +171,38 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - let def_id = self.tcx.map.local_def_id(item.id); - self.process_attrs(item.id, def_id); + self.process_attrs(item.id, &item.attrs); } } fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - if_this_changed: &SourceHashMap, - then_this_would_need: &TargetHashMap) + if_this_changed: &Sources, + then_this_would_need: &Targets) { // Return early here so as not to construct the query, which is not cheap. if if_this_changed.is_empty() { + for &(target_span, _, _, _) in then_this_would_need { + tcx.sess.span_err( + target_span, + &format!("no #[rustc_if_this_changed] annotation detected")); + + } return; } let query = tcx.dep_graph.query(); - for (id, sources) in if_this_changed { - let targets = match then_this_would_need.get(id) { - Some(targets) => targets, - None => { - for &(source_span, ..) in sources.iter().take(1) { - tcx.sess.span_err( - source_span, - &format!("no targets for id `{}`", id)); - } - continue; - } - }; - - for &(_, source_def_id, ref source_dep_node) in sources { - let dependents = query.transitive_successors(source_dep_node); - for &(target_span, ref target_pass, _, ref target_dep_node) in targets { - if !dependents.contains(&target_dep_node) { - tcx.sess.span_err( - target_span, - &format!("no path from `{}` to `{}`", - tcx.item_path_str(source_def_id), - target_pass)); - } else { - tcx.sess.span_err( - target_span, - &format!("OK")); - } + for &(_, source_def_id, ref source_dep_node) in if_this_changed { + let dependents = query.transitive_successors(source_dep_node); + for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { + if !dependents.contains(&target_dep_node) { + tcx.sess.span_err( + target_span, + &format!("no path from `{}` to `{}`", + tcx.item_path_str(source_def_id), + target_pass)); + } else { + tcx.sess.span_err( + target_span, + &format!("OK")); } } } diff --git a/src/test/incremental/krate-inlined.rs b/src/test/incremental/krate-inlined.rs index 3680658984792..ba32b41983fc2 100644 --- a/src/test/incremental/krate-inlined.rs +++ b/src/test/incremental/krate-inlined.rs @@ -8,22 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// revisions: rpass1 rpass2 +// Regr. test that using HIR inlined from another krate does *not* add +// a dependency from the local Krate node. + +// revisions: cfail1 // compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] -#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")] + +#![rustc_if_this_changed(Krate)] fn main() { } mod x { + #[rustc_then_this_would_need(TransCrateItem)] //[cfail1]~ ERROR no path fn method() { // use some methods that require inlining HIR from another crate: let mut v = vec![]; v.push(1); } } - -#[cfg(rpass1)] -fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` From 4c2f3ff44263b813d4211150613edff0c5c92c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 11:01:12 -0400 Subject: [PATCH 591/768] remove the "misc-items" from meta-data It was duplicating information available elsewhere. --- src/librustc_metadata/common.rs | 4 ++-- src/librustc_metadata/decoder.rs | 11 ++-------- src/librustc_metadata/encoder.rs | 35 +++++--------------------------- 3 files changed, 9 insertions(+), 41 deletions(-) diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 1e6c74bef8da5..29b9cc0d1d923 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -149,9 +149,9 @@ pub const tag_items_data_item_visibility: usize = 0x78; pub const tag_items_data_item_inherent_impl: usize = 0x79; // GAP 0x7a pub const tag_mod_child: usize = 0x7b; -pub const tag_misc_info: usize = 0x108; // top-level only -pub const tag_misc_info_crate_items: usize = 0x7c; +// GAP 0x7c +// GAP 0x108 pub const tag_impls: usize = 0x109; // top-level only pub const tag_impls_trait: usize = 0x7d; pub const tag_impls_trait_impl: usize = 0x7e; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6b48b4dfabcfd..d75d5a3b35443 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -23,6 +23,7 @@ use index; use tls_context; use tydecode::TyDecoder; +use rustc::hir::def_id::CRATE_DEF_INDEX; use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; use rustc::hir::map::DefKey; @@ -732,15 +733,7 @@ pub fn each_top_level_item_of_crate(cdata: Cmd, get_crate_data: G, callbac where F: FnMut(DefLike, ast::Name, ty::Visibility), G: FnMut(ast::CrateNum) -> Rc, { - let root_doc = rbml::Doc::new(cdata.data()); - let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); - let crate_items_doc = reader::get_doc(misc_info_doc, - tag_misc_info_crate_items); - - each_child_of_item_or_crate(cdata, - crate_items_doc, - get_crate_data, - callback) + each_child_of_item(cdata, CRATE_DEF_INDEX, get_crate_data, callback) } pub fn get_item_name(cdata: Cmd, id: DefIndex) -> ast::Name { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 23398a0400c51..603b7a483b90c 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1693,30 +1693,6 @@ fn encode_impls<'a>(ecx: &'a EncodeContext, rbml_w.end_tag(); } -fn encode_misc_info(ecx: &EncodeContext, - krate: &hir::Crate, - rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_misc_info); - rbml_w.start_tag(tag_misc_info_crate_items); - for item_id in &krate.module.item_ids { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); - - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); - } - - // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0); - - rbml_w.end_tag(); - rbml_w.end_tag(); -} - // Encodes all reachable symbols in this crate into the metadata. // // This pass is seeded off the reachability list calculated in the @@ -1861,7 +1837,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, codemap_bytes: u64, macro_defs_bytes: u64, impl_bytes: u64, - misc_bytes: u64, + reachable_bytes: u64, item_bytes: u64, index_bytes: u64, xref_bytes: u64, @@ -1877,7 +1853,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, codemap_bytes: 0, macro_defs_bytes: 0, impl_bytes: 0, - misc_bytes: 0, + reachable_bytes: 0, item_bytes: 0, index_bytes: 0, xref_bytes: 0, @@ -1931,11 +1907,10 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_impls(&ecx, krate, rbml_w); stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - // Encode miscellaneous info. + // Encode reachability info. i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_misc_info(&ecx, krate, rbml_w); encode_reachable(&ecx, rbml_w); - stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + stats.reachable_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode and index the items. rbml_w.start_tag(tag_items); @@ -1972,7 +1947,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, println!(" codemap bytes: {}", stats.codemap_bytes); println!(" macro def bytes: {}", stats.macro_defs_bytes); println!(" impl bytes: {}", stats.impl_bytes); - println!(" misc bytes: {}", stats.misc_bytes); + println!(" reachable bytes: {}", stats.reachable_bytes); println!(" item bytes: {}", stats.item_bytes); println!(" index bytes: {}", stats.index_bytes); println!(" xref bytes: {}", stats.xref_bytes); From 2f91ba05fd930e003bb17b763a32382cfe4392a8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 07:50:18 -0400 Subject: [PATCH 592/768] implement a debugging "shadow graph" The shadow graph supercedes the existing code that checked for reads/writes without an active task and now adds the ability to filter for specific edges. --- src/librustc/dep_graph/README.md | 31 ++++++++ src/librustc/dep_graph/debug.rs | 7 ++ src/librustc/dep_graph/mod.rs | 1 + src/librustc/dep_graph/shadow.rs | 123 +++++++++++++++++++++++++++++++ src/librustc/dep_graph/thread.rs | 41 ++++------- src/librustc/lib.rs | 1 + 6 files changed, 176 insertions(+), 28 deletions(-) create mode 100644 src/librustc/dep_graph/shadow.rs diff --git a/src/librustc/dep_graph/README.md b/src/librustc/dep_graph/README.md index f16a9b386bb8a..48f5b7ea2595d 100644 --- a/src/librustc/dep_graph/README.md +++ b/src/librustc/dep_graph/README.md @@ -341,6 +341,8 @@ path is found (as demonstrated above). ### Debugging the dependency graph +#### Dumping the graph + The compiler is also capable of dumping the dependency graph for your debugging pleasure. To do so, pass the `-Z dump-dep-graph` flag. The graph will be dumped to `dep_graph.{txt,dot}` in the current @@ -392,6 +394,35 @@ This will dump out all the nodes that lead from `Hir(foo)` to `TypeckItemBody(bar)`, from which you can (hopefully) see the source of the erroneous edge. +#### Tracking down incorrect edges + +Sometimes, after you dump the dependency graph, you will find some +path that should not exist, but you will not be quite sure how it came +to be. **When the compiler is built with debug assertions,** it can +help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE` +environment variable to a filter. Every edge created in the dep-graph +will be tested against that filter -- if it matches, a `bug!` is +reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`). + +The syntax for these filters is the same as described in the previous +section. However, note that this filter is applied to every **edge** +and doesn't handle longer paths in the graph, unlike the previous +section. + +Example: + +You find that there is a path from the `Hir` of `foo` to the type +check of `bar` and you don't think there should be. You dump the +dep-graph as described in the previous section and open `dep-graph.txt` +to see something like: + + Hir(foo) -> Collect(bar) + Collect(bar) -> TypeckItemBody(bar) + +That first edge looks suspicious to you. So you set +`RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and +then observe the backtrace. Voila, bug fixed! + ### Inlining of HIR nodes For the time being, at least, we still sometimes "inline" HIR nodes diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index 15b0380374c69..5b15c5e67174e 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -66,4 +66,11 @@ impl EdgeFilter { }) } } + + pub fn test(&self, + source: &DepNode, + target: &DepNode) + -> bool { + self.source.test(source) && self.target.test(target) + } } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index a499cb10f2325..9c00e95c17e05 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,6 +15,7 @@ mod edges; mod graph; mod query; mod raii; +mod shadow; mod thread; mod visit; diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs new file mode 100644 index 0000000000000..e038997e0ad42 --- /dev/null +++ b/src/librustc/dep_graph/shadow.rs @@ -0,0 +1,123 @@ +//! The "Shadow Graph" is maintained on the main thread and which +//! tracks each message relating to the dep-graph and applies some +//! sanity checks as they go by. If an error results, it means you get +//! a nice stack-trace telling you precisely what caused the error. +//! +//! NOTE: This is a debugging facility which can potentially have non-trivial +//! runtime impact. Therefore, it is largely compiled out if +//! debug-assertions are not enabled. +//! +//! The basic sanity check, always enabled, is that there is always a +//! task (or ignore) on the stack when you do read/write. +//! +//! Optionally, if you specify RUST_FORBID_DEP_GRAPH_EDGE, you can +//! specify an edge filter to be applied to each edge as it is +//! created. See `./README.md` for details. + +use hir::def_id::DefId; +use std::cell::{BorrowState, RefCell}; +use std::env; + +use super::DepNode; +use super::thread::DepMessage; +use super::debug::EdgeFilter; + +pub struct ShadowGraph { + // if you push None onto the stack, that corresponds to an Ignore + stack: RefCell>>>, + forbidden_edge: Option, +} + +const ENABLED: bool = cfg!(debug_assertions); + +impl ShadowGraph { + pub fn new() -> Self { + let forbidden_edge = if !ENABLED { + None + } else { + match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { + Ok(s) => { + match EdgeFilter::new(&s) { + Ok(f) => Some(f), + Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), + } + } + Err(_) => None, + } + }; + + ShadowGraph { + stack: RefCell::new(vec![]), + forbidden_edge: forbidden_edge, + } + } + + pub fn enqueue(&self, message: &DepMessage) { + if ENABLED { + match self.stack.borrow_state() { + BorrowState::Unused => {} + _ => { + // When we apply edge filters, that invokes the + // Debug trait on DefIds, which in turn reads from + // various bits of state and creates reads! Ignore + // those recursive reads. + return; + } + } + + let mut stack = self.stack.borrow_mut(); + match *message { + DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)), + DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), + DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), + DepMessage::PushIgnore => stack.push(None), + DepMessage::PopTask(_) | + DepMessage::PopIgnore => { + // we could easily check that the stack is + // well-formed here, but since we use closures and + // RAII accessors, this bug basically never + // happens, so it seems not worth the overhead + stack.pop(); + } + DepMessage::Query => (), + } + } + } + + fn check_edge(&self, + source: Option>>, + target: Option>>) { + assert!(ENABLED); + match (source, target) { + // cannot happen, one side is always Some(Some(_)) + (None, None) => unreachable!(), + + // nothing on top of the stack + (None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n), + + // this corresponds to an Ignore being top of the stack + (Some(None), _) | (_, Some(None)) => (), + + // a task is on top of the stack + (Some(Some(source)), Some(Some(target))) => { + if let Some(ref forbidden_edge) = self.forbidden_edge { + if forbidden_edge.test(source, target) { + bug!("forbidden edge {:?} -> {:?} created", source, target) + } + } + } + } + } +} + +// Do a little juggling: we get back a reference to an option at the +// top of the stack, convert it to an optional reference. +fn top<'s>(stack: &'s Vec>>) -> Option>> { + stack.last() + .map(|n: &'s Option>| -> Option<&'s DepNode> { + // (*) + // (*) type annotation just there to clarify what would + // otherwise be some *really* obscure code + n.as_ref() + }) +} diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index 4e16fae187070..90c42d66b7adf 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -20,13 +20,13 @@ use hir::def_id::DefId; use rustc_data_structures::veccell::VecCell; -use std::cell::Cell; use std::sync::mpsc::{self, Sender, Receiver}; use std::thread; use super::DepGraphQuery; use super::DepNode; use super::edges::DepGraphEdges; +use super::shadow::ShadowGraph; #[derive(Debug)] pub enum DepMessage { @@ -42,12 +42,16 @@ pub enum DepMessage { pub struct DepGraphThreadData { enabled: bool, - // Local counter that just tracks how many tasks are pushed onto the - // stack, so that we still get an error in the case where one is - // missing. If dep-graph construction is enabled, we'd get the same - // error when processing tasks later on, but that's annoying because - // it lacks precision about the source of the error. - tasks_pushed: Cell, + // The "shadow graph" is a debugging aid. We give it each message + // in real time as it arrives and it checks for various errors + // (for example, a read/write when there is no current task; it + // can also apply user-defined filters; see `shadow` module for + // details). This only occurs if debug-assertions are enabled. + // + // Note that in some cases the same errors will occur when the + // data is processed off the main thread, but that's annoying + // because it lacks precision about the source of the error. + shadow_graph: ShadowGraph, // current buffer, where we accumulate messages messages: VecCell, @@ -76,7 +80,7 @@ impl DepGraphThreadData { DepGraphThreadData { enabled: enabled, - tasks_pushed: Cell::new(0), + shadow_graph: ShadowGraph::new(), messages: VecCell::with_capacity(INITIAL_CAPACITY), swap_in: rx2, swap_out: tx1, @@ -118,21 +122,7 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { - // Regardless of whether dep graph construction is enabled, we - // still want to check that we always have a valid task on the - // stack when a read/write/etc event occurs. - match message { - DepMessage::Read(_) | DepMessage::Write(_) => - if self.tasks_pushed.get() == 0 { - self.invalid_message("read/write but no current task") - }, - DepMessage::PushTask(_) | DepMessage::PushIgnore => - self.tasks_pushed.set(self.tasks_pushed.get() + 1), - DepMessage::PopTask(_) | DepMessage::PopIgnore => - self.tasks_pushed.set(self.tasks_pushed.get() - 1), - DepMessage::Query => - (), - } + self.shadow_graph.enqueue(&message); if self.enabled { self.enqueue_enabled(message); @@ -147,11 +137,6 @@ impl DepGraphThreadData { self.swap(); } } - - // Outline this too. - fn invalid_message(&self, string: &str) { - bug!("{}; see src/librustc/dep_graph/README.md for more information", string) - } } /// Definition of the depgraph thread. diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index f70349d0ee08b..d2a2f8a972d96 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -24,6 +24,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(associated_consts)] +#![feature(borrow_state)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(collections)] From fe6557eb62c1f8856ed95c6998083d09e6ec470b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 08:26:36 -0400 Subject: [PATCH 593/768] expanding a def-id is not a read Across crates only, converting a def-id into its def-key or def-path was considered a read. This caused spurious reads when computing the symbol name for some item. --- src/librustc_metadata/csearch.rs | 12 ++++++-- .../auxiliary/a.rs | 18 ++++++++++++ .../remove-private-item-cross-crate/main.rs | 28 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs create mode 100644 src/test/incremental/remove-private-item-cross-crate/main.rs diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 0fd7b683067b7..5e5cc7e1e6108 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -425,13 +425,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. fn def_key(&self, def: DefId) -> hir_map::DefKey { - self.dep_graph.read(DepNode::MetaData(def)); + // Note: loading the def-key (or def-path) for a def-id is not + // a *read* of its metadata. This is because the def-id is + // really just an interned shorthand for a def-path, which is the + // canonical name for an item. + // + // self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_key(&cdata, def.index) } fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { - self.dep_graph.read(DepNode::MetaData(def)); + // See `Note` above in `def_key()` for why this read is + // commented out: + // + // self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_path(&cdata, def.index) } diff --git a/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs new file mode 100644 index 0000000000000..4d84e844dedbb --- /dev/null +++ b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs @@ -0,0 +1,18 @@ +// 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. + +#![allow(warnings)] +#![crate_name = "a"] +#![crate_type = "rlib"] + +pub fn foo(b: u8) -> u32 { b as u32 } + +#[cfg(rpass1)] +fn bar() { } diff --git a/src/test/incremental/remove-private-item-cross-crate/main.rs b/src/test/incremental/remove-private-item-cross-crate/main.rs new file mode 100644 index 0000000000000..582ee905d7ca4 --- /dev/null +++ b/src/test/incremental/remove-private-item-cross-crate/main.rs @@ -0,0 +1,28 @@ +// 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. + +// Test that we are able to reuse `main` even though a private +// item was removed from the root module of crate`a`. + +// revisions:rpass1 rpass2 +// aux-build:a.rs + +#![feature(rustc_attrs)] +#![crate_type = "bin"] +#![rustc_partition_reused(module="main", cfg="rpass2")] + +extern crate a; + +pub fn main() { + let vec: Vec = vec![0, 1, 2, 3]; + for &b in &vec { + println!("{}", a::foo(b)); + } +} From 07df8125e6a32796a14ac253aa0df2a0847098b6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 11:55:32 -0400 Subject: [PATCH 594/768] kill the forbidden code supplanted by RUST_FORBID_DEP_GRAPH_EDGE --- src/librustc/dep_graph/graph.rs | 16 ---------------- src/librustc/dep_graph/raii.rs | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index ca441c4bc3ff2..c42eeead69ec1 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -38,10 +38,6 @@ struct DepGraphData { /// Work-products that we generate in this run. work_products: RefCell, WorkProduct>>, - - /// Tracks nodes that are forbidden to read/write; see - /// `DepGraph::forbid`. Used for debugging only. - forbidden: RefCell>>, } impl DepGraph { @@ -51,7 +47,6 @@ impl DepGraph { thread: DepGraphThreadData::new(enabled), previous_work_products: RefCell::new(FnvHashMap()), work_products: RefCell::new(FnvHashMap()), - forbidden: RefCell::new(Vec::new()), }) } } @@ -75,15 +70,6 @@ impl DepGraph { raii::DepTask::new(&self.data.thread, key) } - /// Debugging aid -- forbid reads/writes to `key` while the return - /// value is in scope. Note that this is only available when debug - /// assertions are enabled -- you should not check in code that - /// invokes this function. - #[cfg(debug_assertions)] - pub fn forbid<'graph>(&'graph self, key: DepNode) -> raii::Forbid<'graph> { - raii::Forbid::new(&self.data.forbidden, key) - } - pub fn with_ignore(&self, op: OP) -> R where OP: FnOnce() -> R { @@ -99,12 +85,10 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { - debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Read(v)); } pub fn write(&self, v: DepNode) { - debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Write(v)); } diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index b344eb486240b..4445a02785b56 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -49,19 +49,3 @@ impl<'graph> Drop for IgnoreTask<'graph> { } } -pub struct Forbid<'graph> { - forbidden: &'graph RefCell>> -} - -impl<'graph> Forbid<'graph> { - pub fn new(forbidden: &'graph RefCell>>, node: DepNode) -> Self { - forbidden.borrow_mut().push(node); - Forbid { forbidden: forbidden } - } -} - -impl<'graph> Drop for Forbid<'graph> { - fn drop(&mut self) { - self.forbidden.borrow_mut().pop(); - } -} From 2446e258fcc0f5554f91e54d2f849da4dd69a026 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 14:26:16 -0400 Subject: [PATCH 595/768] kill extra `use` --- src/librustc/dep_graph/raii.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index 4445a02785b56..e4f572902f9e5 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -9,7 +9,6 @@ // except according to those terms. use hir::def_id::DefId; -use std::cell::RefCell; use super::DepNode; use super::thread::{DepGraphThreadData, DepMessage}; From dadce2521e332a6d8f8704ce440637b8a4df7c66 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 18:38:54 -0400 Subject: [PATCH 596/768] always print def-path in Debug impl for DefId I also added an `opt_def_path` so that we can deal with DefIds that are missing a `DefPath` entry. --- src/librustc/hir/def_id.rs | 19 ++++++---------- src/librustc/middle/cstore.rs | 4 ++-- src/librustc/ty/mod.rs | 37 ++++++++++++++++++++++++++++---- src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/decoder.rs | 13 ++++++++--- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index a3b83ec5be4bd..16afa705e3919 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -58,19 +58,14 @@ impl fmt::Debug for DefId { write!(f, "DefId {{ krate: {:?}, node: {:?}", self.krate, self.index)?; - // Unfortunately, there seems to be no way to attempt to print - // a path for a def-id, so I'll just make a best effort for now - // and otherwise fallback to just printing the crate/node pair - if self.is_local() { // (1) - // (1) side-step fact that not all external things have paths at - // the moment, such as type parameters - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - write!(f, " => {}", tcx.item_path_str(*self))?; + ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_path) = tcx.opt_def_path(*self) { + write!(f, " => {}", def_path.to_string(tcx))?; } - Ok(()) - })?; - } + } + Ok(()) + })?; write!(f, " }}") } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b33bc520fe216..52645883a8be9 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -233,7 +233,7 @@ pub trait CrateStore<'tcx> { def: DefKey) -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; + fn relative_def_path(&self, def: DefId) -> Option; fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; @@ -430,7 +430,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { bug!("relative_def_path") } + fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78358ce534d99..53838b0760a79 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2437,12 +2437,41 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Returns the `DefPath` of an item. Note that if `id` is not - /// local to this crate -- or is inlined into this crate -- the - /// result will be a non-local `DefPath`. + /// Convert a `DefId` into its fully expanded `DefPath` (every + /// `DefId` is really just an interned def-path). + /// + /// Note that if `id` is not local to this crate -- or is + /// inlined into this crate -- the result will be a non-local + /// `DefPath`. + /// + /// This function is only safe to use when you are sure that the + /// full def-path is accessible. Examples that are known to be + /// safe are local def-ids or items; see `opt_def_path` for more + /// details. pub fn def_path(self, id: DefId) -> ast_map::DefPath { + self.opt_def_path(id).unwrap_or_else(|| { + bug!("could not load def-path for {:?}", id) + }) + } + + /// Convert a `DefId` into its fully expanded `DefPath` (every + /// `DefId` is really just an interned def-path). + /// + /// When going across crates, we do not save the full info for + /// every cross-crate def-id, and hence we may not always be able + /// to create a def-path. Therefore, this returns + /// `Option` to cover that possibility. It will always + /// return `Some` for local def-ids, however, as well as for + /// items. The problems arise with "minor" def-ids like those + /// associated with a pattern, `impl Trait`, or other internal + /// detail to a fn. + /// + /// Note that if `id` is not local to this crate -- or is + /// inlined into this crate -- the result will be a non-local + /// `DefPath`. + pub fn opt_def_path(self, id: DefId) -> Option { if id.is_local() { - self.map.def_path(id) + Some(self.map.def_path(id)) } else { self.sess.cstore.relative_def_path(id) } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 5e5cc7e1e6108..d7ca93235fddb 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -435,7 +435,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::def_key(&cdata, def.index) } - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { + fn relative_def_path(&self, def: DefId) -> Option { // See `Note` above in `def_key()` for why this read is // commented out: // diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d75d5a3b35443..5bad89f1a593f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -759,7 +759,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: krate: cdata.cnum, index: def_key(cdata, id).parent.unwrap() }; - let mut parent_def_path = def_path(cdata, id); + let mut parent_def_path = def_path(cdata, id).unwrap(); parent_def_path.data.pop(); if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { let ii = decode_inlined_item(cdata, @@ -1626,9 +1626,16 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { } } -pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { +// Returns the path leading to the thing with this `id`. Note that +// some def-ids don't wind up in the metadata, so `def_path` sometimes +// returns `None` +pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { debug!("def_path(id={:?})", id); - hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent)) + if cdata.get_item(id).is_some() { + Some(hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))) + } else { + None + } } pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy { From c2ffa2f938ec3171180b8e0d4dc20bf92b3a8cfd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Sep 2016 06:48:17 -0400 Subject: [PATCH 597/768] pacify the mercilous tidy add licenses to shadow.rs --- src/librustc/dep_graph/shadow.rs | 10 ++++++++++ src/librustc/middle/cstore.rs | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index e038997e0ad42..f9f75d006775f 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -1,3 +1,13 @@ +// Copyright 2012-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. + //! The "Shadow Graph" is maintained on the main thread and which //! tracks each message relating to the dep-graph and applies some //! sanity checks as they go by. If an error results, it means you get diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 52645883a8be9..d1722ac6f2f7f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -430,7 +430,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } - fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } + fn relative_def_path(&self, def: DefId) -> Option { + bug!("relative_def_path") + } fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } From 3057b7b9749f16ad982b54b4bdeee7e2c8a845bb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Sep 2016 12:14:43 -0400 Subject: [PATCH 598/768] ICH: Make CachingCodemapView robustly handle invalid spans. --- .../calculate_svh/caching_codemap_view.rs | 36 ++++++++++++++----- .../calculate_svh/svh_visitor.rs | 15 ++++---- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs index 32aa5a4272871..ad9c48420e217 100644 --- a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs +++ b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs @@ -53,16 +53,16 @@ impl<'tcx> CachingCodemapView<'tcx> { pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) - -> (Rc, usize, BytePos) { + -> Option<(Rc, usize, BytePos)> { self.time_stamp += 1; // Check if the position is in one of the cached lines for cache_entry in self.line_cache.iter_mut() { if pos >= cache_entry.line_start && pos < cache_entry.line_end { cache_entry.time_stamp = self.time_stamp; - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); + return Some((cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start)); } } @@ -78,8 +78,26 @@ impl<'tcx> CachingCodemapView<'tcx> { // If the entry doesn't point to the correct file, fix it up if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { - let file_index = self.codemap.lookup_filemap_idx(pos); - cache_entry.file = self.codemap.files.borrow()[file_index].clone(); + let file_valid; + let files = self.codemap.files.borrow(); + + if files.len() > 0 { + let file_index = self.codemap.lookup_filemap_idx(pos); + let file = files[file_index].clone(); + + if pos >= file.start_pos && pos < file.end_pos { + cache_entry.file = file; + file_valid = true; + } else { + file_valid = false; + } + } else { + file_valid = false; + } + + if !file_valid { + return None; + } } let line_index = cache_entry.file.lookup_line(pos).unwrap(); @@ -90,8 +108,8 @@ impl<'tcx> CachingCodemapView<'tcx> { cache_entry.line_end = line_bounds.1; cache_entry.time_stamp = self.time_stamp; - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); + return Some((cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start)); } } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 05a2f751d2921..b1cad10f60aa8 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -86,8 +86,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let (file1, line1, col1) = self.codemap.byte_pos_to_line_and_col(span.lo); - let (file2, line2, col2) = self.codemap.byte_pos_to_line_and_col(span_hi); + let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); + let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); let expansion_kind = match span.expn_id { NO_EXPANSION => SawSpanExpnKind::NoExpansion, @@ -95,9 +95,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { _ => SawSpanExpnKind::SomeExpansion, }; - SawSpan(&file1.name[..], line1, col1, - &file2.name[..], line2, col2, - expansion_kind).hash(self.st); + SawSpan(loc1.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), + loc2.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), + expansion_kind) + .hash(self.st); if expansion_kind == SawSpanExpnKind::SomeExpansion { let call_site = self.codemap.codemap().source_callsite(span); @@ -171,7 +172,9 @@ enum SawAbiComponent<'a> { SawAssocTypeBinding, SawAttribute(ast::AttrStyle), SawMacroDef, - SawSpan(&'a str, usize, BytePos, &'a str, usize, BytePos, SawSpanExpnKind), + SawSpan(Option<(&'a str, usize, BytePos)>, + Option<(&'a str, usize, BytePos)>, + SawSpanExpnKind), } /// SawExprComponent carries all of the information that we want From d8c58d40eff80a256b27cab875795e42d83817ee Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 6 Sep 2016 18:53:43 +0200 Subject: [PATCH 599/768] re-add accidentally removed line --- src/librustc_typeck/check/wfcheck.rs | 1 + src/test/compile-fail/issue-36299.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/test/compile-fail/issue-36299.rs diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6e87c29c4b363..c61d3e1a8762c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -480,6 +480,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { (ast_generics.lifetimes[index].lifetime.span, ast_generics.lifetimes[index].lifetime.name) } else { + let index = index - ast_generics.lifetimes.len(); (ast_generics.ty_params[index].span, ast_generics.ty_params[index].name) }; diff --git a/src/test/compile-fail/issue-36299.rs b/src/test/compile-fail/issue-36299.rs new file mode 100644 index 0000000000000..88ac74cb09e42 --- /dev/null +++ b/src/test/compile-fail/issue-36299.rs @@ -0,0 +1,15 @@ +// 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. + +struct Foo<'a, A> {} +//~^ ERROR parameter `'a` is never used +//~| ERROR parameter `A` is never used + +fn main() {} From 3784067edcbcd0614f6c4c88f6445ca17ae27ff6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 2 Sep 2016 12:01:03 -0700 Subject: [PATCH 600/768] Point macros 1.1 errors to the input item Before: ```rust error[E0106]: missing lifetime specifier --> src/main.rs:10:10 | 10 | #[derive(Serialize, Deserialize)] | ^ expected lifetime parameter error[E0038]: the trait `T` cannot be made into an object --> src/main.rs:15:15 | 15 | #[derive(Serialize, Deserialize)] | ^^^^^^^^^^ the trait `T` cannot be made into an object ``` After: ```rust error[E0106]: missing lifetime specifier --> src/main.rs:11:1 | 11 | struct A { | ^ expected lifetime parameter error[E0038]: the trait `T` cannot be made into an object --> src/main.rs:16:1 | 16 | struct B<'a> { | ^ the trait `T` cannot be made into an object ``` --- src/libsyntax_ext/deriving/custom.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 1f9c24a0dcd69..716cf3a94b516 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -53,6 +53,7 @@ impl MultiItemModifier for CustomDerive { } } + let input_span = item.span; let input = __internal::new_token_stream(item); let res = __internal::set_parse_sess(&ecx.parse_sess, || { let inner = self.inner; @@ -77,9 +78,9 @@ impl MultiItemModifier for CustomDerive { // Right now we have no knowledge of spans at all in custom derive // macros, everything is just parsed as a string. Reassign all spans to - // the #[derive] attribute for better errors here. + // the input `item` for better errors here. item.into_iter().flat_map(|item| { - ChangeSpan { span: span }.fold_item(item) + ChangeSpan { span: input_span }.fold_item(item) }).map(Annotatable::Item).collect() } } From 68d29cba95da88fafc5853c78b484f2708a305d8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 11:23:49 +1200 Subject: [PATCH 601/768] save-analysis: add docs data --- src/librustc_save_analysis/data.rs | 11 ++++++ src/librustc_save_analysis/dump_visitor.rs | 33 +++++++++++++---- src/librustc_save_analysis/external_data.rs | 24 +++++++++++- src/librustc_save_analysis/json_api_dumper.rs | 12 ++++++ src/librustc_save_analysis/json_dumper.rs | 12 ++++++ src/librustc_save_analysis/lib.rs | 37 ++++++++++++++++--- 6 files changed, 116 insertions(+), 13 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index a58cce0745f30..5f6e65e289fd5 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -134,6 +134,7 @@ pub struct EnumData { pub scope: NodeId, pub variants: Vec, pub visibility: Visibility, + pub docs: String, } /// Data for extern crates. @@ -167,6 +168,7 @@ pub struct FunctionData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } /// Data about a function call. @@ -213,6 +215,7 @@ pub struct MacroData { pub span: Span, pub name: String, pub qualname: String, + pub docs: String, } /// Data about a macro use. @@ -248,6 +251,7 @@ pub struct MethodData { pub value: String, pub decl_id: Option, pub visibility: Visibility, + pub docs: String, } /// Data for modules. @@ -261,6 +265,7 @@ pub struct ModData { pub filename: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } /// Data for a reference to a module. @@ -283,6 +288,7 @@ pub struct StructData { pub value: String, pub fields: Vec, pub visibility: Visibility, + pub docs: String, } #[derive(Debug, RustcEncodable)] @@ -295,6 +301,7 @@ pub struct StructVariantData { pub value: String, pub scope: NodeId, pub parent: Option, + pub docs: String, } #[derive(Debug, RustcEncodable)] @@ -307,6 +314,7 @@ pub struct TraitData { pub value: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } #[derive(Debug, RustcEncodable)] @@ -319,6 +327,7 @@ pub struct TupleVariantData { pub value: String, pub scope: NodeId, pub parent: Option, + pub docs: String, } /// Data for a typedef. @@ -331,6 +340,7 @@ pub struct TypeDefData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } /// Data for a reference to a type or trait. @@ -374,6 +384,7 @@ pub struct VariableData { pub value: String, pub type_value: String, pub visibility: Visibility, + pub docs: String, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a695a07066205..faf9cb2b0e3bd 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -36,7 +36,7 @@ use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; use std::collections::HashSet; use std::hash::*; -use syntax::ast::{self, NodeId, PatKind}; +use syntax::ast::{self, NodeId, PatKind, Attribute}; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string}; @@ -44,7 +44,7 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector}; +use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; use super::data::*; use super::dump::Dump; use super::external_data::Lower; @@ -368,6 +368,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: 0, parent: None, visibility: Visibility::Inherited, + docs: String::new(), }.lower(self.tcx)); } } @@ -380,6 +381,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { id: ast::NodeId, name: ast::Name, vis: Visibility, + attrs: &[Attribute], span: Span) { debug!("process_method: {}:{}", id, name); @@ -421,6 +423,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: sig_str, decl_id: decl_id, visibility: vis, + docs: docs_for_attrs(attrs), }.lower(self.tcx)); } @@ -491,6 +494,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: String::new(), visibility: Visibility::Inherited, parent: None, + docs: String::new(), }.lower(self.tcx)); } } @@ -541,7 +545,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { typ: &ast::Ty, expr: &ast::Expr, parent_id: NodeId, - vis: Visibility) { + vis: Visibility, + attrs: &[Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -558,6 +563,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, parent: Some(parent_id), visibility: vis, + docs: docs_for_attrs(attrs), }.lower(self.tcx)); } @@ -600,6 +606,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, fields: fields, visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), }.lower(self.tcx)); } @@ -653,6 +660,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, scope: enum_data.scope, parent: Some(item.id), + docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -677,6 +685,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, scope: enum_data.scope, parent: Some(item.id), + docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -759,6 +768,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, items: methods.iter().map(|i| i.id).collect(), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1007,6 +1017,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: 0, parent: None, visibility: Visibility::Inherited, + docs: String::new(), }.lower(self.tcx)); } } @@ -1036,7 +1047,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.dumper.macro_data(MacroData { span: sub_span, name: data.name.clone(), - qualname: qualname.clone() + qualname: qualname.clone(), + // FIXME where do macro docs come from? + docs: String::new(), }.lower(self.tcx)); } } @@ -1049,7 +1062,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, scope: data.scope, callee_span: data.callee_span, - imported: data.imported + imported: data.imported, }.lower(self.tcx)); } } @@ -1065,7 +1078,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &ty, &expr, trait_id, - Visibility::Public); + Visibility::Public, + &trait_item.attrs); } ast::TraitItemKind::Method(ref sig, ref body) => { self.process_method(sig, @@ -1073,6 +1087,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { trait_item.id, trait_item.ident.name, Visibility::Public, + &trait_item.attrs, trait_item.span); } ast::TraitItemKind::Const(_, None) | @@ -1091,7 +1106,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &ty, &expr, impl_id, - From::from(&impl_item.vis)); + From::from(&impl_item.vis), + &impl_item.attrs); } ast::ImplItemKind::Method(ref sig, ref body) => { self.process_method(sig, @@ -1099,6 +1115,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { impl_item.id, impl_item.ident.name, From::from(&impl_item.vis), + &impl_item.attrs, impl_item.span); } ast::ImplItemKind::Type(_) | @@ -1240,6 +1257,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> value: value, visibility: From::from(&item.vis), parent: None, + docs: docs_for_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1429,6 +1447,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> scope: 0, parent: None, visibility: Visibility::Inherited, + docs: String::new(), }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 4333c6dd18e60..3642346582bb9 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -93,6 +93,7 @@ pub struct EnumData { pub scope: DefId, pub variants: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::EnumData { @@ -108,6 +109,7 @@ impl Lower for data::EnumData { scope: make_def_id(self.scope, &tcx.map), variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -170,6 +172,7 @@ pub struct FunctionData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } impl Lower for data::FunctionData { @@ -186,6 +189,7 @@ impl Lower for data::FunctionData { value: self.value, visibility: self.visibility, parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -257,6 +261,7 @@ pub struct MacroData { pub span: SpanData, pub name: String, pub qualname: String, + pub docs: String, } impl Lower for data::MacroData { @@ -267,6 +272,7 @@ impl Lower for data::MacroData { span: SpanData::from_span(self.span, tcx.sess.codemap()), name: self.name, qualname: self.qualname, + docs: self.docs, } } } @@ -330,7 +336,8 @@ pub struct MethodData { pub value: String, pub decl_id: Option, pub visibility: Visibility, - pub parent: Option + pub parent: Option, + pub docs: String, } impl Lower for data::MethodData { @@ -347,6 +354,7 @@ impl Lower for data::MethodData { decl_id: self.decl_id, visibility: self.visibility, parent: Some(make_def_id(self.scope, &tcx.map)), + docs: self.docs, } } } @@ -362,6 +370,7 @@ pub struct ModData { pub filename: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::ModData { @@ -377,6 +386,7 @@ impl Lower for data::ModData { filename: self.filename, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -414,6 +424,7 @@ pub struct StructData { pub value: String, pub fields: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::StructData { @@ -430,6 +441,7 @@ impl Lower for data::StructData { value: self.value, fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -444,6 +456,7 @@ pub struct StructVariantData { pub value: String, pub scope: DefId, pub parent: Option, + pub docs: String, } impl Lower for data::StructVariantData { @@ -459,6 +472,7 @@ impl Lower for data::StructVariantData { value: self.value, scope: make_def_id(self.scope, &tcx.map), parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -473,6 +487,7 @@ pub struct TraitData { pub value: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::TraitData { @@ -488,6 +503,7 @@ impl Lower for data::TraitData { value: self.value, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -502,6 +518,7 @@ pub struct TupleVariantData { pub value: String, pub scope: DefId, pub parent: Option, + pub docs: String, } impl Lower for data::TupleVariantData { @@ -517,6 +534,7 @@ impl Lower for data::TupleVariantData { value: self.value, scope: make_def_id(self.scope, &tcx.map), parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -531,6 +549,7 @@ pub struct TypeDefData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } impl Lower for data::TypeDefData { @@ -545,6 +564,7 @@ impl Lower for data::TypeDefData { value: self.value, visibility: self.visibility, parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -632,6 +652,7 @@ pub struct VariableData { pub type_value: String, pub parent: Option, pub visibility: Visibility, + pub docs: String, } impl Lower for data::VariableData { @@ -649,6 +670,7 @@ impl Lower for data::VariableData { type_value: self.type_value, parent: self.parent.map(|id| make_def_id(id, &tcx.map)), visibility: self.visibility, + docs: self.docs, } } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 874babb907e4c..751c2d06ee757 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -168,6 +168,7 @@ struct Def { parent: Option, children: Vec, decl_id: Option, + docs: String, } #[derive(Debug, RustcEncodable)] @@ -209,6 +210,7 @@ impl From for Option { parent: None, children: data.variants.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, }), _ => None, } @@ -227,6 +229,7 @@ impl From for Option { parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, + docs: data.docs, }) } } @@ -242,6 +245,7 @@ impl From for Option { parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, + docs: data.docs, }) } } @@ -258,6 +262,7 @@ impl From for Option { parent: None, children: data.fields.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, }), _ => None, } @@ -276,6 +281,7 @@ impl From for Option { children: data.items.into_iter().map(|id| From::from(id)).collect(), parent: None, decl_id: None, + docs: data.docs, }), _ => None, } @@ -294,6 +300,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: None, + docs: data.docs, }), _ => None, } @@ -312,6 +319,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: data.decl_id.map(|id| From::from(id)), + docs: data.docs, }), _ => None, } @@ -329,6 +337,7 @@ impl From for Option { children: vec![], parent: None, decl_id: None, + docs: data.docs, }) } } @@ -345,6 +354,7 @@ impl From for Option { children: data.items.into_iter().map(|id| From::from(id)).collect(), parent: None, decl_id: None, + docs: data.docs, }), _ => None, } @@ -363,6 +373,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: None, + docs: String::new(), }), _ => None, } @@ -386,6 +397,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: None, + docs: data.docs, }), _ => None, } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index b1955cbd7b801..3000376e72460 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -183,6 +183,7 @@ struct Def { value: String, children: Vec, decl_id: Option, + docs: String, } #[derive(Debug, RustcEncodable)] @@ -223,6 +224,7 @@ impl From for Def { value: data.value, children: data.variants.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -238,6 +240,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } @@ -252,6 +255,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } @@ -266,6 +270,7 @@ impl From for Def { value: data.value, children: data.fields.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -280,6 +285,7 @@ impl From for Def { value: data.value, children: data.items.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -294,6 +300,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } @@ -308,6 +315,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: data.decl_id.map(|id| From::from(id)), + docs: data.docs, } } } @@ -322,6 +330,7 @@ impl From for Def { value: String::new(), children: vec![], decl_id: None, + docs: data.docs, } } } @@ -336,6 +345,7 @@ impl From for Def { value: data.filename, children: data.items.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -350,6 +360,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: String::new(), } } } @@ -369,6 +380,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index f32baf30ff42e..eeb8d02429c06 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -29,6 +29,7 @@ extern crate serialize as rustc_serialize; extern crate syntax_pos; + mod csv_dumper; mod json_api_dumper; mod json_dumper; @@ -50,8 +51,8 @@ use std::env; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use syntax::ast::{self, NodeId, PatKind}; -use syntax::parse::token::{self, keywords}; +use syntax::ast::{self, NodeId, PatKind, Attribute}; +use syntax::parse::token::{self, keywords, InternedString}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; use syntax::codemap::MacroAttribute; @@ -142,6 +143,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: make_signature(decl, generics), visibility: From::from(&item.vis), parent: None, + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -168,6 +170,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: value, type_value: ty_to_string(&typ), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -185,6 +188,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Mod(ref m) => { @@ -204,6 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { filename: filename, items: m.items.iter().map(|i| i.id).collect(), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Enum(ref def, _) => { @@ -225,6 +230,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), variants: def.variants.iter().map(|v| v.node.data.id()).collect(), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => { @@ -291,6 +297,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: "".to_owned(), type_value: typ, visibility: From::from(&field.vis), + docs: docs_for_attrs(&field.attrs), }) } else { None @@ -303,7 +310,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, vis) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -316,7 +323,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - (result, From::from(&item.vis)) + (result, From::from(&item.vis), docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -338,7 +345,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(def_id) => { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { - (format!("::{}", self.tcx.item_path_str(def_id)), From::from(&item.vis)) + (format!("::{}", self.tcx.item_path_str(def_id)), + From::from(&item.vis), + docs_for_attrs(&item.attrs)) } r => { span_bug!(span, @@ -382,6 +391,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: String::new(), visibility: vis, parent: Some(parent_scope), + docs: docs, }) } @@ -739,6 +749,23 @@ impl Visitor for PathCollector { } } + +fn docs_for_attrs(attrs: &[Attribute]) -> String { + let doc = InternedString::new("doc"); + let mut result = String::new(); + + for attr in attrs { + if attr.name() == doc { + if let Some(ref val) = attr.value_str() { + result.push_str(val); + result.push('\n'); + } + } + } + + result +} + #[derive(Clone, Copy, Debug)] pub enum Format { Csv, From 31100403fd7a3734b9281cc530795716f94240a0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 11:28:13 +1200 Subject: [PATCH 602/768] save-analysis: add a `kind` tag to JSON dumps --- src/librustc_save_analysis/json_api_dumper.rs | 10 ++++++++++ src/librustc_save_analysis/json_dumper.rs | 3 +++ src/librustc_save_analysis/lib.rs | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 751c2d06ee757..78eaa65872a4c 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -16,6 +16,8 @@ use rustc_serialize::json::as_json; use external_data::*; use data::{VariableKind, Visibility}; use dump::Dump; +use super::Format; + // A dumper to dump a restricted set of JSON information, designed for use with // libraries distributed without their source. Clients are likely to use type @@ -81,17 +83,25 @@ impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { #[derive(Debug, RustcEncodable)] struct Analysis { + kind: Format, prelude: Option, imports: Vec, defs: Vec, + // These two fields are dummies so that clients can parse the two kinds of + // JSON data in the same way. + refs: Vec<()>, + macro_refs: Vec<()>, } impl Analysis { fn new() -> Analysis { Analysis { + kind: Format::JsonApi, prelude: None, imports: vec![], defs: vec![], + refs: vec![], + macro_refs: vec![], } } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 3000376e72460..2de883a55d324 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -16,6 +16,7 @@ use rustc_serialize::json::as_json; use external_data::*; use data::VariableKind; use dump::Dump; +use super::Format; pub struct JsonDumper<'b, W: Write + 'b> { output: &'b mut W, @@ -87,6 +88,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { #[derive(Debug, RustcEncodable)] struct Analysis { + kind: Format, prelude: Option, imports: Vec, defs: Vec, @@ -97,6 +99,7 @@ struct Analysis { impl Analysis { fn new() -> Analysis { Analysis { + kind: Format::Json, prelude: None, imports: vec![], defs: vec![], diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index eeb8d02429c06..99ab0d2684fe8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -766,7 +766,7 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { result } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { Csv, Json, From a77b55d58f9b173b1e4fb96bb6935fadbfda3240 Mon Sep 17 00:00:00 2001 From: Justin LeFebvre Date: Tue, 6 Sep 2016 01:04:07 -0400 Subject: [PATCH 603/768] remove the extraneous not_equal implementation for slices. --- src/libcore/slice.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index baa41aa7af5b2..b22bdb43414fd 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1821,7 +1821,8 @@ impl PartialOrd for [T] { // intermediate trait for specialization of slice's PartialEq trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; - fn not_equal(&self, other: &[B]) -> bool; + + fn not_equal(&self, other: &[B]) -> bool { !self.equal(other) } } // Generic slice equality @@ -1841,20 +1842,6 @@ impl SlicePartialEq for [A] true } - - default fn not_equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return true; - } - - for i in 0..self.len() { - if self[i].ne(&other[i]) { - return true; - } - } - - false - } } // Use memcmp for bytewise equality when the types allow @@ -1874,10 +1861,6 @@ impl SlicePartialEq for [A] other.as_ptr() as *const u8, size) == 0 } } - - fn not_equal(&self, other: &[A]) -> bool { - !self.equal(other) - } } #[doc(hidden)] From 0adcf46cdf3d85e78e761fdaaa9c3fa8a69df927 Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Tue, 6 Sep 2016 18:31:00 -0700 Subject: [PATCH 604/768] detecting nodejs in configure --- configure | 4 ++++ src/bootstrap/bootstrap.py | 9 --------- src/bootstrap/config.rs | 3 --- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/configure b/configure index bcc1faea3b5d8..352b77560b73c 100755 --- a/configure +++ b/configure @@ -634,6 +634,7 @@ valopt datadir "${CFG_PREFIX}/share" "install data" valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" +valopt nodejs "" "set path to nodejs" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "" "Android NDK standalone path (deprecated)" @@ -749,6 +750,9 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi +# Checking for node, but not required +probe CFG_NODEJS nodejs node + # If we have no git directory then we are probably a tarball distribution # and shouldn't attempt to load submodules if [ ! -e ${CFG_SRC_DIR}.git ] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3f4a18ab1247d..17a7c9ca66a26 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -236,15 +236,6 @@ def rustc(self): return config + '/bin/rustc' + self.exe_suffix() return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix()) - def nodejs(self): - config = self.get_toml('nodejs') - if config: - return config - if os.path.exists(os.path.join(self.bin_root(), "bin/nodejs")): - return os.path.join(self.bin_root(), "bin/nodejs" + self.exe_suffix()) - elif os.path.exists(os.path.join(self.bin_root(), "bin/node")): - return os.path.join(self.bin_root(), "bin/node" + self.exe_suffix()) - def get_string(self, line): start = line.find('"') end = start + 1 + line[start+1:].find('"') diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5a7ae4f6973d5..682a6f74126a8 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -67,7 +67,6 @@ pub struct Config { pub target: Vec, pub rustc: Option, pub cargo: Option, - pub nodejs: Option, pub local_rebuild: bool, // libstd features @@ -112,7 +111,6 @@ struct Build { host: Vec, target: Vec, cargo: Option, - nodejs: Option, rustc: Option, compiler_docs: Option, docs: Option, @@ -217,7 +215,6 @@ impl Config { } config.rustc = build.rustc.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from); - config.nodejs = build.nodejs.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); From b99c5cf109925b3a13aa768ad4644000d926b851 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 7 Sep 2016 04:15:56 +0200 Subject: [PATCH 605/768] doc: we got coercion going on here, so no need to be this explicit --- src/libstd/path.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9a5b1da0f08f4..12f8619cde64a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1169,9 +1169,9 @@ impl PathBuf { /// let mut p = PathBuf::from("/test/test.rs"); /// /// p.pop(); - /// assert_eq!(Path::new("/test"), p.as_path()); + /// assert_eq!(Path::new("/test"), p); /// p.pop(); - /// assert_eq!(Path::new("/"), p.as_path()); + /// assert_eq!(Path::new("/"), p); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pop(&mut self) -> bool { From 8cfc69ecea9874ad28253ecc47d50099f9e7001e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 6 Sep 2016 21:49:02 -0500 Subject: [PATCH 606/768] add utility musl_root method, update config.toml.example --- src/bootstrap/compile.rs | 3 +-- src/bootstrap/config.toml.example | 10 ++++++---- src/bootstrap/lib.rs | 7 +++++++ src/bootstrap/sanity.rs | 3 +-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e14317b23b4d1..dbb356c82e6fb 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -60,8 +60,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } } if target.contains("musl") { - if let Some(p) = build.config.target_config[target].musl_root.as_ref() - .or(build.config.musl_root.as_ref()) { + if let Some(p) = build.musl_root(target) { cargo.env("MUSL_ROOT", p); } } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef622..1b453baa29846 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -115,10 +115,6 @@ # nightly features #channel = "dev" -# The root location of the MUSL installation directory. The library directory -# will also need to contain libunwind.a for an unwinding implementation. -#musl-root = "..." - # By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix # platforms to ensure that the compiler is usable by default from the build # directory (as it links to a number of dynamic libraries). This may not be @@ -160,3 +156,9 @@ # the NDK for the target lives. This is used to find the C compiler to link and # build native code. #android-ndk = "/path/to/ndk" + +# The root location of the MUSL installation directory. The library directory +# will also need to contain libunwind.a for an unwinding implementation. Note +# that this option only makes sense for MUSL targets that produce statically +# linked binaries +#musl-root = "..." diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index dbf29cda49212..94c14f7ea2546 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -977,6 +977,13 @@ impl Build { } return base } + + /// Returns the "musl root" for this `target`, if defined + fn musl_root(&self, target: &str) -> Option<&Path> { + self.config.target_config[target].musl_root.as_ref() + .or(self.config.musl_root.as_ref()) + .map(|p| &**p) + } } impl<'a> Compiler<'a> { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index f1d7f869a9657..c69f9489c306d 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -111,8 +111,7 @@ pub fn check(build: &mut Build) { // Make sure musl-root is valid if specified if target.contains("musl") && !target.contains("mips") { - match build.config.target_config[target].musl_root.as_ref() - .or(build.config.musl_root.as_ref()) { + match build.musl_root(target) { Some(root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { panic!("couldn't find libc.a in musl dir: {}", From f84d081a7e705da1f3e920801319424b53cfd8b0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 09:47:35 +0000 Subject: [PATCH 607/768] Avoid instaiblity errors in code generated by `syntax_ext::deriving::call_intrinsic()`. --- src/libsyntax_ext/deriving/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 5582166c12e9c..fcbce36389082 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -338,10 +338,19 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { /// Constructs an expression that calls an intrinsic fn call_intrinsic(cx: &ExtCtxt, - span: Span, + mut span: Span, intrinsic: &str, args: Vec>) -> P { + span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern("derive")), + span: Some(span), + allow_internal_unstable: true, + }, + }); + let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); From d6ea10ec764bbddd39cc4a3d34b6a4987ac867a6 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Sep 2016 03:09:09 +0000 Subject: [PATCH 608/768] Add regression test. --- .../auxiliary/custom_derive_partial_eq.rs | 81 +++++++++++++++++++ .../custom-derive-partial-eq.rs | 22 +++++ 2 files changed, 103 insertions(+) create mode 100644 src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs create mode 100644 src/test/run-pass-fulldeps/custom-derive-partial-eq.rs diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs new file mode 100644 index 0000000000000..956f789dab839 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs @@ -0,0 +1,81 @@ +// 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. + +// force-host + +#![feature(plugin_registrar, rustc_private, item_like_imports)] + +extern crate syntax; +extern crate syntax_ext; +extern crate rustc_plugin; + +use syntax_ext::deriving; +use deriving::generic::*; +use deriving::generic::ty::*; + +use rustc_plugin::Registry; +use syntax::ast::*; +use syntax::codemap::Span; +use syntax::ext::base::*; +use syntax::ext::build::AstBuilder; +use syntax::parse::token::{intern, InternedString}; +use syntax::ptr::P; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_syntax_extension(intern("derive_CustomPartialEq"), + MultiDecorator(Box::new(expand_deriving_partial_eq))); +} + +fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, + push: &mut FnMut(Annotatable)) { + // structures are equal if all fields are equal, and non equal, if + // any fields are not equal or if the enum variants are different + fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_fold(true, + |cx, span, subexpr, self_f, other_fs| { + let other_f = (other_fs.len(), other_fs.get(0)).1.unwrap(); + let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); + cx.expr_binary(span, BinOpKind::And, subexpr, eq) + }, + cx.expr_bool(span, true), + Box::new(|cx, span, _, _| cx.expr_bool(span, false)), + cx, + span, + substr) + } + + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + let methods = vec![MethodDef { + name: "eq", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec!(borrowed_self()), + ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")), + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(cs_eq)), + }]; + + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: deriving::generic::ty::Path::new(vec!["std", "cmp", "PartialEq"]), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + is_unsafe: false, + supports_unions: false, + methods: methods, + associated_types: Vec::new(), + }; + trait_def.expand(cx, mitem, item, push) +} diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs new file mode 100644 index 0000000000000..8cc7ab4219dc5 --- /dev/null +++ b/src/test/run-pass-fulldeps/custom-derive-partial-eq.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. + +// aux-build:custom_derive_partial_eq.rs +// ignore-stage1 +// ignore-pretty : (#23623) problems when ending with // comments + +#![feature(plugin, custom_derive)] +#![plugin(custom_derive_partial_eq)] +#![allow(unused)] + +#[derive(CustomPartialEq)] // Check that this is not a stability error. +enum E { V1, V2 } + +fn main() {} From 102b3a937b8bb5ef601fd586a3d9ffcd518d6bf3 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 6 Sep 2016 21:10:15 -0400 Subject: [PATCH 609/768] Add doc example for `std::time::Instant::elapsed`. --- src/libstd/time/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 0e1508a1c4c28..154f603c84f16 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -150,6 +150,18 @@ impl Instant { /// This function may panic if the current time is earlier than this /// instant, which is something that can happen if an `Instant` is /// produced synthetically. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, Instant}; + /// + /// let instant = Instant::now(); + /// let three_secs = Duration::from_secs(3); + /// sleep(three_secs); + /// assert!(instant.elapsed() >= three_secs); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn elapsed(&self) -> Duration { Instant::now() - *self From 8760a5e3cc8bab89053ef9cee9757160e76f517d Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 17:09:24 +0200 Subject: [PATCH 610/768] Follow target ABI sign-/zero-extension rules for enum types While attempting to port Rust to s390x, I ran into an ABI violation (that caused rust_eh_personality to be miscompiled, breaking unwinding). The problem is that this function returns an enum type, which is supposed to be sign-extended according to the s390x ABI. However, common code would ignore target sign-/zero-extension rules for any types that do not satisfy is_integral(), which includes enums. For the general case of Rust enum types, which map to structure types with a discriminant, that seems correct. However, in the special case of simple enums that map directly to C enum types (i.e. LLVM integers), this is incorrect; we must follow the target extension rules for those. Signed-off-by: Ulrich Weigand --- src/librustc_trans/abi.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c2b040c32f6a3..ab0fd0c92edd4 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -26,6 +26,7 @@ use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; use type_of; +use adt; use rustc::hir; use rustc::ty::{self, Ty}; @@ -317,6 +318,14 @@ impl FnType { if ty.is_integral() { arg.signedness = Some(ty.is_signed()); } + // Rust enum types that map onto C enums (LLVM integers) also + // need to follow the target ABI zero-/sign-extension rules. + if let ty::TyEnum(..) = ty.sty { + if arg.ty.kind() == llvm::Integer { + let repr = adt::represent_type(ccx, ty); + arg.signedness = Some(adt::is_discr_signed(&repr)); + } + } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. From 3f0462acbbabc7703dffdd2771d6cca56eb5545b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 17:21:10 +0200 Subject: [PATCH 611/768] Fix argument to FIONBIO ioctl The FIONBIO ioctl takes as argument a pointer to an integer, which should be either 0 or 1 to indicate whether nonblocking mode is to be switched off or on. The type of the pointed-to variable is "int". However, the set_nonblocking routine in libstd/sys/unix/net.rs passes a pointer to a libc::c_ulong variable. This doesn't matter on all 32-bit platforms and on all litte-endian platforms, but it will break on big-endian 64-bit platforms. Found while porting Rust to s390x (a big-endian 64-bit platform). Signed-off-by: Ulrich Weigand --- src/libstd/sys/unix/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 3f77abd7f44d8..f124ea651ec2c 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -213,7 +213,7 @@ impl Socket { } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_ulong; + let mut nonblocking = nonblocking as libc::c_int; cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ()) } From ce413e0da234ecc68648c81d7c476da3a8d68b9e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 12:37:16 +1200 Subject: [PATCH 612/768] save-analysis: tweak the type value for functions --- src/librustc_save_analysis/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 99ab0d2684fe8..164869c5e1592 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -676,7 +676,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { - let mut sig = String::new(); + let mut sig = "fn ".to_owned(); if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { sig.push('<'); sig.push_str(&generics.lifetimes.iter() @@ -696,7 +696,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::>().join(", ")); sig.push(')'); match decl.output { - ast::FunctionRetTy::Default(_) => {} + ast::FunctionRetTy::Default(_) => sig.push_str(" -> ()"), ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))), } From 493544a1f9009c794015697440093f59ab1856c7 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 08:31:11 -0700 Subject: [PATCH 613/768] save-analysis: only emit type in the value for variables --- src/librustc_save_analysis/dump_visitor.rs | 8 ++++++-- src/librustc_save_analysis/json_dumper.rs | 2 +- src/librustc_save_analysis/lib.rs | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index faf9cb2b0e3bd..05859a63c5d31 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1427,11 +1427,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> for &(id, ref p, immut, ref_kind) in &collector.collected_paths { match self.tcx.expect_def(id) { Def::Local(_, id) => { - let value = if immut == ast::Mutability::Immutable { + let mut value = if immut == ast::Mutability::Immutable { self.span.snippet(p.span).to_string() } else { "".to_string() }; + let typ = self.tcx.node_types() + .get(&id).map(|t| t.to_string()).unwrap_or(String::new()); + value.push_str(": "); + value.push_str(&typ); assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); @@ -1443,7 +1447,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> name: path_to_string(p), qualname: format!("{}${}", path_to_string(p), id), value: value, - type_value: String::new(), + type_value: typ, scope: 0, parent: None, visibility: Visibility::Inherited, diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 2de883a55d324..75abff8d37edb 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -380,7 +380,7 @@ impl From for Def { span: data.span, name: data.name, qualname: data.qualname, - value: data.value, + value: data.type_value, children: vec![], decl_id: None, docs: data.docs, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 164869c5e1592..3c0f10755089b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -749,7 +749,6 @@ impl Visitor for PathCollector { } } - fn docs_for_attrs(attrs: &[Attribute]) -> String { let doc = InternedString::new("doc"); let mut result = String::new(); From b58294e3289cdaca6ef07c77777e4787cad285ad Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 09:27:56 -0700 Subject: [PATCH 614/768] save-analysis: strip /// or whatever from doc comments --- src/librustc_save_analysis/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 3c0f10755089b..6170e14940ec1 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -52,6 +52,7 @@ use std::fs::{self, File}; use std::path::{Path, PathBuf}; use syntax::ast::{self, NodeId, PatKind, Attribute}; +use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::parse::token::{self, keywords, InternedString}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; @@ -756,7 +757,7 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { for attr in attrs { if attr.name() == doc { if let Some(ref val) = attr.value_str() { - result.push_str(val); + result.push_str(&strip_doc_comment_decoration(val)); result.push('\n'); } } From ce3cecf116a2d691c53f37c1d257a416ecfd381b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 21:03:21 +0200 Subject: [PATCH 615/768] Use layout_of to detect C enums --- src/librustc_trans/abi.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index ab0fd0c92edd4..42289ec094f32 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -26,7 +26,6 @@ use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; use type_of; -use adt; use rustc::hir; use rustc::ty::{self, Ty}; @@ -36,6 +35,7 @@ use std::cmp; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; +use rustc::ty::layout::Layout; #[derive(Clone, Copy, PartialEq, Debug)] enum ArgKind { @@ -318,13 +318,10 @@ impl FnType { if ty.is_integral() { arg.signedness = Some(ty.is_signed()); } - // Rust enum types that map onto C enums (LLVM integers) also - // need to follow the target ABI zero-/sign-extension rules. - if let ty::TyEnum(..) = ty.sty { - if arg.ty.kind() == llvm::Integer { - let repr = adt::represent_type(ccx, ty); - arg.signedness = Some(adt::is_discr_signed(&repr)); - } + // Rust enum types that map onto C enums also need to follow + // the target ABI zero-/sign-extension rules. + if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) { + arg.signedness = Some(signed); } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu From 04b776e5eca7aa49618a1425f08c8825e51b19dc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 4 Sep 2016 18:37:30 +0300 Subject: [PATCH 616/768] Zero first byte of CString on drop This should prevent code like ``` let ptr = CString::new("hello").unwrap().as_ptr(); ``` from working by accident. --- src/libstd/ffi/c_str.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 38222c014f61b..2d5e8c0419402 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -19,6 +19,7 @@ use mem; use memchr; use ops; use os::raw::c_char; +use ptr; use slice; use str::{self, Utf8Error}; @@ -68,6 +69,9 @@ use str::{self, Utf8Error}; #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CString { + // Invariant 1: the slice ends with a zero byte and has a length of at least one. + // Invariant 2: the slice contains only one zero byte. + // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. inner: Box<[u8]>, } @@ -244,7 +248,7 @@ impl CString { /// Failure to call `from_raw` will lead to a memory leak. #[stable(feature = "cstr_memory", since = "1.4.0")] pub fn into_raw(self) -> *mut c_char { - Box::into_raw(self.inner) as *mut c_char + Box::into_raw(self.into_inner()) as *mut c_char } /// Converts the `CString` into a `String` if it contains valid Unicode data. @@ -265,7 +269,7 @@ impl CString { /// it is guaranteed to not have any interior nul bytes. #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec { - let mut vec = self.inner.into_vec(); + let mut vec = self.into_inner().into_vec(); let _nul = vec.pop(); debug_assert_eq!(_nul, Some(0u8)); vec @@ -275,7 +279,7 @@ impl CString { /// includes the trailing nul byte. #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { - self.inner.into_vec() + self.into_inner().into_vec() } /// Returns the contents of this `CString` as a slice of bytes. @@ -293,6 +297,24 @@ impl CString { pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner } + + // Bypass "move out of struct which implements `Drop` trait" restriction. + fn into_inner(self) -> Box<[u8]> { + unsafe { + let result = ptr::read(&self.inner); + mem::forget(self); + result + } + } +} + +// Turns this `CString` into an empty string to prevent +// memory unsafe code from working by accident. +#[stable(feature = "cstring_drop", since = "1.13.0")] +impl Drop for CString { + fn drop(&mut self) { + unsafe { *self.inner.get_unchecked_mut(0) = 0; } + } } #[stable(feature = "rust1", since = "1.0.0")] From f9a340804c998f25691be182fc8bc40b8fc9a496 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 7 Sep 2016 10:13:49 +0300 Subject: [PATCH 617/768] Add a test for CString drop --- src/test/run-pass/cstring-drop.rs | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/run-pass/cstring-drop.rs diff --git a/src/test/run-pass/cstring-drop.rs b/src/test/run-pass/cstring-drop.rs new file mode 100644 index 0000000000000..960391bb8deac --- /dev/null +++ b/src/test/run-pass/cstring-drop.rs @@ -0,0 +1,49 @@ +// 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. + +// ignore-emscripten + +// Test that `CString::new("hello").unwrap().as_ptr()` pattern +// leads to failure. + +use std::env; +use std::ffi::{CString, CStr}; +use std::os::raw::c_char; +use std::process::{Command, Stdio}; + +fn main() { + let args: Vec = env::args().collect(); + if args.len() > 1 && args[1] == "child" { + // Repeat several times to be more confident that + // it is `Drop` for `CString` that does the cleanup, + // and not just some lucky UB. + let xs = vec![CString::new("Hello").unwrap(); 10]; + let ys = xs.iter().map(|s| s.as_ptr()).collect::>(); + drop(xs); + assert!(ys.into_iter().any(is_hello)); + return; + } + + let output = Command::new(&args[0]).arg("child").output().unwrap(); + assert!(!output.status.success()); +} + +fn is_hello(s: *const c_char) -> bool { + // `s` is a dangling pointer and reading it is technically + // undefined behavior. But we want to prevent the most diabolical + // kind of UB (apart from nasal demons): reading a value that was + // previously written. + // + // Segfaulting or reading an empty string is Ok, + // reading "Hello" is bad. + let s = unsafe { CStr::from_ptr(s) }; + let hello = CString::new("Hello").unwrap(); + s == hello.as_ref() +} From 7e46f2ceaa84ae7ba7143fcbe8bb3d0da2449fb4 Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Wed, 7 Sep 2016 13:13:37 -0700 Subject: [PATCH 618/768] moving nodejs detection logic to configure and adding a nodejs cmd sanity check --- src/bootstrap/config.rs | 4 ++++ src/bootstrap/sanity.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a8..b170120251195 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -79,6 +79,7 @@ pub struct Config { pub musl_root: Option, pub prefix: Option, pub codegen_tests: bool, + pub nodejs: Option, } /// Per-target configuration stored in the global configuration structure. @@ -391,6 +392,9 @@ impl Config { self.rustc = Some(PathBuf::from(value).join("bin/rustc")); self.cargo = Some(PathBuf::from(value).join("bin/cargo")); } + "CFG_NODEJS" if value.len() > 0 => { + self.nodejs = Some(PathBuf::from(value)); + } _ => {} } } diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index ae7f2e018f9f9..c345893954f46 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -76,7 +76,7 @@ pub fn check(build: &mut Build) { need_cmd("python".as_ref()); // If a manual nodejs was added to the config, - // of if a nodejs install is detected through bootstrap.py, use it. + // of if a nodejs install is detected through config, use it. if build.config.nodejs.is_some() { need_cmd("nodejs".as_ref()) } From f6aab5b9e516f3086e75745f53aaf77212bedde9 Mon Sep 17 00:00:00 2001 From: Jakob Demler Date: Wed, 7 Sep 2016 22:15:32 +0200 Subject: [PATCH 619/768] Fixed typo in nomicon --- src/doc/nomicon/ownership.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/nomicon/ownership.md b/src/doc/nomicon/ownership.md index 6be8d3b70286a..a6ecf6ab91b4f 100644 --- a/src/doc/nomicon/ownership.md +++ b/src/doc/nomicon/ownership.md @@ -52,7 +52,7 @@ let mut data = vec![1, 2, 3]; let x = &data[0]; // OH NO! `push` causes the backing storage of `data` to be reallocated. -// Dangling pointer! User after free! Alas! +// Dangling pointer! Use after free! Alas! // (this does not compile in Rust) data.push(4); From 41d1cd7196d6799fa960ac220d20b958c1b797ed Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 7 Sep 2016 23:18:46 +0200 Subject: [PATCH 620/768] add static_in_const feature gate also updates tests and deletes the spurious .bk files I inadvertently added last time. --- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/rscope.rs | 39 ++++++++++ src/libsyntax/feature_gate.rs | 3 + src/test/compile-fail/const-unsized.rs | 2 + src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/rfc1623.rs | 2 +- src/test/compile-fail/rfc1623.rs.bk | 98 -------------------------- src/test/run-pass/rfc1623.rs | 1 + src/test/run-pass/rfc1623.rs.bk | 81 --------------------- 9 files changed, 48 insertions(+), 182 deletions(-) delete mode 100644 src/test/compile-fail/rfc1623.rs.bk delete mode 100644 src/test/run-pass/rfc1623.rs.bk diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fcc0b09e31acf..0eb6a747263ea 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1567,7 +1567,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, ..) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t) + ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index f5b13c4207d90..5b00a625bacf5 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -213,6 +213,45 @@ impl RegionScope for ElidableRscope { } } +/// A scope that behaves as an ElidabeRscope with a `'static` default region +/// that should also warn if the `static_in_const` feature is unset. +#[derive(Copy, Clone)] +pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { + /// create a new StaticRscope from a reference to the `TyCtxt` + pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self { + StaticRscope { tcx: tcx } + } +} + +impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { + fn anon_regions(&self, + _span: Span, + count: usize) + -> Result, Option>> { + Ok(vec![ty::ReStatic; count]) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + if !self.tcx.sess.features.borrow().static_in_const { + self.tcx + .sess + .struct_span_warn(span, + "This needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") + .emit(); + } + ty::ReStatic + } +} + /// A scope in which we generate anonymous, late-bound regions for /// omitted regions. This occurs in function signatures. pub struct BindingRscope { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dd2956f706c95..8b8a41fc20488 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -295,6 +295,9 @@ declare_features! ( // Allows untagged unions `union U { ... }` (active, untagged_unions, "1.13.0", Some(32836)), + + // elide `'static` lifetimes in `static`s and `const`s + (active, static_in_const, "1.13.0", Some(35897)), ); declare_features! ( diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index a73164b957c83..07d6edb1f3b15 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,6 +15,7 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size +//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -27,6 +28,7 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size +//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index b9382520cf9d3..d721c8bb6d2bf 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - + //~| WARNING: This needs a `'static` lifetime or the `static_in_const` feature 0 }; } diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 1d8fc7fe111c0..083cc218eecf3 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(static_in_const)] #![allow(dead_code)] fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { diff --git a/src/test/compile-fail/rfc1623.rs.bk b/src/test/compile-fail/rfc1623.rs.bk deleted file mode 100644 index abdcc02de767f..0000000000000 --- a/src/test/compile-fail/rfc1623.rs.bk +++ /dev/null @@ -1,98 +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. - -#![allow(dead_code)] - -fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } - -// the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ ERROR: missing lifetime specifier - &(non_elidable as fn(&u8, &u8) -> &u8); - -struct SomeStruct<'x, 'y, 'z: 'x> { - foo: &'x Foo<'z>, - bar: &'x Bar<'z>, - f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, -} - -fn id(t: T) -> T { t } - -static SOME_STRUCT : &SomeStruct = SomeStruct { - foo: &Foo { bools: &[false, true] }, - bar: &Bar { bools: &[true, true] }, - f: &id, -}; - -// very simple test for a 'static static with default lifetime -static STATIC_STR : &'static str = "&'static str"; -const CONST_STR : &'static str = "&'static str"; - -// this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; - -// a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] -} - -static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; -const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; - -type Bar<'a> = Foo<'a>; - -static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; -const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; - -type Baz<'a> = fn(&'a [u8]) -> Option; - -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } - -static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); -const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); - -static BYTES : &'static [u8] = &[1, 2, 3]; - -fn main() { - let x = &[1u8, 2, 3]; - let y = x; - - //this works, so lifetime < `'static` is valid - assert_eq!(Some(1), STATIC_BAZ(y)); - assert_eq!(Some(1), CONST_BAZ(y)); - - let y = &[1u8, 2, 3]; - //^~ ERROR: borrowed values does not live long enough - STATIC_BAZ(BYTES); // BYTES has static lifetime - CONST_BAZ(y); // This forces static lifetime, which y has not -} diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 17453933c8abc..fc9143dc450b7 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(static_in_const)] #![allow(dead_code)] // very simple test for a 'static static with default lifetime diff --git a/src/test/run-pass/rfc1623.rs.bk b/src/test/run-pass/rfc1623.rs.bk deleted file mode 100644 index 0915118ca27c0..0000000000000 --- a/src/test/run-pass/rfc1623.rs.bk +++ /dev/null @@ -1,81 +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. - -#![allow(dead_code)] - -// very simple test for a 'static static with default lifetime -static STATIC_STR : &str = "&'static str"; -const CONST_STR : &str = "&'static str"; - -// this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; - -// a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] -} - -static STATIC_FOO : Foo = Foo { bools: &[true, false] }; -const CONST_FOO : Foo = Foo { bools: &[true, false] }; - -type Bar<'a> = Foo<'a>; - -static STATIC_BAR : Bar = Bar { bools: &[true, false] }; -const CONST_BAR : Bar = Bar { bools: &[true, false] }; - -type Baz<'a> = fn(&'a [u8]) -> Option; - -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } - -static STATIC_BAZ : &Baz = &(baz as Baz); -const CONST_BAZ : &Baz = &(baz as Baz); - -static BYTES : &[u8] = &[1, 2, 3]; - -fn main() { - // make sure that the lifetime is actually elided (and not defaulted) - let x = &[1u8, 2, 3]; - STATIC_SIMPLE_FN(x); - CONST_SIMPLE_FN(x); - - STATIC_BAZ(BYTES); // neees static lifetime - CONST_BAZ(BYTES); - - // make sure this works with different lifetimes - let a = &1; - { - let b = &2; - let c = &3; - CONST_MULTI_FN(a, b, c); - } -} From 3af0c6572eebd2c7fad72e8ba37eac71b8abc8bc Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 2 Sep 2016 01:44:23 +0000 Subject: [PATCH 621/768] Refactor code out of the folder implementation for `StripUnconfigured`. --- src/libsyntax/config.rs | 124 ++++++++++++++++------------- src/libsyntax/util/small_vector.rs | 6 ++ 2 files changed, 75 insertions(+), 55 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 7f6395997abe1..07604bffa1c66 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -13,7 +13,7 @@ use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_fea use {fold, attr}; use ast; use codemap::{Spanned, respan}; -use parse::{ParseSess, token}; +use parse::ParseSess; use ptr::P; use util::small_vector::SmallVector; @@ -60,6 +60,15 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool) (krate, features) } +macro_rules! configure { + ($this:ident, $node:ident) => { + match $this.configure($node) { + Some(node) => node, + None => return Default::default(), + } + } +} + impl<'a> StripUnconfigured<'a> { fn configure(&mut self, node: T) -> Option { let node = self.process_cfg_attrs(node); @@ -156,37 +165,35 @@ impl<'a> StripUnconfigured<'a> { } } } -} -impl<'a> fold::Folder for StripUnconfigured<'a> { - fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, - items: foreign_mod.items.into_iter().filter_map(|item| { - self.configure(item).map(|item| fold::noop_fold_foreign_item(item, self)) - }).collect(), + items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(), } } - fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - let fold_struct = |this: &mut Self, vdata| match vdata { + fn configure_variant_data(&mut self, vdata: ast::VariantData) -> ast::VariantData { + match vdata { ast::VariantData::Struct(fields, id) => { - let fields = fields.into_iter().filter_map(|field| this.configure(field)); + let fields = fields.into_iter().filter_map(|field| self.configure(field)); ast::VariantData::Struct(fields.collect(), id) } ast::VariantData::Tuple(fields, id) => { - let fields = fields.into_iter().filter_map(|field| this.configure(field)); + let fields = fields.into_iter().filter_map(|field| self.configure(field)); ast::VariantData::Tuple(fields.collect(), id) } ast::VariantData::Unit(id) => ast::VariantData::Unit(id) - }; + } + } - let item = match item { + fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + match item { ast::ItemKind::Struct(def, generics) => { - ast::ItemKind::Struct(fold_struct(self, def), generics) + ast::ItemKind::Struct(self.configure_variant_data(def), generics) } ast::ItemKind::Union(def, generics) => { - ast::ItemKind::Union(fold_struct(self, def), generics) + ast::ItemKind::Union(self.configure_variant_data(def), generics) } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { @@ -195,7 +202,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { node: ast::Variant_ { name: v.node.name, attrs: v.node.attrs, - data: fold_struct(self, v.node.data), + data: self.configure_variant_data(v.node.data), disr_expr: v.node.disr_expr, }, span: v.span @@ -207,12 +214,19 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { }, generics) } item => item, - }; + } + } - fold::noop_fold_item_kind(item, self) + fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind { + if let ast::ExprKind::Match(m, arms) = expr_kind { + let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect(); + ast::ExprKind::Match(m, arms) + } else { + expr_kind + } } - fn fold_expr(&mut self, expr: P) -> P { + fn configure_expr(&mut self, expr: P) -> P { self.visit_stmt_or_expr_attrs(expr.attrs()); // If an expr is valid to cfg away it will have been removed by the @@ -227,64 +241,64 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { self.sess.span_diagnostic.span_err(attr.span, msg); } - let expr = self.process_cfg_attrs(expr); - fold_expr(self, expr) + self.process_cfg_attrs(expr) } - fn fold_opt_expr(&mut self, expr: P) -> Option> { - self.configure(expr).map(|expr| fold_expr(self, expr)) + fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option { + self.visit_stmt_or_expr_attrs(stmt.attrs()); + self.configure(stmt) + } +} + +impl<'a> fold::Folder for StripUnconfigured<'a> { + fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + let foreign_mod = self.configure_foreign_mod(foreign_mod); + fold::noop_fold_foreign_mod(foreign_mod, self) } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { - self.visit_stmt_or_expr_attrs(stmt.attrs()); - self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self)) - .unwrap_or(SmallVector::zero()) + fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + let item = self.configure_item_kind(item); + fold::noop_fold_item_kind(item, self) } - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) + fn fold_expr(&mut self, expr: P) -> P { + let mut expr = self.configure_expr(expr).unwrap(); + expr.node = self.configure_expr_kind(expr.node); + P(fold::noop_fold_expr(expr, self)) + } + + fn fold_opt_expr(&mut self, expr: P) -> Option> { + let mut expr = configure!(self, expr).unwrap(); + expr.node = self.configure_expr_kind(expr.node); + Some(P(fold::noop_fold_expr(expr, self))) + } + + fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + match self.configure_stmt(stmt) { + Some(stmt) => fold::noop_fold_stmt(stmt, self), + None => return SmallVector::zero(), + } } fn fold_item(&mut self, item: P) -> SmallVector> { - self.configure(item).map(|item| fold::noop_fold_item(item, self)) - .unwrap_or(SmallVector::zero()) + fold::noop_fold_item(configure!(self, item), self) } fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { - self.configure(item).map(|item| fold::noop_fold_impl_item(item, self)) - .unwrap_or(SmallVector::zero()) + fold::noop_fold_impl_item(configure!(self, item), self) } fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { - self.configure(item).map(|item| fold::noop_fold_trait_item(item, self)) - .unwrap_or(SmallVector::zero()) + fold::noop_fold_trait_item(configure!(self, item), self) } - fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal { + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { // Don't configure interpolated AST (c.f. #34171). // Interpolated AST will get configured once the surrounding tokens are parsed. - nt + mac } } -fn fold_expr(folder: &mut StripUnconfigured, expr: P) -> P { - expr.map(|ast::Expr {id, span, node, attrs}| { - fold::noop_fold_expr(ast::Expr { - id: id, - node: match node { - ast::ExprKind::Match(m, arms) => { - ast::ExprKind::Match(m, arms.into_iter() - .filter_map(|a| folder.configure(a)) - .collect()) - } - _ => node - }, - span: span, - attrs: attrs, - }, folder) - }) -} - fn is_cfg(attr: &ast::Attribute) -> bool { attr.check_name("cfg") } diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 893646f121f0c..373dfc4ddfac5 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -29,6 +29,12 @@ enum SmallVectorRepr { Many(Vec), } +impl Default for SmallVector { + fn default() -> Self { + SmallVector { repr: Zero } + } +} + impl Into> for SmallVector { fn into(self) -> Vec { match self.repr { From d951d5dec44f71eed82daba0854f404cc4bfe2a5 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Wed, 7 Sep 2016 18:26:53 -0400 Subject: [PATCH 622/768] Handle `ReEmpty` for `impl Trait` Closes #35668 --- src/librustc_typeck/check/writeback.rs | 4 ++-- src/test/compile-fail/issue-35668.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-35668.rs diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 4be032c6f7f09..0b70d904c2654 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -319,7 +319,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { match *r { // 'static is valid everywhere. - ty::ReStatic => gcx.mk_region(ty::ReStatic), + ty::ReStatic | + ty::ReEmpty => gcx.mk_region(*r), // Free regions that come from early-bound regions are valid. ty::ReFree(ty::FreeRegion { @@ -341,7 +342,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } ty::ReVar(_) | - ty::ReEmpty | ty::ReErased => { let span = reason.span(self.tcx()); span_bug!(span, "invalid region in impl Trait: {:?}", r); diff --git a/src/test/compile-fail/issue-35668.rs b/src/test/compile-fail/issue-35668.rs new file mode 100644 index 0000000000000..c9323db054c86 --- /dev/null +++ b/src/test/compile-fail/issue-35668.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(conservative_impl_trait)] + +fn func<'a, T>(a: &'a [T]) -> impl Iterator { + a.iter().map(|a| a*a) + //~^ ERROR binary operation `*` cannot be applied to type `&T` +} + +fn main() { + let a = (0..30).collect::>(); + + for k in func(&a) { + println!("{}", k); + } +} From d76bf3ed80b0f6d6fb44704f98df1067353de300 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Sep 2016 22:24:01 +0000 Subject: [PATCH 623/768] Strip unconfigured nodes in the `InvocationCollector` fold. --- src/libsyntax/config.rs | 12 +++--- src/libsyntax/ext/expand.rs | 73 ++++++++++++++++++++++++++++++------- src/libsyntax/lib.rs | 1 + 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 07604bffa1c66..3f5b294cc0443 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -70,7 +70,7 @@ macro_rules! configure { } impl<'a> StripUnconfigured<'a> { - fn configure(&mut self, node: T) -> Option { + pub fn configure(&mut self, node: T) -> Option { let node = self.process_cfg_attrs(node); if self.in_cfg(node.attrs()) { Some(node) } else { None } } @@ -166,7 +166,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + pub fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(), @@ -187,7 +187,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + pub fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { match item { ast::ItemKind::Struct(def, generics) => { ast::ItemKind::Struct(self.configure_variant_data(def), generics) @@ -217,7 +217,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind { + pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind { if let ast::ExprKind::Match(m, arms) = expr_kind { let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect(); ast::ExprKind::Match(m, arms) @@ -226,7 +226,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_expr(&mut self, expr: P) -> P { + pub fn configure_expr(&mut self, expr: P) -> P { self.visit_stmt_or_expr_attrs(expr.attrs()); // If an expr is valid to cfg away it will have been removed by the @@ -244,7 +244,7 @@ impl<'a> StripUnconfigured<'a> { self.process_cfg_attrs(expr) } - fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option { + pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option { self.visit_stmt_or_expr_attrs(stmt.attrs()); self.configure(stmt) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0986d32ff56ac..68aca3ee32f93 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -208,14 +208,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { - let expansion = expansion.fold_with(&mut StripUnconfigured { - config: &self.cx.cfg, - should_test: self.cx.ecfg.should_test, - sess: self.cx.parse_sess, - features: self.cx.ecfg.features, - }); - let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() }; - (expansion.fold_with(&mut collector), collector.invocations) + let crate_config = mem::replace(&mut self.cx.cfg, Vec::new()); + let result = { + let mut collector = InvocationCollector { + cfg: StripUnconfigured { + config: &crate_config, + should_test: self.cx.ecfg.should_test, + sess: self.cx.parse_sess, + features: self.cx.ecfg.features, + }, + cx: self.cx, + invocations: Vec::new(), + }; + (expansion.fold_with(&mut collector), collector.invocations) + }; + + self.cx.cfg = crate_config; + result } fn expand_invoc(&mut self, invoc: Invocation) -> Expansion { @@ -403,9 +412,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { struct InvocationCollector<'a, 'b: 'a> { cx: &'a mut ExtCtxt<'b>, + cfg: StripUnconfigured<'a>, invocations: Vec, } +macro_rules! fully_configure { + ($this:ident, $node:ident, $noop_fold:ident) => { + match $noop_fold($node, &mut $this.cfg).pop() { + Some(node) => node, + None => return SmallVector::zero(), + } + } +} + impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { let mark = Mark::fresh(); @@ -475,11 +494,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } false } + + fn configure(&mut self, node: T) -> Option { + self.cfg.configure(node) + } } impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_expr(&mut self, expr: P) -> P { - let expr = expr.unwrap(); + let mut expr = self.cfg.configure_expr(expr).unwrap(); + expr.node = self.cfg.configure_expr_kind(expr.node); + if let ast::ExprKind::Mac(mac) = expr.node { self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr() } else { @@ -488,7 +513,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_opt_expr(&mut self, expr: P) -> Option> { - let expr = expr.unwrap(); + let mut expr = configure!(self, expr).unwrap(); + expr.node = self.cfg.configure_expr_kind(expr.node); + if let ast::ExprKind::Mac(mac) = expr.node { self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr) .make_opt_expr() @@ -511,6 +538,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + let stmt = match self.cfg.configure_stmt(stmt) { + Some(stmt) => stmt, + None => return SmallVector::zero(), + }; + let (mac, style, attrs) = match stmt.node { StmtKind::Mac(mac) => mac.unwrap(), _ => return noop_fold_stmt(stmt, self), @@ -540,9 +572,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_item(&mut self, item: P) -> SmallVector> { + let item = configure!(self, item); + let (item, attr) = self.classify_item(item); if let Some(attr) = attr { - let item = Annotatable::Item(item); + let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item)); return self.collect_attr(attr, item, ExpansionKind::Items).make_items(); } @@ -610,9 +644,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + let item = configure!(self, item); + let (item, attr) = self.classify_item(item); if let Some(attr) = attr { - let item = Annotatable::TraitItem(P(item)); + let item = + Annotatable::TraitItem(P(fully_configure!(self, item, noop_fold_trait_item))); return self.collect_attr(attr, item, ExpansionKind::TraitItems).make_trait_items() } @@ -626,9 +663,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + let item = configure!(self, item); + let (item, attr) = self.classify_item(item); if let Some(attr) = attr { - let item = Annotatable::ImplItem(P(item)); + let item = Annotatable::ImplItem(P(fully_configure!(self, item, noop_fold_impl_item))); return self.collect_attr(attr, item, ExpansionKind::ImplItems).make_impl_items(); } @@ -653,6 +692,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { _ => unreachable!(), } } + + fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self) + } + + fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + noop_fold_item_kind(self.cfg.configure_item_kind(item), self) + } } pub struct ExpansionConfig<'feat> { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 42201231247af..4a2c9aff2d2b4 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -104,6 +104,7 @@ pub mod abi; pub mod ast; pub mod attr; pub mod codemap; +#[macro_use] pub mod config; pub mod entry; pub mod feature_gate; From 2d759046ba685f419b3de79367e5b973c1b84105 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 2 Sep 2016 03:35:59 +0000 Subject: [PATCH 624/768] Implement stackless placeholder expansion. --- src/libsyntax/ext/expand.rs | 19 +++++++++++++++---- src/libsyntax/ext/placeholders.rs | 11 +++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 68aca3ee32f93..c5b637a980000 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -26,7 +26,6 @@ use ptr::P; use tokenstream::TokenTree; use util::small_vector::SmallVector; -use std::collections::HashMap; use std::mem; use std::path::PathBuf; use std::rc::Rc; @@ -182,10 +181,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Fully expand all the invocations in `expansion`. fn expand(&mut self, expansion: Expansion) -> Expansion { + self.cx.recursion_count = 0; let (expansion, mut invocations) = self.collect_invocations(expansion); invocations.reverse(); - let mut expansions = HashMap::new(); + let mut expansions = vec![vec![(0, expansion)]]; while let Some(invoc) = invocations.pop() { let Invocation { mark, module, depth, backtrace, .. } = invoc; self.cx.syntax_env.current_module = module; @@ -198,13 +198,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.recursion_count = depth + 1; let (expansion, new_invocations) = self.collect_invocations(expansion); - expansions.insert(mark.as_u32(), expansion); + if expansions.len() == depth { + expansions.push(Vec::new()); + } + expansions[depth].push((mark.as_u32(), expansion)); if !self.single_step { invocations.extend(new_invocations.into_iter().rev()); } } - expansion.fold_with(&mut PlaceholderExpander::new(expansions)) + let mut placeholder_expander = PlaceholderExpander::new(); + while let Some(expansions) = expansions.pop() { + for (mark, expansion) in expansions.into_iter().rev() { + let expansion = expansion.fold_with(&mut placeholder_expander); + placeholder_expander.add(mark, expansion); + } + } + + placeholder_expander.remove(0) } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f1665bdde7510..abadcf867b146 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -74,15 +74,18 @@ pub struct PlaceholderExpander { } impl PlaceholderExpander { - pub fn new(expansions: HashMap) -> Self { + pub fn new() -> Self { PlaceholderExpander { - expansions: expansions, + expansions: HashMap::new(), } } + pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) { + self.expansions.insert(id, expansion); + } + pub fn remove(&mut self, id: ast::NodeId) -> Expansion { - let expansion = self.expansions.remove(&id).unwrap(); - expansion.fold_with(self) + self.expansions.remove(&id).unwrap() } } From 9ac91fa48b3eb479cccb5695395faed8f59ece8e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 04:08:38 +0000 Subject: [PATCH 625/768] Improve `directory` computation during invocation collection. --- src/libsyntax/ext/expand.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c5b637a980000..4715eda837490 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -615,16 +615,20 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ast::ItemKind::Mod(ast::Mod { inner, .. }) => { let mut paths = (*self.cx.syntax_env.paths()).clone(); paths.mod_path.push(item.ident); - if item.span.contains(inner) { + + // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). + // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). + // Thus, if `inner` is the dummy span, we know the module is inline. + let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; + + if inline_module { paths.directory.push(&*{ ::attr::first_attr_value_str_by_name(&item.attrs, "path") .unwrap_or(item.ident.name.as_str()) }); } else { - paths.directory = match inner { - syntax_pos::DUMMY_SP => PathBuf::new(), - _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)), - }; + paths.directory = + PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)); paths.directory.pop(); } From a2faf5477c46e425d02b48ec0be6eea49c694fc2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Sep 2016 01:16:06 +0200 Subject: [PATCH 626/768] Set run button transparent instead of invisible --- src/librustdoc/html/highlight.rs | 6 +++++- src/librustdoc/html/markdown.rs | 8 +++++--- src/librustdoc/html/render.rs | 3 ++- src/librustdoc/html/static/playpen.js | 15 +-------------- src/librustdoc/html/static/rustdoc.css | 5 ++++- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 6cb79d6e8630f..855588a4c3a4b 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -33,7 +33,8 @@ use syntax::parse; use syntax_pos::Span; /// Highlights `src`, returning the HTML output. -pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>) -> String { +pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>, + extension: Option<&str>) -> String { debug!("highlighting: ================\n{}\n==============", src); let sess = parse::ParseSess::new(); let fm = sess.codemap().new_filemap("".to_string(), None, src.to_string()); @@ -47,6 +48,9 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str> return format!("
{}
", src); } + if let Some(extension) = extension { + write!(out, "{}", extension).unwrap(); + } write_footer(&mut out).unwrap(); String::from_utf8_lossy(&out[..]).into_owned() } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 139e1033175ea..aff5a964f75cc 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -262,9 +262,11 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { &Default::default()); s.push_str(&format!("{}", Escape(&test))); }); - s.push_str(&highlight::render_with_highlighting(&text, - Some("rust-example-rendered"), - None)); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + Some("
Run"))); let output = CString::new(s).unwrap(); hoedown_buffer_puts(ob, output.as_ptr()); }) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4c6ac56105c67..147710c39f477 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2909,7 +2909,7 @@ impl<'a> fmt::Display for Source<'a> { write!(fmt, "{0:1$}\n", i, cols)?; } write!(fmt, "

")?; - write!(fmt, "{}", highlight::render_with_highlighting(s, None, None))?; + write!(fmt, "{}", highlight::render_with_highlighting(s, None, None, None))?; Ok(()) } } @@ -2918,6 +2918,7 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Macro) -> fmt::Result { w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), + None, None))?; render_stability_since_raw(w, it.stable_since(), None)?; document(w, cx, it) diff --git a/src/librustdoc/html/static/playpen.js b/src/librustdoc/html/static/playpen.js index 8f8a753b06c96..cad97c04e1ac0 100644 --- a/src/librustdoc/html/static/playpen.js +++ b/src/librustdoc/html/static/playpen.js @@ -27,9 +27,7 @@ document.addEventListener('DOMContentLoaded', function() { return; } - var a = document.createElement('a'); - a.setAttribute('class', 'test-arrow'); - a.textContent = 'Run'; + var a = el.querySelectorAll('a.test-arrow')[0]; var code = el.previousElementSibling.textContent; @@ -40,17 +38,6 @@ document.addEventListener('DOMContentLoaded', function() { a.setAttribute('href', window.playgroundUrl + '?code=' + encodeURIComponent(code) + channel); - a.setAttribute('target', '_blank'); - - el.appendChild(a); - }; - - el.onmouseout = function(e) { - if (el.contains(e.relatedTarget)) { - return; - } - - el.removeChild(el.querySelectorAll('a.test-arrow')[0]); }; }); }); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index c97cacd10c381..2884320b82ebd 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -568,15 +568,18 @@ pre.rust .lifetime { color: #B76514; } .rusttest { display: none; } pre.rust { position: relative; } a.test-arrow { + background-color: rgba(78, 139, 202, 0.2); display: inline-block; position: absolute; - background-color: #4e8bca; padding: 5px 10px 5px 10px; border-radius: 5px; font-size: 130%; top: 5px; right: 5px; } +a.test-arrow:hover{ + background-color: #4e8bca; +} .section-header:hover a:after { content: '\2002\00a7\2002'; From a25428269d8cac3ef00162a19dcbb5d5d5c47192 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 7 Sep 2016 17:22:19 -0700 Subject: [PATCH 627/768] Fix duplicate error code --- src/librustc_typeck/check/wfcheck.rs | 4 ++-- src/librustc_typeck/diagnostics.rs | 4 ++-- .../traits-inductive-overflow-supertrait-oibit.rs | 2 +- src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs | 4 ++-- src/test/compile-fail/typeck-auto-trait-no-supertraits.rs | 6 +++--- src/test/compile-fail/typeck-auto-trait-no-typeparams.rs | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6e39e33c9a8d5..0fe703aca79be 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -300,11 +300,11 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { if !items.is_empty() { error_380(self.ccx, span); } else if has_ty_params { - err = Some(struct_span_err!(self.tcx().sess, span, E0566, + err = Some(struct_span_err!(self.tcx().sess, span, E0567, "traits with auto impls (`e.g. impl \ Trait for ..`) can not have type parameters")); } else if has_predicates { - err = Some(struct_span_err!(self.tcx().sess, span, E0565, + err = Some(struct_span_err!(self.tcx().sess, span, E0568, "traits with auto impls (`e.g. impl \ Trait for ..`) cannot have predicates")); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7b7b4d2aa00fa..e5c901f223ffb 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4072,6 +4072,6 @@ register_diagnostics! { E0563, // cannot determine a type for this `impl Trait`: {} E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` - E0565, // auto-traits can not have predicates, - E0566, // auto traits can not have type parameters + E0567, // auto traits can not have type parameters + E0568, // auto-traits can not have predicates, } diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index 168148b92fe44..fe0e583b20a38 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -14,7 +14,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 +trait Magic: Copy {} //~ ERROR E0568 impl Magic for .. {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index 60da647f68240..f6678ac7c2d8c 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -10,8 +10,8 @@ #![feature(optin_builtin_traits)] -trait Magic : Sized where Option : Magic {} //~ ERROR E0565 -impl Magic for .. {} +trait Magic : Sized where Option : Magic {} //~ ERROR E0568 +impl Magic for .. {} impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs index 177d594da18a0..9497dfb39d7d0 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -23,7 +23,7 @@ // type that contains a mutable reference, enabling // mutable aliasing. // -// You can imagine an even more dangerous test, +// You can imagine an even more dangerous test, // which currently compiles on nightly. // // fn main() { @@ -34,8 +34,8 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 -impl Magic for .. {} +trait Magic: Copy {} //~ ERROR E0568 +impl Magic for .. {} impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs index f2841a413db9e..5a852c54869a5 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -10,5 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic {} //~ ERROR E0566 +trait Magic {} //~ ERROR E0567 impl Magic for .. {} From e0eea8b7c1fbf2247694a94e216c239e0ec285b1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:26:55 +0200 Subject: [PATCH 628/768] =?UTF-8?q?warning=20=E2=86=92=20error,=20lowercas?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustc_typeck/rscope.rs | 6 +++--- src/test/compile-fail/const-unsized.rs | 4 ++-- src/test/compile-fail/issue-24446.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 5b00a625bacf5..be44dce8a8aca 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -243,9 +243,9 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess - .struct_span_warn(span, - "This needs a `'static` lifetime or the \ - `static_in_const` feature, see #35897") + .struct_span_err(span, + "this needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") .emit(); } ty::ReStatic diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index 07d6edb1f3b15..d3c0bf0021350 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,7 +15,7 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature +//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -28,7 +28,7 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature +//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index d721c8bb6d2bf..bcc1d3c3e42d9 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - //~| WARNING: This needs a `'static` lifetime or the `static_in_const` feature + //~| ERROR: this needs a `'static` lifetime or the `static_in_const` feature 0 }; } From 2859177ea0f36863672e05b8be044b4c94cfd8f1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:29:37 +0200 Subject: [PATCH 629/768] added feature gate test --- .../compile-fail/feature-gate-static-in-const.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-static-in-const.rs diff --git a/src/test/compile-fail/feature-gate-static-in-const.rs b/src/test/compile-fail/feature-gate-static-in-const.rs new file mode 100644 index 0000000000000..c1fc7cdd06cd0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-static-in-const.rs @@ -0,0 +1,14 @@ +// 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. + +static FOO: &str = "this will work once static_in_const is stable"; +//~^ ERROR: this needs a `'static` lifetime or the `static_in_const` feature + +fn main() {} From df611a62bb4407373bea42d2fb623e6579972521 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:34:41 +0200 Subject: [PATCH 630/768] added feature description to reference --- src/doc/reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index f29cdf6b08035..b72c3743a69ce 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2441,6 +2441,9 @@ The currently implemented features of the reference compiler are: into a Rust program. This capability, especially the signature for the annotated function, is subject to change. +* `static_in_const` - Enables lifetime elision with a `'static` default for + `const` and `static` item declarations. + * `thread_local` - The usage of the `#[thread_local]` attribute is experimental and should be seen as unstable. This attribute is used to declare a `static` as being unique per-thread leveraging From 8c9571279dbdfa509ca2c3e81527457cc9ae169f Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 8 Sep 2016 18:43:21 +0900 Subject: [PATCH 631/768] Use LLVM_COMPONENTS to run tests just for supported targets --- src/test/run-make/atomic-lock-free/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile index 78e7bb231372f..3021555f39d8f 100644 --- a/src/test/run-make/atomic-lock-free/Makefile +++ b/src/test/run-make/atomic-lock-free/Makefile @@ -5,22 +5,31 @@ all: ifeq ($(UNAME),Linux) +ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86) $(RUSTC) --target=i686-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=x86_64-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter arm,$(LLVM_COMPONENTS)),arm) $(RUSTC) --target=arm-unknown-linux-gnueabi atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=arm-unknown-linux-gnueabihf atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=armv7-unknown-linux-gnueabihf atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter aarch64,$(LLVM_COMPONENTS)),aarch64) $(RUSTC) --target=aarch64-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter mips,$(LLVM_COMPONENTS)),mips) $(RUSTC) --target=mips-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=mipsel-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter powerpc,$(LLVM_COMPONENTS)),powerpc) $(RUSTC) --target=powerpc-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=powerpc64-unknown-linux-gnu atomic_lock_free.rs @@ -28,3 +37,4 @@ ifeq ($(UNAME),Linux) $(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add endif +endif From a3f05cec762948e68d2f5cc29003781f44f79820 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 8 Sep 2016 12:58:05 +0200 Subject: [PATCH 632/768] clean up `get_vtable`'s doc comment --- src/librustc_trans/meth.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index e958795570eee..ee2f24d21e07c 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -116,9 +116,11 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, llfn } -/// Creates a returns a dynamic vtable for the given type and vtable origin. +/// Creates a dynamic vtable for the given type and vtable origin. /// This is used only for objects. /// +/// The vtables are cached instead of created on every call. +/// /// The `trait_ref` encodes the erased self type. Hence if we are /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T:Trait`. From d4c6a61c44bdf470a88a7a24d83cfd31f9b70992 Mon Sep 17 00:00:00 2001 From: ggomez Date: Thu, 8 Sep 2016 16:08:47 +0200 Subject: [PATCH 633/768] Ignore this block code because of OSX failure --- src/librustc_metadata/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 01c7d7fc79d58..f52e1437acc95 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -32,8 +32,8 @@ as frameworks are specific to that operating system. Erroneous code example: -```compile_fail,E0455 -#[link(name = "FooCoreServices", kind = "framework")] extern {} +```ignore +#[link(name = "FooCoreServices", kind = "framework")] extern {} // OS used to compile is Linux for example ``` From dd570d64be6f95d601d5104d93207538b236f7cd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Sep 2016 19:18:07 +0200 Subject: [PATCH 634/768] For size of `struct P(Q)`, don't double-count the prefix added by `Q`. Fix #36278. Fix #36294. --- src/librustc_trans/glue.rs | 13 ++++++++- .../run-pass/issue-36278-prefix-nesting.rs | 28 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-36278-prefix-nesting.rs diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 34c92f334d0ac..967ecd9ba416e 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -348,9 +348,20 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, let layout = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); + // Returns size in bytes of all fields except the last one + // (we will be recursing on the last one). + fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 { + let fields = variant.offset_after_field.len(); + if fields > 1 { + variant.offset_after_field[fields - 2].bytes() + } else { + 0 + } + } + let (sized_size, sized_align) = match *layout { ty::layout::Layout::Univariant { ref variant, .. } => { - (variant.min_size().bytes(), variant.align.abi()) + (local_prefix_bytes(variant), variant.align.abi()) } _ => { bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", diff --git a/src/test/run-pass/issue-36278-prefix-nesting.rs b/src/test/run-pass/issue-36278-prefix-nesting.rs new file mode 100644 index 0000000000000..95269d0569dec --- /dev/null +++ b/src/test/run-pass/issue-36278-prefix-nesting.rs @@ -0,0 +1,28 @@ +// 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. + +// Issue 36278: On an unsized struct with >1 level of nontrivial +// nesting, ensure we are computing dynamic size of prefix correctly. + +use std::mem; + +const SZ: usize = 100; +struct P([u8; SZ], T); + +type Ack = P>; + +fn main() { + let size_of_sized; let size_of_unsized; + let x: Box> = Box::new(P([0; SZ], P([0; SZ], [0; 0]))); + size_of_sized = mem::size_of_val::>(&x); + let y: Box> = x; + size_of_unsized = mem::size_of_val::>(&y); + assert_eq!(size_of_sized, size_of_unsized); +} From 707a40f2065cb46d12c4f4991e6408585b315c92 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 8 Sep 2016 10:41:48 -0700 Subject: [PATCH 635/768] Point compile-fail errors to the input item instead of the derive --- src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs | 2 +- .../compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs | 2 +- .../compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs index fa0b5763803ff..1300fe66585c9 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs @@ -23,8 +23,8 @@ trait Append { #[derive(PartialEq, Append, Eq)] -//~^^ ERROR: the semantics of constant patterns is not yet settled struct A { +//~^ ERROR: the semantics of constant patterns is not yet settled inner: u32, } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs index 29b9fd228094a..14c3d84e75be3 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs @@ -17,8 +17,8 @@ extern crate derive_unstable_2; #[derive(Unstable)] -//~^ ERROR: reserved for internal compiler struct A; +//~^ ERROR: reserved for internal compiler fn main() { foo(); diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs index 874081760f662..aa9aaa8115628 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs @@ -17,8 +17,8 @@ extern crate derive_unstable; #[derive(Unstable)] -//~^ ERROR: use of unstable library feature struct A; +//~^ ERROR: use of unstable library feature fn main() { unsafe { foo(); } From f2b672d5567c3b20542e845baaf8a9c47d9df907 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Sep 2016 01:26:02 +0300 Subject: [PATCH 636/768] Refactor `TyStruct`/`TyEnum`/`TyUnion` into `TyAdt` --- src/librustc/infer/error_reporting.rs | 5 +- src/librustc/infer/freshen.rs | 4 +- src/librustc/middle/dead.rs | 23 +- src/librustc/middle/effect.rs | 14 +- src/librustc/middle/expr_use_visitor.rs | 43 +- src/librustc/middle/mem_categorization.rs | 5 +- src/librustc/middle/stability.rs | 62 ++- src/librustc/mir/tcx.rs | 7 +- src/librustc/traits/coherence.rs | 6 +- src/librustc/traits/error_reporting.rs | 38 +- src/librustc/traits/select.rs | 16 +- src/librustc/ty/cast.rs | 2 +- src/librustc/ty/contents.rs | 3 +- src/librustc/ty/context.rs | 22 +- src/librustc/ty/error.rs | 8 +- src/librustc/ty/fast_reject.rs | 14 +- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/item_path.rs | 8 +- src/librustc/ty/layout.rs | 426 +++++++++--------- src/librustc/ty/mod.rs | 44 +- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 18 +- src/librustc/ty/structural_impls.rs | 8 +- src/librustc/ty/sty.rs | 43 +- src/librustc/ty/util.rs | 118 ++--- src/librustc/ty/walk.rs | 5 +- src/librustc/ty/wf.rs | 4 +- src/librustc/util/ppaux.rs | 4 +- src/librustc_borrowck/borrowck/check_loans.rs | 4 +- src/librustc_borrowck/borrowck/fragments.rs | 99 ++-- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 4 +- .../borrowck/gather_loans/restrictions.rs | 9 +- .../borrowck/mir/elaborate_drops.rs | 4 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_borrowck/borrowck/move_data.rs | 57 +-- src/librustc_const_eval/check_match.rs | 39 +- src/librustc_const_eval/eval.rs | 15 +- src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/types.rs | 176 ++++---- src/librustc_lint/unused.rs | 4 +- src/librustc_metadata/decoder.rs | 17 +- src/librustc_metadata/tydecode.rs | 18 +- src/librustc_metadata/tyencode.rs | 12 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 91 ++-- src/librustc_mir/hair/cx/pattern.rs | 10 +- src/librustc_mir/transform/type_check.rs | 16 +- src/librustc_passes/consts.rs | 4 +- src/librustc_privacy/lib.rs | 14 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 10 +- src/librustc_trans/adt.rs | 300 ++++++------ src/librustc_trans/base.rs | 3 +- src/librustc_trans/collector.rs | 12 +- src/librustc_trans/common.rs | 7 +- src/librustc_trans/context.rs | 10 +- src/librustc_trans/debuginfo/metadata.rs | 58 ++- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 4 +- src/librustc_trans/glue.rs | 163 +++---- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_trans/trans_item.rs | 4 +- src/librustc_trans/type_of.rs | 14 +- src/librustc_typeck/check/_match.rs | 6 +- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/dropck.rs | 26 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 38 +- src/librustc_typeck/coherence/mod.rs | 15 +- src/librustc_typeck/coherence/orphan.rs | 15 +- src/librustc_typeck/collect.rs | 14 +- src/librustc_typeck/variance/constraints.rs | 4 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 14 +- src/test/run-pass/auxiliary/issue13507.rs | 4 +- 77 files changed, 1087 insertions(+), 1215 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 38f3f055cbb24..b8a3bdfcf2573 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -488,10 +488,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate match (&exp_found.expected.sty, &exp_found.found.sty) { - (&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => { + (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => { report_path_match(err, exp_adt.did, found_adt.did); }, _ => () diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 8aeb0757f5de2..eea12b7f19712 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | - ty::TyEnum(..) | + ty::TyAdt(..) | ty::TyBox(..) | ty::TyStr | ty::TyError | @@ -167,8 +167,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyTrait(..) | - ty::TyStruct(..) | - ty::TyUnion(..) | ty::TyClosure(..) | ty::TyNever | ty::TyTuple(..) | diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 26a89feb2181f..9db6ac1dcefd0 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -86,8 +86,6 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_definition(&mut self, id: ast::NodeId) { - use ty::TypeVariants::{TyEnum, TyStruct, TyUnion}; - let def = self.tcx.expect_def(id); // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar` @@ -95,11 +93,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { - match substs.substs.type_at(0).sty { - TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => { - self.check_def_id(tyid.did) - } - _ => {} + if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty { + self.check_def_id(tyid.did); } } } @@ -133,23 +128,27 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().field_named(name).did); } - _ => span_bug!(lhs.span, "named field access on non-struct/union"), + _ => span_bug!(lhs.span, "named field access on non-ADT"), } } fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.insert_def_id(def.struct_variant().fields[idx].did); + match self.tcx.expr_ty_adjusted(lhs).sty { + ty::TyAdt(def, _) => { + self.insert_def_id(def.struct_variant().fields[idx].did); + } + ty::TyTuple(..) => {} + _ => span_bug!(lhs.span, "numeric field access on non-ADT"), } } fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { let variant = match self.tcx.node_id_to_type(lhs.id).sty { - ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => { + ty::TyAdt(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } _ => span_bug!(lhs.span, "non-ADT in struct pattern") diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index a7af0b50b8494..8b8d15b0b6ebf 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -178,8 +178,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprField(ref base_expr, field) => { - if let ty::TyUnion(..) = self.tcx.expr_ty_adjusted(base_expr).sty { - self.require_unsafe(field.span, "access to union field"); + if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty { + if adt.is_union() { + self.require_unsafe(field.span, "access to union field"); + } } } _ => {} @@ -190,9 +192,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &hir::Pat) { if let PatKind::Struct(_, ref fields, _) = pat.node { - if let ty::TyUnion(..) = self.tcx.pat_ty(pat).sty { - for field in fields { - self.require_unsafe(field.span, "matching on union field"); + if let ty::TyAdt(adt, ..) = self.tcx.pat_ty(pat).sty { + if adt.is_union() { + for field in fields { + self.require_unsafe(field.span, "matching on union field"); + } } } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d32954d3800ad..9f05dde4e66f4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -671,28 +671,31 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - if let ty::TyStruct(def, substs) = with_cmt.ty.sty { - // Consume those fields of the with expression that are needed. - for with_field in &def.struct_variant().fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field( - &*with_expr, - with_cmt.clone(), - with_field.name, - with_field.ty(self.tcx(), substs) - ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + match with_cmt.ty.sty { + ty::TyAdt(adt, substs) if adt.is_struct() => { + // Consume those fields of the with expression that are needed. + for with_field in &adt.struct_variant().fields { + if !contains_field_named(with_field, fields) { + let cmt_field = self.mc.cat_field( + &*with_expr, + with_cmt.clone(), + with_field.name, + with_field.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + } } } - } else { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - span_bug!( - with_expr.span, - "with expression doesn't evaluate to a struct"); + _ => { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + span_bug!( + with_expr.span, + "with expression doesn't evaluate to a struct"); + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f8eb0d4a0ece8..39d5487e8beb1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -223,8 +223,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { Ok(deref_ptr(UnsafePtr(mt.mutbl))) } - ty::TyEnum(..) | - ty::TyStruct(..) => { // newtype + ty::TyAdt(..) => { // newtype Ok(deref_interior(InteriorField(PositionalField(0)))) } @@ -1154,7 +1153,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Struct(..) => { match self.pat_ty(&pat)?.sty { - ty::TyStruct(adt_def, _) => { + ty::TyAdt(adt_def, _) => { adt_def.struct_variant().fields.len() } ref ty => { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c62c99c3b7062..9a56959de38bc 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -20,7 +20,7 @@ use lint; use middle::cstore::LOCAL_CRATE; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; -use ty::{self, TyCtxt}; +use ty::{self, TyCtxt, AdtKind}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; use syntax_pos::{Span, DUMMY_SP}; @@ -561,17 +561,19 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.struct_variant().field_named(field.node).did } _ => span_bug!(e.span, - "stability::check_expr: named field access on non-struct/union") + "stability::check_expr: named field access on non-ADT") } } hir::ExprTupField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => def.struct_variant().fields[field.node].did, + ty::TyAdt(def, _) => { + def.struct_variant().fields[field.node].did + } ty::TyTuple(..) => return, _ => span_bug!(e.span, "stability::check_expr: unnamed field access on \ @@ -579,31 +581,28 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } } hir::ExprStruct(_, ref expr_fields, _) => { - let type_ = tcx.expr_ty(e); - match type_.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { - // check the stability of each field that appears - // in the construction expression. - for field in expr_fields { - let did = def.struct_variant() - .field_named(field.name.node) - .did; - maybe_do_stability_check(tcx, did, field.span, cb); - } + match tcx.expr_ty(e).sty { + ty::TyAdt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + // check the stability of each field that appears + // in the construction expression. + for field in expr_fields { + let did = adt.struct_variant().field_named(field.name.node).did; + maybe_do_stability_check(tcx, did, field.span, cb); + } - // we're done. - return - } - // we don't look at stability attributes on - // struct-like enums (yet...), but it's definitely not - // a bug to have construct one. - ty::TyEnum(..) => return, - _ => { - span_bug!(e.span, - "stability::check_expr: struct construction \ - of non-struct/union, type {:?}", - type_); - } + // we're done. + return + } + AdtKind::Enum => { + // we don't look at stability attributes on + // struct-like enums (yet...), but it's definitely not + // a bug to have construct one. + return + } + }, + ref ty => span_bug!(e.span, "stability::check_expr: struct \ + construction of non-ADT type: {:?}", ty) } } _ => return @@ -648,10 +647,9 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let v = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) | - Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(), - Some(_) | None => return, + let v = match tcx.pat_ty_opt(pat).map(|ty| &ty.sty) { + Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), + _ => return, }; match pat.node { // Foo(a, b, c) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index c82e723525b45..74ad6c602f6cd 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { LvalueTy::Ty { ty } => ty, LvalueTy::Downcast { adt_def, substs, variant_index: _ } => - tcx.mk_enum(adt_def, substs), + tcx.mk_adt(adt_def, substs), } } @@ -75,7 +75,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { } ProjectionElem::Downcast(adt_def1, index) => match self.to_ty(tcx).sty { - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { + assert!(adt_def.is_enum()); assert!(index < adt_def.variants.len()); assert_eq!(adt_def, adt_def1); LvalueTy::Downcast { adt_def: adt_def, @@ -83,7 +84,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { variant_index: index } } _ => { - bug!("cannot downcast non-enum type: `{:?}`", self) + bug!("cannot downcast non-ADT type: `{:?}`", self) } }, ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 0a7d3e6e76d8f..83774f0cf7ead 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -224,7 +224,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => + ty::TyAdt(def, _) => def.is_fundamental(), ty::TyTrait(ref data) => tcx.has_attr(data.principal.def_id(), "fundamental"), @@ -260,9 +260,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> infer_is_local.0 } - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.did.is_local() } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index e5ebe96932d4f..52ddd8ab5dac0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,7 +27,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; use infer::{self, InferCtxt, TypeOrigin}; -use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -151,32 +151,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyBool => Some(0), ty::TyChar => Some(1), ty::TyStr => Some(2), - ty::TyInt(..) | ty::TyUint(..) | - ty::TyInfer(ty::IntVar(..)) => Some(3), + ty::TyInt(..) | ty::TyUint(..) | ty::TyInfer(ty::IntVar(..)) => Some(3), ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4), - ty::TyEnum(..) => Some(5), - ty::TyStruct(..) => Some(6), - ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(7), - ty::TyArray(..) | ty::TySlice(..) => Some(8), - ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(9), - ty::TyTrait(..) => Some(10), - ty::TyClosure(..) => Some(11), - ty::TyTuple(..) => Some(12), - ty::TyProjection(..) => Some(13), - ty::TyParam(..) => Some(14), - ty::TyAnon(..) => Some(15), - ty::TyNever => Some(16), - ty::TyUnion(..) => Some(17), + ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), + ty::TyArray(..) | ty::TySlice(..) => Some(6), + ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7), + ty::TyTrait(..) => Some(8), + ty::TyClosure(..) => Some(9), + ty::TyTuple(..) => Some(10), + ty::TyProjection(..) => Some(11), + ty::TyParam(..) => Some(12), + ty::TyAnon(..) => Some(13), + ty::TyNever => Some(14), + ty::TyAdt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct => Some(15), + AdtKind::Union => Some(16), + AdtKind::Enum => Some(17), + }, ty::TyInfer(..) | ty::TyError => None } } match (type_category(a), type_category(b)) { (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { - (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) | - (&ty::TyUnion(def_a, _), &ty::TyUnion(def_b, _)) | - (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) => - def_a == def_b, + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => def_a == def_b, _ => cat_a == cat_b }, // infer and error can be equated to all types diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3f2bc8cbd13c5..94dba7d12a8c7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1638,7 +1638,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyArray(..), &ty::TySlice(_)) => true, // Struct -> Struct. - (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => { + (&ty::TyAdt(def_id_a, _), &ty::TyAdt(def_id_b, _)) if def_id_a.is_struct() => { def_id_a == def_id_b } @@ -1780,8 +1780,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.last().into_iter().cloned().collect())) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where(ty::Binder(match sized_crit.sty { @@ -1837,8 +1836,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.to_vec())) } - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | - ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { + ty::TyAdt(..) | ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { // Fallback to whatever user-defined impls exist in this case. None } @@ -1930,11 +1928,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // for `PhantomData`, we pass `T` - ty::TyStruct(def, substs) if def.is_phantom_data() => { + ty::TyAdt(def, substs) if def.is_phantom_data() => { substs.types().collect() } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { def.all_fields() .map(|f| f.ty(self.tcx(), substs)) .collect() @@ -2566,7 +2564,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Struct -> Struct. - (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { + (&ty::TyAdt(def, substs_a), &ty::TyAdt(_, substs_b)) => { let fields = def .all_fields() .map(|f| f.unsubst_ty()) @@ -2621,7 +2619,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { k } }); - let new_struct = tcx.mk_struct(def, Substs::new(tcx, params)); + let new_struct = tcx.mk_adt(def, Substs::new(tcx, params)); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c8d282d18af1d..0badb85e9e095 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -65,7 +65,7 @@ impl<'tcx> CastTy<'tcx> { ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), ty::TyFloat(_) => Some(CastTy::Float), - ty::TyEnum(d,_) if d.is_payloadfree() => + ty::TyAdt(d,_) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index e0e8a329e6e1d..b499e1346e73c 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -224,8 +224,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { TypeContents::union(&v.fields, |f| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0fc1641d31f70..20601493d68f3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -27,7 +27,7 @@ use ty::subst::Substs; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants}; -use ty::{AdtDef, ClosureSubsts, Region}; +use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject}; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; @@ -620,7 +620,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn intern_adt_def(self, did: DefId, - kind: ty::AdtKind, + kind: AdtKind, variants: Vec>) -> ty::AdtDefMaster<'gcx> { let def = ty::AdtDefData::new(self, did, kind, variants); @@ -1032,8 +1032,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait, - TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); + TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyTrait, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len()); @@ -1227,9 +1227,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) } - pub fn mk_enum(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_adt(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - self.mk_ty(TyEnum(def, substs)) + self.mk_ty(TyAdt(def, substs)) } pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -1316,16 +1316,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyProjection(inner)) } - pub fn mk_struct(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyStruct(def, substs)) - } - - pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyUnion(def, substs)) - } - pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 0e33e396f7e18..d820fddea3907 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), - ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)), + ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyBox(_) => "box".to_string(), ty::TyArray(_, n) => format!("array of {} elements", n), ty::TySlice(_) => "slice".to_string(), @@ -244,12 +244,6 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTrait(ref inner) => { format!("trait {}", tcx.item_path_str(inner.principal.def_id())) } - ty::TyStruct(def, _) => { - format!("struct `{}`", tcx.item_path_str(def.did)) - } - ty::TyUnion(def, _) => { - format!("union `{}`", tcx.item_path_str(def.did)) - } ty::TyClosure(..) => "closure".to_string(), ty::TyTuple(_) => "tuple".to_string(), ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 84f34a640dd8e..ee1544d2d996d 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -22,15 +22,13 @@ pub enum SimplifiedType { IntSimplifiedType(ast::IntTy), UintSimplifiedType(ast::UintTy), FloatSimplifiedType(ast::FloatTy), - EnumSimplifiedType(DefId), + AdtSimplifiedType(DefId), StrSimplifiedType, VecSimplifiedType, PtrSimplifiedType, NeverSimplifiedType, TupleSimplifiedType(usize), TraitSimplifiedType(DefId), - StructSimplifiedType(DefId), - UnionSimplifiedType(DefId), ClosureSimplifiedType(DefId), AnonSimplifiedType(DefId), FunctionSimplifiedType(usize), @@ -57,19 +55,13 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyInt(int_type) => Some(IntSimplifiedType(int_type)), ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)), ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), - ty::TyEnum(def, _) => Some(EnumSimplifiedType(def.did)), + ty::TyAdt(def, _) => Some(AdtSimplifiedType(def.did)), ty::TyStr => Some(StrSimplifiedType), ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), ty::TyRawPtr(_) => Some(PtrSimplifiedType), ty::TyTrait(ref trait_info) => { Some(TraitSimplifiedType(trait_info.principal.def_id())) } - ty::TyStruct(def, _) => { - Some(StructSimplifiedType(def.did)) - } - ty::TyUnion(def, _) => { - Some(UnionSimplifiedType(def.did)) - } ty::TyRef(_, mt) => { // since we introduce auto-refs during method lookup, we // just treat &T and T as equivalent from the point of @@ -79,7 +71,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyBox(_) => { // treat like we would treat `Box` match tcx.lang_items.require_owned_box() { - Ok(def_id) => Some(StructSimplifiedType(def_id)), + Ok(def_id) => Some(AdtSimplifiedType(def_id)), Err(msg) => tcx.sess.fatal(&msg), } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index ce6e4d6516ec6..cddd59fa83c1b 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -102,7 +102,7 @@ impl FlagComputation { } } - &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => { + &ty::TyAdt(_, substs) => { self.add_substs(substs); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index ddb0a6970cba5..b6b55fc0e33dd 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -262,9 +262,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // impl on `Foo`, but fallback to `::bar` if self-type is // anything other than a simple path. match self_ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { if substs.types().next().is_none() { // ignore regions self.push_item_path(buffer, adt_def.did); } else { @@ -320,9 +318,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// decisions and we may want to adjust it later. pub fn characteristic_def_id_of_type(ty: Ty) -> Option { match ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => Some(adt_def.did), + ty::TyAdt(adt_def, _) => Some(adt_def.did), ty::TyTrait(ref data) => Some(data.principal.def_id()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 276fc708eed1b..3c0aa041d2dd3 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> Struct { } // Is this the NonZero lang item wrapping a pointer or integer type? - (&Univariant { non_zero: true, .. }, &ty::TyStruct(def, substs)) => { + (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); match *fields[0].ty(tcx, substs).layout(infcx)? { @@ -573,7 +573,7 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - (_, &ty::TyStruct(def, substs)) => { + (_, &ty::TyAdt(def, substs)) if def.is_struct() => { Struct::non_zero_field_path(infcx, def.struct_variant().fields .iter().map(|field| { field.ty(tcx, substs) @@ -694,7 +694,7 @@ pub enum Layout { non_zero: bool }, - /// SIMD vectors, from TyStruct marked with #[repr(simd)]. + /// SIMD vectors, from structs marked with #[repr(simd)]. Vector { element: Primitive, count: u64 @@ -715,7 +715,7 @@ pub enum Layout { non_zero: bool }, - // Remaining variants are all ADTs such as TyStruct, TyEnum or TyTuple. + // Remaining variants are all ADTs such as structs, enums or tuples. /// C-like enums; basically an integer. CEnum { @@ -919,240 +919,242 @@ impl<'a, 'gcx, 'tcx> Layout { } // ADTs. - ty::TyStruct(def, substs) => { - if ty.is_simd() { - // SIMD vector types. - let element = ty.simd_type(tcx); - match *element.layout(infcx)? { - Scalar { value, .. } => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } - _ => { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element)); + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + if ty.is_simd() { + // SIMD vector types. + let element = ty.simd_type(tcx); + match *element.layout(infcx)? { + Scalar { value, .. } => { + return success(Vector { + element: value, + count: ty.simd_size(tcx) as u64 + }); + } + _ => { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + ty, element)); + } } } - } - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut st = Struct::new(dl, packed); - st.extend(dl, fields, ty)?; - - Univariant { - variant: st, - non_zero: Some(def.did) == tcx.lang_items.non_zero() - } - } - ty::TyUnion(def, substs) => { - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut un = Union::new(dl, packed); - un.extend(dl, fields, ty)?; - UntaggedUnion { variants: un } - } - ty::TyEnum(def, substs) => { - let hint = *tcx.lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if def.variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - - return success(Univariant { - variant: Struct::new(dl, false), - non_zero: false - }); - } - - if def.variants.iter().all(|v| v.fields.is_empty()) { - // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); - for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; - if x < min { min = x; } - if x > max { max = x; } - } - - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); - return success(CEnum { - discr: discr, - signed: signed, - min: min as u64, - max: max as u64 + let fields = def.struct_variant().fields.iter().map(|field| { + field.ty(tcx, substs).layout(infcx) }); - } + let packed = tcx.lookup_packed(def.did); + let mut st = Struct::new(dl, packed); + st.extend(dl, fields, ty)?; - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { - bug!("non-C-like enum {} with specified discriminants", - tcx.item_path_str(def.did)); + Univariant { + variant: st, + non_zero: Some(def.did) == tcx.lang_items.non_zero() } } - - if def.variants.len() == 1 { - // Equivalent to a struct/tuple/newtype. - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - let fields = def.variants[0].fields.iter().map(|field| { + AdtKind::Union => { + let fields = def.struct_variant().fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }); - let mut st = Struct::new(dl, false); - st.extend(dl, fields, ty)?; - return success(Univariant { variant: st, non_zero: false }); + let packed = tcx.lookup_packed(def.did); + let mut un = Union::new(dl, packed); + un.extend(dl, fields, ty)?; + UntaggedUnion { variants: un } } + AdtKind::Enum => { + let hint = *tcx.lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if def.variants.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false + }); + } - // Cache the substituted and normalized variant field types. - let variants = def.variants.iter().map(|v| { - v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() - }).collect::>(); + if def.variants.iter().all(|v| v.fields.is_empty()) { + // All bodies empty -> intlike + let (mut min, mut max) = (i64::MAX, i64::MIN); + for v in &def.variants { + let x = v.disr_val.to_u64_unchecked() as i64; + if x < min { min = x; } + if x > max { max = x; } + } - if variants.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - for discr in 0..2 { - let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) + let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + return success(CEnum { + discr: discr, + signed: signed, + min: min as u64, + max: max as u64 }); - if !Struct::would_be_zero_sized(dl, other_fields)? { - continue; + } + + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + for (i, v) in def.variants.iter().enumerate() { + if i as u64 != v.disr_val.to_u64_unchecked() { + bug!("non-C-like enum {} with specified discriminants", + tcx.item_path_str(def.did)); } - let path = Struct::non_zero_field_path(infcx, - variants[discr].iter().cloned())?; - let mut path = if let Some(p) = path { p } else { continue }; - - // FIXME(eddyb) should take advantage of a newtype. - if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) + } + + if def.variants.len() == 1 { + // Equivalent to a struct/tuple/newtype. + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + let fields = def.variants[0].fields.iter().map(|field| { + field.ty(tcx, substs).layout(infcx) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, fields, ty)?; + return success(Univariant { variant: st, non_zero: false }); + } + + // Cache the substituted and normalized variant field types. + let variants = def.variants.iter().map(|v| { + v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() + }).collect::>(); + + if variants.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + for discr in 0..2 { + let other_fields = variants[1 - discr].iter().map(|ty| { + ty.layout(infcx) + }); + if !Struct::would_be_zero_sized(dl, other_fields)? { + continue; + } + let path = Struct::non_zero_field_path(infcx, + variants[discr].iter().cloned())?; + let mut path = if let Some(p) = path { p } else { continue }; + + // FIXME(eddyb) should take advantage of a newtype. + if path == &[0] && variants[discr].len() == 1 { + match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => { + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value + }); + } + _ => { + bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) + } } } + + path.push(0); // For GEP through a pointer. + path.reverse(); + let mut st = Struct::new(dl, false); + st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; + return success(StructWrappedNullablePointer { + nndiscr: discr as u64, + nonnull: st, + discrfield: path + }); } + } - path.push(0); // For GEP through a pointer. - path.reverse(); - let mut st = Struct::new(dl, false); - st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; - return success(StructWrappedNullablePointer { - nndiscr: discr as u64, - nonnull: st, - discrfield: path + // The general case. + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + + let mut align = dl.aggregate_align; + let mut size = Size::from_bytes(0); + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256, 256).unwrap(); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); + let mut variants = variants.into_iter().map(|fields| { + let mut found_start = false; + let fields = fields.into_iter().map(|field| { + let field = field.layout(infcx)?; + if !found_start { + // Find the first field we can't move later + // to make room for a larger discriminant. + let field_align = field.align(dl); + if field.size(dl).bytes() != 0 || field_align.abi() != 1 { + start_align = start_align.min(field_align); + found_start = true; + } + } + Ok(field) }); + let mut st = Struct::new(dl, false); + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; + size = cmp::max(size, st.min_size()); + align = align.max(st.align); + Ok(st) + }).collect::, _>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.abi_align(align); + + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutError::SizeOverflow(ty)); } - } - // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); - - let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256, 256).unwrap(); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); - let mut variants = variants.into_iter().map(|fields| { - let mut found_start = false; - let fields = fields.into_iter().map(|field| { - let field = field.layout(infcx)?; - if !found_start { - // Find the first field we can't move later - // to make room for a larger discriminant. - let field_align = field.align(dl); - if field.size(dl).bytes() != 0 || field_align.abi() != 1 { - start_align = start_align.min(field_align); - found_start = true; - } + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + + // Use the initial field alignment + let wanted = start_align.abi(); + let mut ity = min_ity; + for &candidate in &[I16, I32, I64] { + let ty = Int(candidate); + if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { + ity = candidate; + break; } - Ok(field) - }); - let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); - align = align.max(st.align); - Ok(st) - }).collect::, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.abi_align(align); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); - } - - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - - // Use the initial field alignment - let wanted = start_align.abi(); - let mut ity = min_ity; - for &candidate in &[I16, I32, I64] { - let ty = Int(candidate); - if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { - ity = candidate; - break; } - } - // FIXME(eddyb) conservative only to avoid diverging from trans::adt. - if align.abi() != start_align.abi() { - ity = min_ity; - } + // FIXME(eddyb) conservative only to avoid diverging from trans::adt. + if align.abi() != start_align.abi() { + ity = min_ity; + } - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = Int(min_ity).size(dl); - let new_ity_size = Int(ity).size(dl); - for variant in &mut variants { - for offset in &mut variant.offset_after_field { - if *offset > old_ity_size { - break; + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = Int(min_ity).size(dl); + let new_ity_size = Int(ity).size(dl); + for variant in &mut variants { + for offset in &mut variant.offset_after_field { + if *offset > old_ity_size { + break; + } + *offset = new_ity_size; } - *offset = new_ity_size; } } - } - General { - discr: ity, - variants: variants, - size: size, - align: align + General { + discr: ity, + variants: variants, + size: size, + align: align + } } - } + }, // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { @@ -1317,9 +1319,9 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. - if def.variants.is_empty() || def.variants.len() > 2 { + if def.is_union() || def.variants.is_empty() || def.variants.len() > 2 { return Err(err); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dfe24d5627bf1..91e3950745089 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -952,9 +952,7 @@ impl<'tcx> TraitPredicate<'tcx> { self.input_types() .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => + ty::TyAdt(adt_def, _) => Some(adt_def.did), _ => None @@ -1573,18 +1571,49 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) } + #[inline] + pub fn is_struct(&self) -> bool { + !self.is_union() && !self.is_enum() + } + + #[inline] + pub fn is_union(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_UNION) + } + + #[inline] + pub fn is_enum(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_ENUM) + } + /// Returns the kind of the ADT - Struct or Enum. #[inline] pub fn adt_kind(&self) -> AdtKind { - if self.flags.get().intersects(AdtFlags::IS_ENUM) { + if self.is_enum() { AdtKind::Enum - } else if self.flags.get().intersects(AdtFlags::IS_UNION) { + } else if self.is_union() { AdtKind::Union } else { AdtKind::Struct } } + pub fn descr(&self) -> &'static str { + match self.adt_kind() { + AdtKind::Struct => "struct", + AdtKind::Union => "union", + AdtKind::Enum => "enum", + } + } + + pub fn variant_descr(&self) -> &'static str { + match self.adt_kind() { + AdtKind::Struct => "struct", + AdtKind::Union => "union", + AdtKind::Enum => "variant", + } + } + /// Returns whether this is a dtorck type. If this returns /// true, this type being safe for destruction requires it to be /// alive; Otherwise, only the contents are required to be. @@ -1622,8 +1651,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { /// Asserts this is a struct and returns the struct's unique /// variant. pub fn struct_variant(&self) -> &VariantDefData<'gcx, 'container> { - let adt_kind = self.adt_kind(); - assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union); + assert!(!self.is_enum()); &self.variants[0] } @@ -1832,7 +1860,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } } - TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => { + TyAdt(adt, substs) => { // recursive case let adt = tcx.lookup_adt_def_master(adt.did); adt.calculate_sized_constraint_inner(tcx, stack); diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index a7bb0374b75bf..a4edd3b93c949 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -172,9 +172,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyUint(..) | // OutlivesScalar ty::TyFloat(..) | // OutlivesScalar ty::TyNever | // ... - ty::TyEnum(..) | // OutlivesNominalType - ty::TyStruct(..) | // OutlivesNominalType - ty::TyUnion(..) | // OutlivesNominalType + ty::TyAdt(..) | // OutlivesNominalType ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index dfae19487b6f0..b10c731fe27d0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -414,11 +414,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(a) } - (&ty::TyEnum(a_def, a_substs), &ty::TyEnum(b_def, b_substs)) + (&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs)) if a_def == b_def => { let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_enum(a_def, substs)) + Ok(tcx.mk_adt(a_def, substs)) } (&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) => @@ -440,20 +440,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, })) } - (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_struct(a_def, substs)) - } - - (&ty::TyUnion(a_def, a_substs), &ty::TyUnion(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_union(a_def, substs)) - } - (&ty::TyClosure(a_id, a_substs), &ty::TyClosure(b_id, b_substs)) if a_id == b_id => diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 952641f6832f9..6c3dabfe113fe 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -482,7 +482,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)), ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), - ty::TyEnum(tid, substs) => ty::TyEnum(tid, substs.fold_with(folder)), + ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)), ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)), ty::TyFnDef(def_id, substs, f) => { @@ -494,8 +494,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(ref r, tm) => { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } - ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)), - ty::TyUnion(did, substs) => ty::TyUnion(did, substs.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -516,7 +514,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRawPtr(ref tm) => tm.visit_with(visitor), ty::TyArray(typ, _sz) => typ.visit_with(visitor), ty::TySlice(typ) => typ.visit_with(visitor), - ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), + ty::TyAdt(_, substs) => substs.visit_with(visitor), ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), ty::TyTuple(ts) => ts.visit_with(visitor), ty::TyFnDef(_, substs, ref f) => { @@ -524,8 +522,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), - ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), - ty::TyUnion(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7ded2b05f3b5b..a755dd056cd84 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -106,24 +106,13 @@ pub enum TypeVariants<'tcx> { /// A primitive floating-point type. For example, `f64`. TyFloat(ast::FloatTy), - /// An enumerated type, defined with `enum`. + /// Structures, enumerations and unions. /// /// Substs here, possibly against intuition, *may* contain `TyParam`s. /// That is, even after substitution it is possible that there are type - /// variables. This happens when the `TyEnum` corresponds to an enum - /// definition and not a concrete use of it. This is true for `TyStruct` - /// and `TyUnion` as well. - TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A structure type, defined with `struct`. - /// - /// See warning about substitutions for enumerated types. - TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A union type, defined with `union`. - /// - /// See warning about substitutions for enumerated types. - TyUnion(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// variables. This happens when the `TyAdt` corresponds to an ADT + /// definition and not a concrete use of it. + TyAdt(AdtDef<'tcx>, &'tcx Substs<'tcx>), /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly @@ -922,7 +911,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { - TyEnum(def, _) | TyStruct(def, _) | TyUnion(def, _) => def.is_empty(), + TyAdt(def, _) => def.is_empty(), // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested // and they don't break anything. But I'm keeping my changes small for now. @@ -950,7 +939,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } pub fn is_phantom_data(&self) -> bool { - if let TyStruct(def, _) = self.sty { + if let TyAdt(def, _) = self.sty { def.is_phantom_data() } else { false @@ -985,8 +974,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_structural(&self) -> bool { match self.sty { - TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) | - TyArray(..) | TyClosure(..) => true, + TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true, _ => self.is_slice() | self.is_trait() } } @@ -994,7 +982,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { match self.sty { - TyStruct(def, _) => def.is_simd(), + TyAdt(def, _) => def.is_simd(), _ => false } } @@ -1009,7 +997,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn simd_type(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match self.sty { - TyStruct(def, substs) => { + TyAdt(def, substs) => { def.struct_variant().fields[0].ty(tcx, substs) } _ => bug!("simd_type called on invalid type") @@ -1018,7 +1006,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn simd_size(&self, _cx: TyCtxt) -> usize { match self.sty { - TyStruct(def, _) => def.struct_variant().fields.len(), + TyAdt(def, _) => def.struct_variant().fields.len(), _ => bug!("simd_size called on invalid type") } } @@ -1203,9 +1191,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_to_def_id(&self) -> Option { match self.sty { TyTrait(ref tt) => Some(tt.principal.def_id()), - TyStruct(def, _) | - TyUnion(def, _) | - TyEnum(def, _) => Some(def.did), + TyAdt(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None } @@ -1213,7 +1199,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_adt_def(&self) -> Option> { match self.sty { - TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt), + TyAdt(adt, _) => Some(adt), _ => None } } @@ -1231,10 +1217,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { v.extend(obj.principal.skip_binder().substs.regions()); v } - TyEnum(_, substs) | - TyStruct(_, substs) | - TyUnion(_, substs) | - TyAnon(_, substs) => { + TyAdt(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 51ca6bfeb5aff..68de8d96f33dc 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use infer::InferCtxt; use hir::pat_util; use traits::{self, Reveal}; -use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; +use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::{Disr, ParameterEnvironment}; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; @@ -138,28 +138,30 @@ impl<'tcx> ParameterEnvironment<'tcx> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| { let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) | ty::TyUnion(struct_def, substs) => { - for field in struct_def.all_fields() { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingField( - field.name)) - } - } - struct_def - } - ty::TyEnum(enum_def, substs) => { - for variant in &enum_def.variants { - for field in &variant.fields { + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + for field in adt.all_fields() { let field_ty = field.ty(tcx, substs); if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingVariant( - variant.name)) + return Err(CopyImplementationError::InfrigingField( + field.name)) } } + adt } - enum_def - } + AdtKind::Enum => { + for variant in &adt.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingVariant( + variant.name)) + } + } + } + adt + } + }, _ => return Err(CopyImplementationError::NotAnAdt) }; @@ -183,7 +185,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { for field in def.all_fields() { let field_ty = field.ty(self, substs); if let TyError = field_ty.sty { @@ -203,16 +205,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { i: usize, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) | - (&TyUnion(def, substs), None) => { - def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), Some(vid)) => { + adt.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), None) => { - assert!(def.is_univariant()); - def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), None) => { + // Don't use `struct_variant`, this may be a univariant enum. + adt.variants[0].fields.get(i).map(|f| f.ty(self, substs)) } (&TyTuple(ref v), None) => v.get(i).cloned(), _ => None @@ -226,12 +224,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { n: Name, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) | - (&TyUnion(def, substs), None) => { - def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), Some(vid)) => { + adt.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), None) => { + adt.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) } _ => return None } @@ -256,10 +253,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def, substs) = ty.sty { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break + loop { + match ty.sty { + TyAdt(def, substs) if def.is_struct() => { + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break + } + } + _ => break } } ty @@ -275,15 +277,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { - if a_def != b_def { - break; - } - if let Some(f) = a_def.struct_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; + loop { + match (&a.sty, &b.sty) { + (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) + if a_def == b_def && a_def.is_struct() => { + match a_def.struct_variant().fields.last() { + Some(f) => { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); + } + _ => break + } + } + _ => break } } (a, b) @@ -431,9 +437,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { TyInt(i) => self.hash(i), TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), - TyStruct(d, _) | - TyUnion(d, _) | - TyEnum(d, _) => self.def_id(d.did), + TyAdt(d, _) => self.def_id(d.did), TyArray(_, n) => self.hash(n), TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), @@ -560,8 +564,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> { mutbl: hir::MutMutable, .. }) => Some(true), - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) | + TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyAdt(..) | TyAnon(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span)); @@ -601,7 +605,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyStr | TyTrait(..) | TySlice(_) => Some(false), - TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) | + TyAdt(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyAnon(..) | TyError => None }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span)); @@ -663,7 +667,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(tcx, sp, seen, ty) } - TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => { + TyAdt(def, substs) => { find_nonrepresentable(tcx, sp, seen, @@ -680,7 +684,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { match ty.sty { - TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => { + TyAdt(ty_def, _) => { ty_def == def } _ => false @@ -689,9 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyUnion(did_a, ref substs_a), &TyUnion(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + (&TyAdt(did_a, substs_a), &TyAdt(did_b, substs_b)) => { if did_a != did_b { return false; } @@ -713,7 +715,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("is_type_structurally_recursive: {:?}", ty); match ty.sty { - TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => { + TyAdt(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index cea3bd6348dbe..dd3a62f7cd2dd 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -93,10 +93,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { pred.0.ty }).rev()); } - ty::TyEnum(_, ref substs) | - ty::TyStruct(_, ref substs) | - ty::TyUnion(_, ref substs) | - ty::TyAnon(_, ref substs) => { + ty::TyAdt(_, substs) | ty::TyAnon(_, substs) => { stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 599e2be4db247..0557660e98c2f 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -336,9 +336,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.compute_projection(data); } - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) => { // WfNominalType let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d0e02f2e8acdd..3b84ff86ab9fb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::subst::{self, Subst, Substs}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum}; +use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::TyClosure; @@ -868,7 +868,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => { + TyAdt(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && !tcx.tcache.borrow().contains_key(&def.did) { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 6f4c48d632a7a..089733da536d8 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -796,9 +796,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 45f5c3288a6d0..515868c460d07 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -21,7 +21,7 @@ use borrowck::LoanPathElem::{LpDeref, LpInterior}; use borrowck::move_data::InvalidMovePathIndex; use borrowck::move_data::{MoveData, MovePathIndex}; use rustc::hir::def_id::{DefId}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, AdtKind, TyCtxt}; use rustc::middle::mem_categorization as mc; use std::mem; @@ -422,8 +422,8 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, variant_did); }; - match (&parent_ty.sty, enum_variant_info) { - (&ty::TyTuple(ref v), None) => { + match parent_ty.sty { + ty::TyTuple(ref v) => { let tuple_idx = match *origin_field_name { mc::PositionalField(tuple_idx) => tuple_idx, mc::NamedField(_) => @@ -438,69 +438,68 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyStruct(def, _), None) => { - match *origin_field_name { - mc::NamedField(ast_name) => { - for f in &def.struct_variant().fields { - if f.name == ast_name { - continue; + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + match *origin_field_name { + mc::NamedField(ast_name) => { + for f in &def.struct_variant().fields { + if f.name == ast_name { + continue; + } + let field_name = mc::NamedField(f.name); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::NamedField(f.name); - add_fragment_sibling_local(field_name, None); } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in def.struct_variant().fields.iter().enumerate() { - if i == tuple_idx { - continue + mc::PositionalField(tuple_idx) => { + for (i, _f) in def.struct_variant().fields.iter().enumerate() { + if i == tuple_idx { + continue + } + let field_name = mc::PositionalField(i); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); } } } - } - - (&ty::TyUnion(..), None) => { - // Do nothing, all union fields are moved/assigned together. - } - - (&ty::TyEnum(def, _), ref enum_variant_info) => { - let variant = match *enum_variant_info { - Some((vid, ref _lp2)) => def.variant_with_id(vid), - None => { - assert!(def.is_univariant()); - &def.variants[0] - } - }; - match *origin_field_name { - mc::NamedField(ast_name) => { - for field in &variant.fields { - if field.name == ast_name { - continue; + AdtKind::Union => { + // Do nothing, all union fields are moved/assigned together. + } + AdtKind::Enum => { + let variant = match enum_variant_info { + Some((vid, ref _lp2)) => def.variant_with_id(vid), + None => { + assert!(def.is_univariant()); + &def.variants[0] + } + }; + match *origin_field_name { + mc::NamedField(ast_name) => { + for field in &variant.fields { + if field.name == ast_name { + continue; + } + let field_name = mc::NamedField(field.name); + add_fragment_sibling_local(field_name, Some(variant.did)); } - let field_name = mc::NamedField(field.name); - add_fragment_sibling_local(field_name, Some(variant.did)); } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in variant.fields.iter().enumerate() { - if tuple_idx == i { - continue; + mc::PositionalField(tuple_idx) => { + for (i, _f) in variant.fields.iter().enumerate() { + if tuple_idx == i { + continue; + } + let field_name = mc::PositionalField(i); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); } } } - } + }, - ref sty_and_variant_info => { + ref ty => { let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id)); span_bug!(opt_span.unwrap_or(DUMMY_SP), "type {:?} ({:?}) is not fragmentable", - parent_ty, - sty_and_variant_info); + parent_ty, ty); } } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 5f2d6c406c4b9..3e335dacc8ed9 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -178,7 +178,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { if def.has_dtor() { Some(cmt.clone()) } else { diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index bda68a1cd1ceb..3fa7c252b842c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -148,9 +148,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ which implements the `Drop` trait", diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index c08dc9330b8fd..fdcefdc0d4307 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -103,8 +103,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let base_ty = cmt_base.ty; let result = self.restrict(cmt_base); // Borrowing one union field automatically borrows all its fields. - if let ty::TyUnion(ref adt_def, _) = base_ty.sty { - match result { + match base_ty.sty { + ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { for field in &adt_def.struct_variant().fields { @@ -124,9 +124,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { LpInterior(opt_variant_id, interior))); RestrictionResult::SafeIf(lp, base_vec) } - } - } else { - self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) + }, + _ => self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index c5d1034537989..71274b7e0218a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,7 +709,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { self.open_drop_for_adt(c, def, substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -893,7 +893,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { if def.has_dtor() { self.tcx.sess.span_warn( c.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 9c462feeaadd7..e035e268b1c4c 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -261,7 +261,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", lv, ty); true diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 0c9261df54870..e9ba406389f88 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -367,20 +367,22 @@ impl<'a, 'tcx> MoveData<'tcx> { kind: MoveKind) { // Moving one union field automatically moves all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty { - for field in &adt_def.struct_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_move_helper(tcx, sibling_lp, id, kind); + if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + if adt_def.is_union() { + for field in &adt_def.struct_variant().fields { + let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + let field_ty = if field == interior { + lp.ty + } else { + tcx.types.err // Doesn't matter + }; + let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, + LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); + self.add_move_helper(tcx, sibling_lp, id, kind); + } + return; } - return; } } @@ -422,20 +424,23 @@ impl<'a, 'tcx> MoveData<'tcx> { mode: euv::MutateMode) { // Assigning to one union field automatically assigns to all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty { - for field in &adt_def.struct_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_assignment_helper(tcx, sibling_lp, assign_id, span, assignee_id, mode); + if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + if adt_def.is_union() { + for field in &adt_def.struct_variant().fields { + let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + let field_ty = if field == interior { + lp.ty + } else { + tcx.types.err // Doesn't matter + }; + let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, + LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); + self.add_assignment_helper(tcx, sibling_lp, assign_id, + span, assignee_id, mode); + } + return; } - return; } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e49011d887370..da4445ef68947 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -245,21 +245,23 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node { let pat_ty = cx.tcx.pat_ty(p); - if let ty::TyEnum(edef, _) = pat_ty.sty { - if let Def::Local(..) = cx.tcx.expect_def(p.id) { - if edef.variants.iter().any(|variant| { - variant.name == name.node && variant.kind == VariantKind::Unit - }) { - let ty_path = cx.tcx.item_path_str(edef.did); - let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, - "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - name.node, ty_path); - help!(err, - "if you meant to match on a variant, \ - consider making the path in the pattern qualified: `{}::{}`", - ty_path, name.node); - err.emit(); + if let ty::TyAdt(edef, _) = pat_ty.sty { + if edef.is_enum() { + if let Def::Local(..) = cx.tcx.expect_def(p.id) { + if edef.variants.iter().any(|variant| { + variant.name == name.node && variant.kind == VariantKind::Unit + }) { + let ty_path = cx.tcx.item_path_str(edef.did); + let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, + "pattern binding `{}` is named the same as one \ + of the variants of the type `{}`", + name.node, ty_path); + help!(err, + "if you meant to match on a variant, \ + consider making the path in the pattern qualified: `{}::{}`", + ty_path, name.node); + err.emit(); + } } } } @@ -566,7 +568,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pat = match left_ty.sty { ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { + ty::TyAdt(adt, _) => { let v = ctor.variant_for_adt(adt); match v.kind { VariantKind::Struct => { @@ -659,7 +661,8 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), ty::TySlice(_) => (0..max_slice_length+1).map(|length| Slice(length)).collect(), - ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(), + ty::TyAdt(def, _) if def.is_enum() => + def.variants.iter().map(|v| Variant(v.did)).collect(), _ => vec![Single] } } @@ -837,7 +840,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us _ => bug!() }, ty::TyRef(..) => 1, - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { + ty::TyAdt(adt, _) => { ctor.variant_for_adt(adt).fields.len() } ty::TyArray(_, n) => n, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 30e5a0cacf551..4f4c16d3f6a61 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -257,8 +257,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, format!("floating point constants cannot be used in patterns")); } - ty::TyEnum(adt_def, _) | - ty::TyStruct(adt_def, _) => { + ty::TyAdt(adt_def, _) if adt_def.is_union() => { + // Matching on union fields is unsafe, we can't hide it in constants + tcx.sess.span_err(span, "cannot use unions in constant patterns"); + } + ty::TyAdt(adt_def, _) => { if !tcx.has_attr(adt_def.did, "structural_match") { tcx.sess.add_lint( lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, @@ -271,10 +274,6 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_path_str(adt_def.did))); } } - ty::TyUnion(..) => { - // Matching on union fields is unsafe, we can't hide it in constants - tcx.sess.span_err(span, "cannot use unions in constant patterns"); - } _ => { } } let pat = match expr.node { @@ -1039,7 +1038,7 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), - (&ty::TyEnum(ref adt, _), i) => { + (&ty::TyAdt(adt, _), i) if adt.is_enum() => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); infer(i, tcx, &int_ty.to_ty(tcx).sty) @@ -1230,7 +1229,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) }, None => Ok(Integral(Infer(n))), - Some(&ty::TyEnum(ref adt, _)) => { + Some(&ty::TyAdt(adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a73930fa52517..b610a924a3396 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -468,21 +468,21 @@ impl LateLintPass for MissingCopyImplementations { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } hir::ItemUnion(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_union(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_enum(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } _ => return, }; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 54cec3fd7e135..a6049acdb10d4 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -12,7 +12,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{Layout, Primitive}; use rustc::traits::Reveal; use middle::const_val::ConstVal; @@ -431,110 +431,112 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match ty.sty { - ty::TyStruct(def, substs) => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found struct without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found struct without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } - // We can't completely trust repr(C) markings; make sure the - // fields are actually safe. - if def.struct_variant().fields.is_empty() { - return FfiUnsafe( - "found zero-size struct in foreign module, consider \ - adding a member to this struct"); - } + // We can't completely trust repr(C) markings; make sure the + // fields are actually safe. + if def.struct_variant().fields.is_empty() { + return FfiUnsafe( + "found zero-size struct in foreign module, consider \ + adding a member to this struct"); + } - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + } } + FfiSafe } - FfiSafe - } - ty::TyUnion(def, substs) => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found union without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } + AdtKind::Union => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found union without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + } } + FfiSafe } - FfiSafe - } - ty::TyEnum(def, substs) => { - if def.variants.is_empty() { - // Empty enums are okay... although sort of useless. - return FfiSafe - } + AdtKind::Enum => { + if def.variants.is_empty() { + // Empty enums are okay... although sort of useless. + return FfiSafe + } - // Check for a repr() attribute to specify the size of the - // discriminant. - let repr_hints = cx.lookup_repr_hints(def.did); - match &repr_hints[..] { - &[] => { - // Special-case types like `Option`. - if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe( - "found enum without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(...)] attribute to \ - the type") + // Check for a repr() attribute to specify the size of the + // discriminant. + let repr_hints = cx.lookup_repr_hints(def.did); + match &repr_hints[..] { + &[] => { + // Special-case types like `Option`. + if !is_repr_nullable_ptr(cx, def, substs) { + return FfiUnsafe( + "found enum without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(...)] attribute to \ + the type") + } } - } - &[ref hint] => { - if !hint.is_ffi_safe() { + &[ref hint] => { + if !hint.is_ffi_safe() { + // FIXME: This shouldn't be reachable: we should check + // this earlier. + return FfiUnsafe( + "enum has unexpected #[repr(...)] attribute") + } + + // Enum with an explicitly sized discriminant; either + // a C-style enum or a discriminated union. + + // The layout of enum variants is implicitly repr(C). + // FIXME: Is that correct? + } + _ => { // FIXME: This shouldn't be reachable: we should check // this earlier. return FfiUnsafe( - "enum has unexpected #[repr(...)] attribute") + "enum has too many #[repr(...)] attributes"); } - - // Enum with an explicitly sized discriminant; either - // a C-style enum or a discriminated union. - - // The layout of enum variants is implicitly repr(C). - // FIXME: Is that correct? - } - _ => { - // FIXME: This shouldn't be reachable: we should check - // this earlier. - return FfiUnsafe( - "enum has too many #[repr(...)] attributes"); } - } - // Check the contained variants. - for variant in &def.variants { - for field in &variant.fields { - let arg = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, arg); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + // Check the contained variants. + for variant in &def.variants { + for field in &variant.fields { + let arg = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, arg); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + } } } + FfiSafe } - FfiSafe - } + }, ty::TyChar => { FfiUnsafe("found Rust type `char` in foreign module, while \ diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f07720f5202bd..d31f16df69356 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -136,9 +136,7 @@ impl LateLintPass for UnusedResults { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyNever => return, ty::TyBool => return, - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { let attrs = cx.tcx.get_attrs(def.did); check_must_use(cx, &attrs[..], s.span) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6b48b4dfabcfd..4dc06f0d02496 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -36,7 +36,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; use middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind}; use rustc_const_math::ConstInt; @@ -453,23 +453,19 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, let mut ctor_did = None; let (kind, variants) = match item_family(doc) { Enum => { - (ty::AdtKind::Enum, - get_enum_variants(cdata, doc)) + (AdtKind::Enum, get_enum_variants(cdata, doc)) } Struct(..) => { // Use separate constructor id for unit/tuple structs and reuse did for braced structs. ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| { translated_def_id(cdata, ctor_doc) }); - (ty::AdtKind::Struct, - vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) + (AdtKind::Struct, vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) } Union => { - (ty::AdtKind::Union, - vec![get_struct_variant(cdata, doc, did)]) + (AdtKind::Union, vec![get_struct_variant(cdata, doc, did)]) } - _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", - item_family(doc), did) + _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", item_family(doc), did) }; let adt = tcx.intern_adt_def(did, kind, variants); @@ -481,8 +477,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, // this needs to be done *after* the variant is interned, // to support recursive structures for variant in &adt.variants { - if variant.kind == ty::VariantKind::Tuple && - adt.adt_kind() == ty::AdtKind::Enum { + if variant.kind == ty::VariantKind::Tuple && adt.is_enum() { // tuple-like enum variant fields aren't real items - get the types // from the ctor. debug!("evaluating the ctor-type of {:?}", diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 55ff4817683de..bcaf1640bc41b 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -358,14 +358,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } 'c' => return tcx.types.char, - 't' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return tcx.mk_enum(def, substs); - } 'x' => { assert_eq!(self.next(), '['); let trait_ref = ty::Binder(self.parse_existential_trait_ref()); @@ -470,15 +462,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_struct(def, substs); - } - 'U' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_union(def, substs); + return self.tcx.mk_adt(def, substs); } 'k' => { assert_eq!(self.next(), '['); diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index bef3cf3a1940f..8030abf6330e7 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -97,11 +97,6 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ast::FloatTy::F64 => write!(w, "MF"), }; } - ty::TyEnum(def, substs) => { - write!(w, "t[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } ty::TyTrait(ref obj) => { write!(w, "x["); enc_existential_trait_ref(w, cx, obj.principal.0); @@ -165,16 +160,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyParam(p) => { write!(w, "p[{}|{}]", p.idx, p.name); } - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) => { write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } - ty::TyUnion(def, substs) => { - write!(w, "U[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } ty::TyClosure(def, substs) => { write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, substs.func_substs); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6ea1fb5036065..a40571c5d8597 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above - let is_union = adt_def.adt_kind() == ty::AdtKind::Union; + let is_union = adt_def.is_union(); let active_field_index = if is_union { Some(fields[0].name.index()) } else { None }; // first process the set of fields that were provided diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8812287c34294..4518f8cb373fa 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -19,7 +19,7 @@ use rustc::hir::def::Def; use rustc::middle::const_val::ConstVal; use rustc_const_eval as const_eval; use rustc::middle::region::CodeExtent; -use rustc::ty::{self, VariantDef, Ty}; +use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::mir::repr::*; use rustc::hir; @@ -459,48 +459,50 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprStruct(_, ref fields, ref base) => { match expr_ty.sty { - ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => { - let field_refs = field_refs(&adt.variants[0], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: 0, - substs: substs, - fields: field_refs, - base: base.as_ref().map(|base| { - FruInfo { - base: base.to_ref(), - field_types: cx.tcx.tables - .borrow() - .fru_field_types[&expr.id] - .clone() - } - }) + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + let field_refs = field_refs(&adt.variants[0], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: 0, + substs: substs, + fields: field_refs, + base: base.as_ref().map(|base| { + FruInfo { + base: base.to_ref(), + field_types: cx.tcx.tables + .borrow() + .fru_field_types[&expr.id] + .clone() + } + }) + } } - } - ty::TyEnum(adt, substs) => { - match cx.tcx.expect_def(expr.id) { - Def::Variant(enum_id, variant_id) => { - debug_assert!(adt.did == enum_id); - assert!(base.is_none()); - - let index = adt.variant_index_with_id(variant_id); - let field_refs = field_refs(&adt.variants[index], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: index, - substs: substs, - fields: field_refs, - base: None + AdtKind::Enum => { + match cx.tcx.expect_def(expr.id) { + Def::Variant(enum_id, variant_id) => { + debug_assert!(adt.did == enum_id); + assert!(base.is_none()); + + let index = adt.variant_index_with_id(variant_id); + let field_refs = field_refs(&adt.variants[index], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: index, + substs: substs, + fields: field_refs, + base: None + } + } + ref def => { + span_bug!( + expr.span, + "unexpected def: {:?}", + def); } - } - ref def => { - span_bug!( - expr.span, - "unexpected def: {:?}", - def); } } - } + }, _ => { span_bug!( expr.span, @@ -579,13 +581,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { let index = match cx.tcx.expr_ty_adjusted(source).sty { - ty::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) => + ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => - span_bug!( - expr.span, - "field of non-struct: {:?}", - ty), + span_bug!(expr.span, "field of non-ADT: {:?}", ty), }; let index = index.unwrap_or_else(|| { span_bug!( @@ -680,7 +679,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::TyFnDef(..) => def_id, // A unit struct which is used as a value. We return a completely different ExprKind // here to account for this special case. - ty::TyStruct(adt_def, substs) => return ExprKind::Adt { + ty::TyAdt(adt_def, substs) => return ExprKind::Adt { adt_def: adt_def, variant_index: 0, substs: substs, @@ -694,7 +693,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // expression. ty::TyFnDef(..) => variant_id, // A unit variant, similar special case to the struct case above. - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { debug_assert!(adt_def.did == enum_id); let index = adt_def.variant_index_with_id(variant_id); return ExprKind::Adt { diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 30f79796aaa6d..3639b165eb5ab 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -198,8 +198,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::TupleStruct(_, ref subpatterns, ddpos) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, - _ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"), + ty::TyAdt(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), }; let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); @@ -217,13 +217,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Struct(_, ref fields, _) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => adt_def, + ty::TyAdt(adt_def, _) => adt_def, _ => { span_bug!( pat.span, - "struct pattern not applied to struct or enum"); + "struct pattern not applied to an ADT"); } }; let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index e260b1d262aed..7fda658185e07 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -218,7 +218,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { - ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => { + ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { if index >= adt_def.variants.len() { LvalueTy::Ty { ty: span_mirbug_and_err!( @@ -281,10 +281,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { (&adt_def.variants[variant_index], substs) } LvalueTy::Ty { ty } => match ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) - if adt_def.is_univariant() => { + ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -364,7 +361,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::SetDiscriminant{ ref lvalue, variant_index } => { let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx); let adt = match lvalue_type.sty { - TypeVariants::TyEnum(adt, _) => adt, + TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt, _ => { span_bug!(stmt.source_info.span, "bad set discriminant ({:?} = {:?}): lhs is not an enum", @@ -444,9 +441,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::Switch { ref discr, adt_def, ref targets } => { let discr_ty = discr.ty(mir, tcx).to_ty(tcx); match discr_ty.sty { - ty::TyEnum(def, _) - if def == adt_def && adt_def.variants.len() == targets.len() - => {}, + ty::TyAdt(def, _) if def.is_enum() && + def == adt_def && + adt_def.variants.len() == targets.len() + => {}, _ => { span_mirbug!(self, term, "bad Switch ({:?} on {:?})", adt_def, discr_ty); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index d4e8eb51cde27..f919e42b6bd7d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -439,9 +439,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { /// instead of producing errors. fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { v.add_qualif(ConstQualif::NEEDS_DROP); } _ => {} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 8c72933c4ce46..4012c1cb34889 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -384,11 +384,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { - if def.adt_kind() != ty::AdtKind::Enum && - !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { - let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" }; + if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", - field.name, kind_descr, self.tcx.item_path_str(def.did)) + field.name, def.variant_descr(), self.tcx.item_path_str(def.did)) .span_label(span, &format!("field `{}` is private", field.name)) .emit(); } @@ -438,7 +436,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { // (i.e. `all_fields - fields`), just check them all, // unless the ADT is a union, then unmentioned fields // are not checked. - if adt.adt_kind() == ty::AdtKind::Union { + if adt.is_union() { for expr_field in expr_fields { self.check_field(expr.span, adt, variant.field_named(expr_field.name.node)); } @@ -511,7 +509,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { - ty::TyStruct(def, _) => { + // enum fields have no privacy at this time + ty::TyAdt(def, _) if !def.is_enum() => { let expected_len = def.struct_variant().fields.len(); for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) { if let PatKind::Wild = field.node { @@ -520,9 +519,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.check_field(field.span, def, &def.struct_variant().fields[i]); } } - ty::TyEnum(..) => { - // enum fields have no privacy at this time - } _ => {} } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index ebd0bdc71d7f0..27ee5765c99fa 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1338,7 +1338,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> }; let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { - ty::TyStruct(def, _) => { + ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); if !self.span.filter_generated(sub_span, ex.span) { self.dumper.variable_ref(VariableRefData { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 04cd72ac2d364..868e3bb1f1b73 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -420,7 +420,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } }; match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); @@ -432,14 +432,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })); } _ => { - debug!("Expected struct type, found {:?}", ty); + debug!("Expected struct or union type, found {:?}", ty); None } } } ast::ExprKind::Struct(ref path, ..) => { match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); Some(Data::TypeRefData(TypeRefData { @@ -450,9 +450,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } _ => { - // FIXME ty could legitimately be a TyEnum, but then we will fail + // FIXME ty could legitimately be an enum, but then we will fail // later if we try to look up the fields. - debug!("expected TyStruct, found {:?}", ty); + debug!("expected struct or union, found {:?}", ty); None } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 9eeefa079fb63..e8498363e45a3 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -49,7 +49,7 @@ use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use syntax::ast; use syntax::attr; use syntax::attr::IntType; @@ -179,172 +179,174 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elems) => { Univariant(mk_struct(cx, &elems[..], false, t)) } - ty::TyStruct(def, substs) => { - let ftys = def.struct_variant().fields.iter().map(|field| { - monomorphize::field_ty(cx.tcx(), substs, field) - }).collect::>(); - let packed = cx.tcx().lookup_packed(def.did); - - Univariant(mk_struct(cx, &ftys[..], packed, t)) - } - ty::TyUnion(def, substs) => { - let ftys = def.struct_variant().fields.iter().map(|field| { - monomorphize::field_ty(cx.tcx(), substs, field) - }).collect::>(); - let packed = cx.tcx().lookup_packed(def.did); - UntaggedUnion(mk_union(cx, &ftys[..], packed, t)) - } ty::TyClosure(_, ref substs) => { Univariant(mk_struct(cx, &substs.upvar_tys, false, t)) } - ty::TyEnum(def, substs) => { - let cases = get_cases(cx.tcx(), def, substs); - let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if cases.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - return Univariant(mk_struct(cx, &[], false, t)); + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + let ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) + }).collect::>(); + let packed = cx.tcx().lookup_packed(def.did); + + Univariant(mk_struct(cx, &ftys[..], packed, t)) } - - if cases.iter().all(|c| c.tys.is_empty()) { - // All bodies empty -> intlike - let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); - let bounds = IntBounds { - ulo: discrs.iter().min().unwrap().0, - uhi: discrs.iter().max().unwrap().0, - slo: discrs.iter().map(|n| n.0 as i64).min().unwrap(), - shi: discrs.iter().map(|n| n.0 as i64).max().unwrap() - }; - return mk_cenum(cx, hint, &bounds); + AdtKind::Union => { + let ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) + }).collect::>(); + let packed = cx.tcx().lookup_packed(def.did); + UntaggedUnion(mk_union(cx, &ftys[..], packed, t)) } + AdtKind::Enum => { + let cases = get_cases(cx.tcx(), def, substs); + let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if cases.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + return Univariant(mk_struct(cx, &[], false, t)); + } - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - if !cases.iter().enumerate().all(|(i,c)| c.discr == Disr::from(i)) { - bug!("non-C-like enum {} with specified discriminants", - cx.tcx().item_path_str(def.did)); - } + if cases.iter().all(|c| c.tys.is_empty()) { + // All bodies empty -> intlike + let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); + let bounds = IntBounds { + ulo: discrs.iter().min().unwrap().0, + uhi: discrs.iter().max().unwrap().0, + slo: discrs.iter().map(|n| n.0 as i64).min().unwrap(), + shi: discrs.iter().map(|n| n.0 as i64).max().unwrap() + }; + return mk_cenum(cx, hint, &bounds); + } - if cases.len() == 1 && hint == attr::ReprAny { - // Equivalent to a struct/tuple/newtype. - return Univariant(mk_struct(cx, &cases[0].tys, false, t)); - } + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + if !cases.iter().enumerate().all(|(i,c)| c.discr == Disr::from(i)) { + bug!("non-C-like enum {} with specified discriminants", + cx.tcx().item_path_str(def.did)); + } - if cases.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - let mut discr = 0; - while discr < 2 { - if cases[1 - discr].is_zerolen(cx, t) { - let st = mk_struct(cx, &cases[discr].tys, - false, t); - match cases[discr].find_ptr(cx) { - Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { - return RawNullablePointer { - nndiscr: Disr::from(discr), - nnty: st.fields[0], - nullfields: cases[1 - discr].tys.clone() - }; - } - Some(mut discrfield) => { - discrfield.push(0); - discrfield.reverse(); - return StructWrappedNullablePointer { - nndiscr: Disr::from(discr), - nonnull: st, - discrfield: discrfield, - nullfields: cases[1 - discr].tys.clone() - }; + if cases.len() == 1 && hint == attr::ReprAny { + // Equivalent to a struct/tuple/newtype. + return Univariant(mk_struct(cx, &cases[0].tys, false, t)); + } + + if cases.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + let mut discr = 0; + while discr < 2 { + if cases[1 - discr].is_zerolen(cx, t) { + let st = mk_struct(cx, &cases[discr].tys, + false, t); + match cases[discr].find_ptr(cx) { + Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { + return RawNullablePointer { + nndiscr: Disr::from(discr), + nnty: st.fields[0], + nullfields: cases[1 - discr].tys.clone() + }; + } + Some(mut discrfield) => { + discrfield.push(0); + discrfield.reverse(); + return StructWrappedNullablePointer { + nndiscr: Disr::from(discr), + nonnull: st, + discrfield: discrfield, + nullfields: cases[1 - discr].tys.clone() + }; + } + None => {} } - None => {} } + discr += 1; } - discr += 1; } - } - // The general case. - assert!((cases.len() - 1) as i64 >= 0); - let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64, - slo: 0, shi: (cases.len() - 1) as i64 }; - let min_ity = range_to_inttype(cx, hint, &bounds); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let fields : Vec<_> = cases.iter().map(|c| { - let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); - ftys.extend_from_slice(&c.tys); - mk_struct(cx, &ftys, false, t) - }).collect(); - - - // Check to see if we should use a different type for the - // discriminant. If the overall alignment of the type is - // the same as the first field in each variant, we can safely use - // an alignment-sized type. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - // This check is needed to avoid increasing the size of types when - // the alignment of the first field is smaller than the overall - // alignment of the type. - let (_, align) = union_size_and_align(&fields); - let mut use_align = true; - for st in &fields { - // Get the first non-zero-sized field - let field = st.fields.iter().skip(1).filter(|ty| { - let t = type_of::sizing_type_of(cx, **ty); - machine::llsize_of_real(cx, t) != 0 || - // This case is only relevant for zero-sized types with large alignment - machine::llalign_of_min(cx, t) != 1 - }).next(); - - if let Some(field) = field { - let field_align = type_of::align_of(cx, *field); - if field_align != align { - use_align = false; - break; + // The general case. + assert!((cases.len() - 1) as i64 >= 0); + let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64, + slo: 0, shi: (cases.len() - 1) as i64 }; + let min_ity = range_to_inttype(cx, hint, &bounds); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let fields : Vec<_> = cases.iter().map(|c| { + let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); + ftys.extend_from_slice(&c.tys); + mk_struct(cx, &ftys, false, t) + }).collect(); + + + // Check to see if we should use a different type for the + // discriminant. If the overall alignment of the type is + // the same as the first field in each variant, we can safely use + // an alignment-sized type. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + // This check is needed to avoid increasing the size of types when + // the alignment of the first field is smaller than the overall + // alignment of the type. + let (_, align) = union_size_and_align(&fields); + let mut use_align = true; + for st in &fields { + // Get the first non-zero-sized field + let field = st.fields.iter().skip(1).filter(|ty| { + let t = type_of::sizing_type_of(cx, **ty); + machine::llsize_of_real(cx, t) != 0 || + // This case is only relevant for zero-sized types with large alignment + machine::llalign_of_min(cx, t) != 1 + }).next(); + + if let Some(field) = field { + let field_align = type_of::align_of(cx, *field); + if field_align != align { + use_align = false; + break; + } } } - } - // If the alignment is smaller than the chosen discriminant size, don't use the - // alignment as the final size. - let min_ty = ll_inttype(&cx, min_ity); - let min_size = machine::llsize_of_real(cx, min_ty); - if (align as u64) < min_size { - use_align = false; - } - - let ity = if use_align { - // Use the overall alignment - match align { - 1 => attr::UnsignedInt(ast::UintTy::U8), - 2 => attr::UnsignedInt(ast::UintTy::U16), - 4 => attr::UnsignedInt(ast::UintTy::U32), - 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => - attr::UnsignedInt(ast::UintTy::U64), - _ => min_ity // use min_ity as a fallback + // If the alignment is smaller than the chosen discriminant size, don't use the + // alignment as the final size. + let min_ty = ll_inttype(&cx, min_ity); + let min_size = machine::llsize_of_real(cx, min_ty); + if (align as u64) < min_size { + use_align = false; } - } else { - min_ity - }; - let fields : Vec<_> = cases.iter().map(|c| { - let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); - ftys.extend_from_slice(&c.tys); - mk_struct(cx, &ftys[..], false, t) - }).collect(); + let ity = if use_align { + // Use the overall alignment + match align { + 1 => attr::UnsignedInt(ast::UintTy::U8), + 2 => attr::UnsignedInt(ast::UintTy::U16), + 4 => attr::UnsignedInt(ast::UintTy::U32), + 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => + attr::UnsignedInt(ast::UintTy::U64), + _ => min_ity // use min_ity as a fallback + } + } else { + min_ity + }; - ensure_enum_fits_in_address_space(cx, &fields[..], t); + let fields : Vec<_> = cases.iter().map(|c| { + let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); + ftys.extend_from_slice(&c.tys); + mk_struct(cx, &ftys[..], false, t) + }).collect(); - General(ity, fields) - } + ensure_enum_fits_in_address_space(cx, &fields[..], t); + + General(ity, fields) + } + }, _ => bug!("adt::represent_type called on non-ADT type: {}", t) } } @@ -376,7 +378,7 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFnPtr(_) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? - ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { + ty::TyAdt(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { let nonzero_fields = &def.struct_variant().fields; assert_eq!(nonzero_fields.len(), 1); let field_ty = monomorphize::field_ty(tcx, substs, &nonzero_fields[0]); @@ -395,7 +397,7 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { for (j, field) in def.struct_variant().fields.iter().enumerate() { let field_ty = monomorphize::field_ty(tcx, substs, field); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ec8ab33c4ca54..a6581ae605b56 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -467,8 +467,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } // This can be extended to enums and tuples in the future. - // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) | - (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) => { + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { assert_eq!(def_a, def_b); let src_repr = adt::represent_type(bcx.ccx(), src_ty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 704fac5ce7e53..5a8ab62a2aa2d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -743,9 +743,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // If the type implements Drop, also add a translation item for the // monomorphized Drop::drop() implementation. let destructor_did = match ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) => def.destructor(), + ty::TyAdt(def, _) => def.destructor(), _ => None }; @@ -798,9 +796,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyTrait(_) => { /* nothing to do */ } - ty::TyStruct(ref adt_def, substs) | - ty::TyUnion(ref adt_def, substs) | - ty::TyEnum(ref adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { for field in adt_def.all_fields() { let field_type = monomorphize::apply_param_substs(scx, substs, @@ -989,8 +985,8 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } - (&ty::TyStruct(source_adt_def, source_substs), - &ty::TyStruct(target_adt_def, target_substs)) => { + (&ty::TyAdt(source_adt_def, source_substs), + &ty::TyAdt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); let kind = custom_coerce_unsize_info(scx, source_ty, target_ty); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index bd98eee8869b1..e0de04d150ca7 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -88,8 +88,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - return false; } match ty.sty { - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | - ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { + ty::TyAdt(..) | ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { let llty = sizing_type_of(ccx, ty); llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type()) } @@ -101,7 +100,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<[Ty<'tcx>; 2]> { match ty.sty { - ty::TyEnum(adt, substs) | ty::TyStruct(adt, substs) => { + ty::TyAdt(adt, substs) => { assert_eq!(adt.variants.len(), 1); let fields = &adt.variants[0].fields; if fields.len() != 2 { @@ -205,7 +204,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> { -> Self { match ty.sty { - ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => { + ty::TyAdt(adt, substs) => { let variant = match opt_def { None => adt.struct_variant(), Some(def) => adt.variant_of_def(def) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 2422b9f30069b..b10129d1019ae 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -223,13 +223,9 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { let def_ids: Vec = key.walk() .filter_map(|t| match t.sty { - ty::TyStruct(adt_def, _) | - ty::TyEnum(adt_def, _) => - Some(adt_def.did), - ty::TyProjection(ref proj) => - Some(proj.trait_ref.def_id), - _ => - None + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, }) .collect(); DepNode::TraitSelect(def_ids) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 1bf1023dcd895..31df49609cb8b 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -30,7 +30,7 @@ use rustc::hir; use {type_of, adt, machine, monomorphize}; use common::CrateContext; use type_::Type; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, AdtKind, Ty}; use session::config; use util::nodemap::FnvHashMap; use util::common::path2cstr; @@ -176,18 +176,10 @@ impl<'tcx> TypeMap<'tcx> { ty::TyFloat(_) => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, - ty::TyEnum(def, substs) => { - unique_type_id.push_str("enum "); + ty::TyAdt(def, substs) => { + unique_type_id.push_str(&(String::from(def.descr()) + " ")); from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, - ty::TyStruct(def, substs) => { - unique_type_id.push_str("struct "); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, - ty::TyUnion(def, substs) => { - unique_type_id.push_str("union "); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, + } ty::TyTuple(component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, @@ -705,13 +697,6 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::TyEnum(def, _) => { - prepare_enum_metadata(cx, - t, - def.did, - unique_type_id, - usage_site_span).finalize(cx) - } ty::TyArray(typ, len) => { fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span) } @@ -779,18 +764,27 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } - ty::TyStruct(..) => { - prepare_struct_metadata(cx, + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + prepare_struct_metadata(cx, + t, + unique_type_id, + usage_site_span).finalize(cx) + } + AdtKind::Union => { + prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx) - } - ty::TyUnion(..) => { - prepare_union_metadata(cx, - t, - unique_type_id, - usage_site_span).finalize(cx) - } + } + AdtKind::Enum => { + prepare_enum_metadata(cx, + t, + def.did, + unique_type_id, + usage_site_span).finalize(cx) + } + }, ty::TyTuple(ref elements) => { prepare_tuple_metadata(cx, t, @@ -1134,8 +1128,8 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type); let (struct_def_id, variant, substs) = match struct_type.sty { - ty::TyStruct(def, substs) => (def.did, def.struct_variant(), substs), - _ => bug!("prepare_struct_metadata on a non-struct") + ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs), + _ => bug!("prepare_struct_metadata on a non-ADT") }; let (containing_scope, _) = get_namespace_and_span_for_item(cx, struct_def_id); @@ -1250,8 +1244,8 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let union_llvm_type = type_of::in_memory_type_of(cx, union_type); let (union_def_id, variant, substs) = match union_type.sty { - ty::TyUnion(def, substs) => (def.did, def.struct_variant(), substs), - _ => bug!("prepare_union_metadata on a non-union") + ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs), + _ => bug!("prepare_union_metadata on a non-ADT") }; let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 20a33498475a2..bcd288671bc19 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -421,7 +421,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => { + ty::TyAdt(..) => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } _ => None diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 8291f84054d0c..7f021bee37199 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -44,9 +44,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); }, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 34c92f334d0ac..6c1c5ac2d10e8 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -19,7 +19,7 @@ use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; use rustc::ty::subst::{Substs}; use rustc::traits; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use adt; use base::*; use build::*; @@ -338,7 +338,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, return (C_undef(llty), C_undef(llty)); } match t.sty { - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) => { let ccx = bcx.ccx(); // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized, @@ -487,16 +487,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK DebugLoc::None); bcx } - ty::TyStruct(def, _) | ty::TyEnum(def, _) - if def.dtor_kind().is_present() && !skip_dtor => { - trans_custom_dtor(bcx, t, v0, false) + ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => { + trans_custom_dtor(bcx, t, v0, def.is_union()) } - ty::TyUnion(def, _) => { - if def.dtor_kind().is_present() && !skip_dtor { - trans_custom_dtor(bcx, t, v0, true) - } else { - bcx - } + ty::TyAdt(def, ..) if def.is_union() => { + bcx } _ => { if bcx.fcx.type_needs_drop(t) { @@ -544,23 +539,6 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let mut cx = cx; match t.sty { - ty::TyStruct(..) => { - let repr = adt::represent_type(cx.ccx(), t); - let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); - for (i, &Field(_, field_ty)) in fields.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); - - let val = if type_is_sized(cx.tcx(), field_ty) { - llfld_a - } else { - let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); - Store(cx, llfld_a, get_dataptr(cx, scratch)); - Store(cx, value.meta, get_meta(cx, scratch)); - scratch - }; - cx = drop_ty(cx, val, field_ty, DebugLoc::None); - } - } ty::TyClosure(_, ref substs) => { let repr = adt::represent_type(cx.ccx(), t); for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { @@ -587,63 +565,86 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, cx = drop_ty(cx, llfld_a, *arg, DebugLoc::None); } } - ty::TyEnum(en, substs) => { - let fcx = cx.fcx; - let ccx = fcx.ccx; - - let repr = adt::represent_type(ccx, t); - let n_variants = en.variants.len(); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - - match adt::trans_switch(cx, &repr, av, false) { - (adt::BranchKind::Single, None) => { - if n_variants != 0 { - assert!(n_variants == 1); - cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), - &en.variants[0], substs); - } + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct => { + let repr = adt::represent_type(cx.ccx(), t); + let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); + for (i, &Field(_, field_ty)) in fields.iter().enumerate() { + let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); + + let val = if type_is_sized(cx.tcx(), field_ty) { + llfld_a + } else { + let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, get_dataptr(cx, scratch)); + Store(cx, value.meta, get_meta(cx, scratch)); + scratch + }; + cx = drop_ty(cx, val, field_ty, DebugLoc::None); } - (adt::BranchKind::Switch, Some(lldiscrim_a)) => { - cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); - - // Create a fall-through basic block for the "else" case of - // the switch instruction we're about to generate. Note that - // we do **not** use an Unreachable instruction here, even - // though most of the time this basic block will never be hit. - // - // When an enum is dropped it's contents are currently - // overwritten to DTOR_DONE, which means the discriminant - // could have changed value to something not within the actual - // range of the discriminant. Currently this function is only - // used for drop glue so in this case we just return quickly - // from the outer function, and any other use case will only - // call this for an already-valid enum in which case the `ret - // void` will never be hit. - let ret_void_cx = fcx.new_block("enum-iter-ret-void"); - RetVoid(ret_void_cx, DebugLoc::None); - let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); - let next_cx = fcx.new_block("enum-iter-next"); - - for variant in &en.variants { - let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", - &variant.disr_val - .to_string())); - let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); - AddCase(llswitch, case_val, variant_cx.llbb); - let variant_cx = iter_variant(variant_cx, - &repr, - value, - variant, - substs); - Br(variant_cx, next_cx.llbb, DebugLoc::None); + } + AdtKind::Union => { + bug!("Union in `glue::drop_structural_ty`"); + } + AdtKind::Enum => { + let fcx = cx.fcx; + let ccx = fcx.ccx; + + let repr = adt::represent_type(ccx, t); + let n_variants = adt.variants.len(); + + // NB: we must hit the discriminant first so that structural + // comparison know not to proceed when the discriminants differ. + + match adt::trans_switch(cx, &repr, av, false) { + (adt::BranchKind::Single, None) => { + if n_variants != 0 { + assert!(n_variants == 1); + cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), + &adt.variants[0], substs); + } } - cx = next_cx; + (adt::BranchKind::Switch, Some(lldiscrim_a)) => { + cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); + + // Create a fall-through basic block for the "else" case of + // the switch instruction we're about to generate. Note that + // we do **not** use an Unreachable instruction here, even + // though most of the time this basic block will never be hit. + // + // When an enum is dropped it's contents are currently + // overwritten to DTOR_DONE, which means the discriminant + // could have changed value to something not within the actual + // range of the discriminant. Currently this function is only + // used for drop glue so in this case we just return quickly + // from the outer function, and any other use case will only + // call this for an already-valid enum in which case the `ret + // void` will never be hit. + let ret_void_cx = fcx.new_block("enum-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); + let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); + let next_cx = fcx.new_block("enum-iter-next"); + + for variant in &adt.variants { + let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", + &variant.disr_val + .to_string())); + let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); + AddCase(llswitch, case_val, variant_cx.llbb); + let variant_cx = iter_variant(variant_cx, + &repr, + value, + variant, + substs); + Br(variant_cx, next_cx.llbb, DebugLoc::None); + } + cx = next_cx; + } + _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), } - _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), } - } + }, + _ => { cx.sess().unimpl(&format!("type in drop_structural_ty: {}", t)) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index c0ff6c508bf3e..2049696ee4f71 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -408,7 +408,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "discriminant_value") => { let val_ty = substs.type_at(0); match val_ty.sty { - ty::TyEnum(..) => { + ty::TyAdt(adt, ..) if adt.is_enum() => { let repr = adt::represent_type(ccx, val_ty); adt::trans_get_discr(bcx, &repr, llargs[0], Some(llret_ty), true) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index e078d46274d3e..44e613c4c2b04 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -396,9 +396,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { push_item_name(tcx, adt_def.did, output); push_type_params(tcx, substs, &[], output); }, diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b5565109306b4..3873c24a9f676 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -89,7 +89,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::nil(cx) } - ty::TyStruct(..) if t.is_simd() => { + ty::TyAdt(..) if t.is_simd() => { let e = t.simd_type(cx.tcx()); if !e.is_machine() { cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ @@ -102,8 +102,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::vector(&llet, n) } - ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) | - ty::TyEnum(..) | ty::TyClosure(..) => { + ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => { let repr = adt::represent_type(cx, t); adt::sizing_type_of(cx, &repr, false) } @@ -294,7 +293,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); adt::type_of(cx, &repr) } - ty::TyStruct(..) if t.is_simd() => { + ty::TyAdt(..) if t.is_simd() => { let e = t.simd_type(cx.tcx()); if !e.is_machine() { cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ @@ -306,9 +305,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } - ty::TyStruct(def, ref substs) | - ty::TyUnion(def, ref substs) | - ty::TyEnum(def, ref substs) => { + ty::TyAdt(def, substs) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This // avoids creating more than one copy of the enum when one @@ -331,8 +328,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..) - if !t.is_simd() => { + ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &repr, &mut llty); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 17fb683391982..dd3ac6ff2d457 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -617,7 +617,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { let substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyAdt(_, substs) => substs, ref ty => bug!("unexpected pattern type {:?}", ty), }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { @@ -657,9 +657,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { - ty::TyEnum(_, substs) => (substs, "variant"), - ty::TyStruct(_, substs) => (substs, "struct"), - ty::TyUnion(_, substs) => (substs, "union"), + ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), _ => span_bug!(span, "struct pattern is not an ADT") }; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 0c9da86563ab2..51a9b18392dcf 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal.def_id())), - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { None => None, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 88add66b7dcb0..cc958fb3b2343 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -16,7 +16,7 @@ use middle::free_region::FreeRegionMap; use rustc::infer; use middle::region; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; use util::nodemap::FnvHashSet; @@ -44,9 +44,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty; let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { - ty::TyEnum(adt_def, self_to_impl_substs) | - ty::TyUnion(adt_def, self_to_impl_substs) | - ty::TyStruct(adt_def, self_to_impl_substs) => { + ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, drop_impl_did, dtor_self_type, @@ -301,13 +299,13 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( TypeContext::ADT { def_id, variant, field } => { let adt = tcx.lookup_adt_def(def_id); let variant_name = match adt.adt_kind() { - ty::AdtKind::Enum => format!("enum {} variant {}", - tcx.item_path_str(def_id), - variant), - ty::AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)), - ty::AdtKind::Union => format!("union {}", - tcx.item_path_str(def_id)), + AdtKind::Enum => format!("enum {} variant {}", + tcx.item_path_str(def_id), + variant), + AdtKind::Struct => format!("struct {}", + tcx.item_path_str(def_id)), + AdtKind::Union => format!("union {}", + tcx.item_path_str(def_id)), }; span_note!( &mut err, @@ -435,14 +433,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) if def.is_phantom_data() => { + ty::TyAdt(def, substs) if def.is_phantom_data() => { // PhantomData - behaves identically to T let ity = substs.type_at(0); iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let did = def.did; for variant in &def.variants { for field in variant.fields.iter() { @@ -497,7 +495,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.is_dtorck(tcx) } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 058049992dc00..81e95c91e7ff9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -292,9 +292,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_inherent_candidates_from_object(self_ty, data.principal); self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } ty::TyBox(_) => { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e4ea9bb407d96..3692d6fbf73d6 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -165,7 +165,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(expr) = rcvr_expr { for (ty, _) in self.autoderef(span, rcvr_ty) { match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) if !def.is_enum() => { if let Some(field) = def.struct_variant(). find_field_named(item_name) { let snippet = tcx.sess.codemap().span_to_snippet(expr.span); @@ -359,9 +359,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_expr: Option<&hir::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { - def.did.is_local() - } + ty::TyAdt(def, _) => def.did.is_local(), ty::TyTrait(ref tr) => tr.principal.def_id().is_local(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b059c2ab9f3a8..005cd2e46b89f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1200,7 +1200,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { let t = tcx.node_id_to_type(id); match t.sty { - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); @@ -2911,7 +2911,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { match base_t.sty { - ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => { + ty::TyAdt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); @@ -2957,7 +2957,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { field.node, actual) }, expr_t); match expr_t.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { if let Some(suggested_field_name) = Self::suggest_field_name(def.struct_variant(), field, vec![]) { err.span_help(field.span, @@ -3009,7 +3009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { let field = match base_t.sty { - ty::TyStruct(base_def, substs) => { + ty::TyAdt(base_def, substs) if base_def.is_struct() => { tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple; if !tuple_like { continue } @@ -3074,14 +3074,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { kind_name: &str) { let mut err = self.type_error_struct_with_diag( field.name.span, - |actual| if let ty::TyEnum(..) = ty.sty { - struct_span_err!(self.tcx.sess, field.name.span, E0559, - "{} `{}::{}` has no field named `{}`", - kind_name, actual, variant.name.as_str(), field.name.node) - } else { - struct_span_err!(self.tcx.sess, field.name.span, E0560, - "{} `{}` has no field named `{}`", - kind_name, actual, field.name.node) + |actual| match ty.sty { + ty::TyAdt(adt, ..) if adt.is_enum() => { + struct_span_err!(self.tcx.sess, field.name.span, E0559, + "{} `{}::{}` has no field named `{}`", + kind_name, actual, variant.name.as_str(), field.name.node) + } + _ => { + struct_span_err!(self.tcx.sess, field.name.span, E0560, + "{} `{}` has no field named `{}`", + kind_name, actual, field.name.node) + } }, ty); // prevent all specified fields from being suggested @@ -3102,9 +3105,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { check_completeness: bool) { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { - ty::TyEnum(_, substs) => (substs, "variant"), - ty::TyStruct(_, substs) => (substs, "struct"), - ty::TyUnion(_, substs) => (substs, "union"), + ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3199,8 +3200,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Def::TyAlias(did) => { match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) { - Some(&ty::TyStruct(adt, _)) | - Some(&ty::TyUnion(adt, _)) => Some((did, adt.struct_variant())), + Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => { + Some((did, adt.struct_variant())) + } _ => None, } } @@ -3246,7 +3248,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, struct_ty); match struct_ty.sty { - ty::TyStruct(adt, substs) => { + ty::TyAdt(adt, substs) if adt.is_struct() => { self.tables.borrow_mut().fru_field_types.insert( expr.id, adt.struct_variant().fields.iter().map(|f| { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d2b7f07b9ce6c..046ba5fb4523c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -22,9 +22,9 @@ use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; -use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; +use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyStruct, TyUnion, TyTrait, TyNever, TyTuple}; +use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; @@ -69,9 +69,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Returns the def ID of the base type, if there is one. fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { match ty.sty { - TyEnum(def, _) | - TyStruct(def, _) | - TyUnion(def, _) => { + TyAdt(def, _) => { Some(def.did) } @@ -241,9 +239,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { - ty::TyEnum(type_def, _) | - ty::TyStruct(type_def, _) | - ty::TyUnion(type_def, _) => { + ty::TyAdt(type_def, _) => { type_def.set_destructor(method_def_id.def_id()); } _ => { @@ -426,7 +422,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } - (&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => { + (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) + if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { let source_path = tcx.item_path_str(def_a.did); let target_path = tcx.item_path_str(def_b.did); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index cb424eb48e932..d1eb0f995de13 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -75,9 +75,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { self.tcx.map.node_to_string(item.id)); let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { @@ -294,14 +292,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { - ty::TyStruct(self_def, _) | - ty::TyUnion(self_def, _) | - ty::TyEnum(self_def, _) => - Some(self_def.did), - ty::TyBox(..) => - self.tcx.lang_items.owned_box(), - _ => - None + ty::TyAdt(self_def, _) => Some(self_def.did), + ty::TyBox(..) => self.tcx.lang_items.owned_box(), + _ => None, }; let msg = match opt_self_def_id { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fcc0b09e31acf..082690149c9d1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -67,7 +67,7 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; use rustc::ty::util::IntTypeExt; use rscope::*; @@ -1062,7 +1062,7 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None }; let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, ConstInt::Infer(0), def)]; - let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants); + let adt = ccx.tcx.intern_adt_def(did, AdtKind::Struct, variants); if let Some(ctor_id) = ctor_id { // Make adt definition available through constructor id as well. ccx.tcx.insert_adt_def(ctor_id, adt); @@ -1077,7 +1077,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { let did = ccx.tcx.map.local_def_id(it.id); let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; - ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants) + ccx.tcx.intern_adt_def(did, AdtKind::Union, variants) } fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) @@ -1157,7 +1157,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let did = tcx.map.local_def_id(v.node.data.id()); convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); - tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants) + tcx.intern_adt_def(tcx.map.local_def_id(it.id), AdtKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id @@ -1581,17 +1581,17 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ItemEnum(ref ei, ref generics) => { let def = convert_enum_def(ccx, item, ei); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_enum(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemStruct(ref si, ref generics) => { let def = convert_struct_def(ccx, item, si); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_struct(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemUnion(ref un, ref generics) => { let def = convert_union_def(ccx, item, un); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_union(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemDefaultImpl(..) | ItemTrait(..) | diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1e38f464651b9..b18792d894287 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -344,9 +344,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) => { let item_type = self.tcx().lookup_item_type(def.did); // This edge is actually implied by the call to diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 18c12f98fb428..f1b907e70d74e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -238,7 +238,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let t = tcx.lookup_item_type(did); let predicates = tcx.lookup_predicates(did); match t.ty.sty { - ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => { + ty::TyAdt(edef, _) if edef.is_enum() && !tcx.sess.cstore.is_typedef(did) => { return clean::EnumItem(clean::Enum { generics: (t.generics, &predicates).clean(cx), variants_stripped: false, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 79c66be5e57d7..b9dc75cdd9f12 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; -use rustc::ty; +use rustc::ty::{self, AdtKind}; use rustc::middle::stability; use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; @@ -1811,14 +1811,12 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let did = def.did; - let kind = match self.sty { - ty::TyStruct(..) => TypeStruct, - ty::TyUnion(..) => TypeUnion, - _ => TypeEnum, + let kind = match def.adt_kind() { + AdtKind::Struct => TypeStruct, + AdtKind::Union => TypeUnion, + AdtKind::Enum => TypeEnum, }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, &cx.tcx().item_name(did).as_str(), diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs index 4cb846b51868f..ca1027b11adce 100644 --- a/src/test/run-pass/auxiliary/issue13507.rs +++ b/src/test/run-pass/auxiliary/issue13507.rs @@ -75,13 +75,13 @@ pub mod testtypes { fn foo_method(&self) -> usize; } - // Tests TyStruct + // Tests struct pub struct FooStruct { pub pub_foo_field: usize, foo_field: usize } - // Tests TyEnum + // Tests enum pub enum FooEnum { VarA(usize), VarB(usize, usize) From 553d5f0a38a1ce79e78e7216b493e95b63d29563 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Sep 2016 01:26:02 +0300 Subject: [PATCH 637/768] Address comments --- src/librustc/ty/layout.rs | 404 ++++++++++++++++++-------------------- src/librustc/ty/util.rs | 35 ++-- 2 files changed, 210 insertions(+), 229 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3c0aa041d2dd3..e3f3da916a0a9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> Struct { } // Is this the NonZero lang item wrapping a pointer or integer type? - (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { + (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); match *fields[0].ty(tcx, substs).layout(infcx)? { @@ -918,243 +918,229 @@ impl<'a, 'gcx, 'tcx> Layout { Univariant { variant: st, non_zero: false } } - // ADTs. - ty::TyAdt(def, substs) => match def.adt_kind() { - AdtKind::Struct => { - if ty.is_simd() { - // SIMD vector types. - let element = ty.simd_type(tcx); - match *element.layout(infcx)? { - Scalar { value, .. } => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } - _ => { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element)); - } - } + // SIMD vector types. + ty::TyAdt(def, ..) if def.is_simd() => { + let element = ty.simd_type(tcx); + match *element.layout(infcx)? { + Scalar { value, .. } => { + return success(Vector { + element: value, + count: ty.simd_size(tcx) as u64 + }); } - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) + _ => { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + ty, element)); + } + } + } + + // ADTs. + ty::TyAdt(def, substs) => { + let hint = *tcx.lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if def.variants.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false }); - let packed = tcx.lookup_packed(def.did); - let mut st = Struct::new(dl, packed); - st.extend(dl, fields, ty)?; + } - Univariant { - variant: st, - non_zero: Some(def.did) == tcx.lang_items.non_zero() + if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { + // All bodies empty -> intlike + let (mut min, mut max) = (i64::MAX, i64::MIN); + for v in &def.variants { + let x = v.disr_val.to_u64_unchecked() as i64; + if x < min { min = x; } + if x > max { max = x; } } + + let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + return success(CEnum { + discr: discr, + signed: signed, + min: min as u64, + max: max as u64 + }); } - AdtKind::Union => { - let fields = def.struct_variant().fields.iter().map(|field| { + + if def.variants.len() == 1 { + // Struct, or union, or univariant enum equivalent to a struct. + // (Typechecking will reject discriminant-sizing attrs.) + assert!(!def.is_enum() || hint == attr::ReprAny); + let fields = def.variants[0].fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }); let packed = tcx.lookup_packed(def.did); - let mut un = Union::new(dl, packed); - un.extend(dl, fields, ty)?; - UntaggedUnion { variants: un } + let layout = if def.is_union() { + let mut un = Union::new(dl, packed); + un.extend(dl, fields, ty)?; + UntaggedUnion { variants: un } + } else { + let mut st = Struct::new(dl, packed); + st.extend(dl, fields, ty)?; + let non_zero = Some(def.did) == tcx.lang_items.non_zero(); + Univariant { variant: st, non_zero: non_zero } + }; + return success(layout); } - AdtKind::Enum => { - let hint = *tcx.lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if def.variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - - return success(Univariant { - variant: Struct::new(dl, false), - non_zero: false - }); - } - - if def.variants.iter().all(|v| v.fields.is_empty()) { - // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); - for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; - if x < min { min = x; } - if x > max { max = x; } - } - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); - return success(CEnum { - discr: discr, - signed: signed, - min: min as u64, - max: max as u64 - }); + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + for (i, v) in def.variants.iter().enumerate() { + if i as u64 != v.disr_val.to_u64_unchecked() { + bug!("non-C-like enum {} with specified discriminants", + tcx.item_path_str(def.did)); } + } - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { - bug!("non-C-like enum {} with specified discriminants", - tcx.item_path_str(def.did)); - } - } + // Cache the substituted and normalized variant field types. + let variants = def.variants.iter().map(|v| { + v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() + }).collect::>(); - if def.variants.len() == 1 { - // Equivalent to a struct/tuple/newtype. - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - let fields = def.variants[0].fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) + if variants.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + for discr in 0..2 { + let other_fields = variants[1 - discr].iter().map(|ty| { + ty.layout(infcx) }); - let mut st = Struct::new(dl, false); - st.extend(dl, fields, ty)?; - return success(Univariant { variant: st, non_zero: false }); - } - - // Cache the substituted and normalized variant field types. - let variants = def.variants.iter().map(|v| { - v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() - }).collect::>(); - - if variants.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - for discr in 0..2 { - let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) - }); - if !Struct::would_be_zero_sized(dl, other_fields)? { - continue; - } - let path = Struct::non_zero_field_path(infcx, - variants[discr].iter().cloned())?; - let mut path = if let Some(p) = path { p } else { continue }; - - // FIXME(eddyb) should take advantage of a newtype. - if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) - } + if !Struct::would_be_zero_sized(dl, other_fields)? { + continue; + } + let path = Struct::non_zero_field_path(infcx, + variants[discr].iter().cloned())?; + let mut path = if let Some(p) = path { p } else { continue }; + + // FIXME(eddyb) should take advantage of a newtype. + if path == &[0] && variants[discr].len() == 1 { + match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => { + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value + }); + } + _ => { + bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) } } - - path.push(0); // For GEP through a pointer. - path.reverse(); - let mut st = Struct::new(dl, false); - st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; - return success(StructWrappedNullablePointer { - nndiscr: discr as u64, - nonnull: st, - discrfield: path - }); } - } - // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); - - let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256, 256).unwrap(); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); - let mut variants = variants.into_iter().map(|fields| { - let mut found_start = false; - let fields = fields.into_iter().map(|field| { - let field = field.layout(infcx)?; - if !found_start { - // Find the first field we can't move later - // to make room for a larger discriminant. - let field_align = field.align(dl); - if field.size(dl).bytes() != 0 || field_align.abi() != 1 { - start_align = start_align.min(field_align); - found_start = true; - } - } - Ok(field) - }); + path.push(0); // For GEP through a pointer. + path.reverse(); let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); - align = align.max(st.align); - Ok(st) - }).collect::, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.abi_align(align); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); + st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; + return success(StructWrappedNullablePointer { + nndiscr: discr as u64, + nonnull: st, + discrfield: path + }); } + } - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - - // Use the initial field alignment - let wanted = start_align.abi(); - let mut ity = min_ity; - for &candidate in &[I16, I32, I64] { - let ty = Int(candidate); - if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { - ity = candidate; - break; + // The general case. + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + + let mut align = dl.aggregate_align; + let mut size = Size::from_bytes(0); + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256, 256).unwrap(); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); + let mut variants = variants.into_iter().map(|fields| { + let mut found_start = false; + let fields = fields.into_iter().map(|field| { + let field = field.layout(infcx)?; + if !found_start { + // Find the first field we can't move later + // to make room for a larger discriminant. + let field_align = field.align(dl); + if field.size(dl).bytes() != 0 || field_align.abi() != 1 { + start_align = start_align.min(field_align); + found_start = true; + } } - } + Ok(field) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; + size = cmp::max(size, st.min_size()); + align = align.max(st.align); + Ok(st) + }).collect::, _>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.abi_align(align); + + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutError::SizeOverflow(ty)); + } - // FIXME(eddyb) conservative only to avoid diverging from trans::adt. - if align.abi() != start_align.abi() { - ity = min_ity; + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + + // Use the initial field alignment + let wanted = start_align.abi(); + let mut ity = min_ity; + for &candidate in &[I16, I32, I64] { + let ty = Int(candidate); + if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { + ity = candidate; + break; } + } - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = Int(min_ity).size(dl); - let new_ity_size = Int(ity).size(dl); - for variant in &mut variants { - for offset in &mut variant.offset_after_field { - if *offset > old_ity_size { - break; - } - *offset = new_ity_size; + // FIXME(eddyb) conservative only to avoid diverging from trans::adt. + if align.abi() != start_align.abi() { + ity = min_ity; + } + + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = Int(min_ity).size(dl); + let new_ity_size = Int(ity).size(dl); + for variant in &mut variants { + for offset in &mut variant.offset_after_field { + if *offset > old_ity_size { + break; } + *offset = new_ity_size; } } + } - General { - discr: ity, - variants: variants, - size: size, - align: align - } + General { + discr: ity, + variants: variants, + size: size, + align: align } - }, + } // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 68de8d96f33dc..6b3ebaa895fa3 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -253,15 +253,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - loop { - match ty.sty { - TyAdt(def, substs) if def.is_struct() => { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break - } - } - _ => break + while let TyAdt(def, substs) = ty.sty { + if !def.is_struct() { + break + } + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break } } ty @@ -277,17 +275,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - loop { - match (&a.sty, &b.sty) { - (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) - if a_def == b_def && a_def.is_struct() => { - match a_def.struct_variant().fields.last() { - Some(f) => { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } - _ => break - } + while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def || !a_def.is_struct() { + break + } + match a_def.struct_variant().fields.last() { + Some(f) => { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); } _ => break } From 76a2f9f4542ccb15d6eb2426b162ce91094f04e2 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 22:59:21 +0200 Subject: [PATCH 638/768] fix feature error, test fallout --- src/librustc_typeck/rscope.rs | 18 +++++++++--------- src/test/compile-fail/const-unsized.rs | 2 -- src/test/compile-fail/issue-24446.rs | 1 - 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index be44dce8a8aca..131ecfc6e0c78 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -229,17 +229,9 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { fn anon_regions(&self, - _span: Span, + span: Span, count: usize) -> Result, Option>> { - Ok(vec![ty::ReStatic; count]) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess @@ -248,6 +240,14 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> `static_in_const` feature, see #35897") .emit(); } + Ok(vec![ty::ReStatic; count]) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { ty::ReStatic } } diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index d3c0bf0021350..a73164b957c83 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,7 +15,6 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -28,7 +27,6 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index bcc1d3c3e42d9..acd50bcf9e112 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,6 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - //~| ERROR: this needs a `'static` lifetime or the `static_in_const` feature 0 }; } From aadbcffb7c59718834c63c20ab7ce6276aef430c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 639/768] Issue deprecation warnings for safe accesses to extern statics --- src/doc/book/ffi.md | 2 +- src/libpanic_unwind/seh.rs | 4 +- src/librustc/lint/builtin.rs | 9 ++++- src/librustc/middle/effect.rs | 40 ++++++++++++++----- src/librustc_lint/lib.rs | 4 ++ .../compile-fail/auxiliary/extern-statics.rs | 14 +++++++ src/test/compile-fail/linkage2.rs | 2 +- src/test/compile-fail/linkage3.rs | 2 +- .../compile-fail/safe-extern-statics-mut.rs | 28 +++++++++++++ src/test/compile-fail/safe-extern-statics.rs | 32 +++++++++++++++ .../check-static-recursion-foreign.rs | 2 +- 11 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/extern-statics.rs create mode 100644 src/test/compile-fail/safe-extern-statics-mut.rs create mode 100644 src/test/compile-fail/safe-extern-statics.rs diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 1dea15311ce82..8709c3f4b7b10 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -471,7 +471,7 @@ extern { fn main() { println!("You have readline version {} installed.", - rl_readline_version as i32); + unsafe { rl_readline_version as i32 }); } ``` diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index dd6e92fe9ae19..5896421493008 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -232,13 +232,13 @@ extern "C" { // Again, I'm not entirely sure what this is describing, it just seems to work. #[cfg_attr(not(test), lang = "msvc_try_filter")] static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor { - pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _, + pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, spare: 0 as *mut _, name: imp::NAME1, }; static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor { - pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _, + pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, spare: 0 as *mut _, name: imp::NAME2, }; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index ed94e5fe377c4..fa77c911b4651 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -192,6 +192,12 @@ declare_lint! { "lifetimes or labels named `'_` were erroneously allowed" } +declare_lint! { + pub SAFE_EXTERN_STATICS, + Warn, + "safe access to extern statics was erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -228,7 +234,8 @@ impl LintPass for HardwiredLints { RENAMED_AND_REMOVED_LINTS, SUPER_OR_SELF_IN_GLOBAL_PATH, HR_LIFETIME_IN_ASSOC_TYPE, - LIFETIME_UNDERSCORE + LIFETIME_UNDERSCORE, + SAFE_EXTERN_STATICS ) } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index a7af0b50b8494..082db569e18c6 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -15,6 +15,7 @@ use self::RootUnsafeContext::*; use dep_graph::DepNode; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; +use lint; use syntax::ast; use syntax_pos::Span; @@ -57,16 +58,25 @@ struct EffectCheckVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { - fn require_unsafe(&mut self, span: Span, description: &str) { + fn require_unsafe_ext(&mut self, node_id: ast::NodeId, span: Span, + description: &str, is_lint: bool) { if self.unsafe_context.push_unsafe_count > 0 { return; } match self.unsafe_context.root { SafeContext => { - // Report an error. - struct_span_err!( - self.tcx.sess, span, E0133, - "{} requires unsafe function or block", description) - .span_label(span, &description) - .emit(); + if is_lint { + self.tcx.sess.add_lint(lint::builtin::SAFE_EXTERN_STATICS, + node_id, + span, + format!("{} requires unsafe function or \ + block (error E0133)", description)); + } else { + // Report an error. + struct_span_err!( + self.tcx.sess, span, E0133, + "{} requires unsafe function or block", description) + .span_label(span, &description) + .emit(); + } } UnsafeBlock(block_id) => { // OK, but record this. @@ -76,6 +86,10 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { UnsafeFn => {} } } + + fn require_unsafe(&mut self, span: Span, description: &str) { + self.require_unsafe_ext(ast::DUMMY_NODE_ID, span, description, false) + } } impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { @@ -173,8 +187,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { self.require_unsafe(expr.span, "use of inline assembly"); } hir::ExprPath(..) => { - if let Def::Static(_, true) = self.tcx.expect_def(expr.id) { - self.require_unsafe(expr.span, "use of mutable static"); + if let Def::Static(def_id, mutbl) = self.tcx.expect_def(expr.id) { + if mutbl { + self.require_unsafe(expr.span, "use of mutable static"); + } else if match self.tcx.map.get_if_local(def_id) { + Some(hir::map::NodeForeignItem(..)) => true, + Some(..) => false, + None => self.tcx.sess.cstore.is_foreign_item(def_id), + } { + self.require_unsafe_ext(expr.id, expr.span, "use of extern static", true); + } } } hir::ExprField(ref base_expr, field) => { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index b9817cc6ff45a..bc2979c806f65 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -201,6 +201,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(LIFETIME_UNDERSCORE), reference: "RFC 1177 ", }, + FutureIncompatibleInfo { + id: LintId::of(SAFE_EXTERN_STATICS), + reference: "issue 36247 ", + }, ]); // Register renamed and removed lints diff --git a/src/test/compile-fail/auxiliary/extern-statics.rs b/src/test/compile-fail/auxiliary/extern-statics.rs new file mode 100644 index 0000000000000..07f70b177b3b5 --- /dev/null +++ b/src/test/compile-fail/auxiliary/extern-statics.rs @@ -0,0 +1,14 @@ +// 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. + +extern { + pub static XA: u8; + pub static mut XB: u8; +} diff --git a/src/test/compile-fail/linkage2.rs b/src/test/compile-fail/linkage2.rs index 2a127d937eaaa..afae4a451d699 100644 --- a/src/test/compile-fail/linkage2.rs +++ b/src/test/compile-fail/linkage2.rs @@ -16,5 +16,5 @@ extern { } fn main() { - println!("{}", foo); + println!("{}", unsafe { foo }); } diff --git a/src/test/compile-fail/linkage3.rs b/src/test/compile-fail/linkage3.rs index 8343f718902dc..c222989ed6677 100644 --- a/src/test/compile-fail/linkage3.rs +++ b/src/test/compile-fail/linkage3.rs @@ -16,5 +16,5 @@ extern { } fn main() { - println!("{:?}", foo); + println!("{:?}", unsafe { foo }); } diff --git a/src/test/compile-fail/safe-extern-statics-mut.rs b/src/test/compile-fail/safe-extern-statics-mut.rs new file mode 100644 index 0000000000000..b5f3b4535df92 --- /dev/null +++ b/src/test/compile-fail/safe-extern-statics-mut.rs @@ -0,0 +1,28 @@ +// 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. + +// aux-build:extern-statics.rs + +#![allow(unused)] +#![deny(safe_extern_statics)] + +extern crate extern_statics; +use extern_statics::*; + +extern { + static mut B: u8; +} + +fn main() { + let b = B; //~ ERROR use of mutable static requires unsafe function or block + let rb = &B; //~ ERROR use of mutable static requires unsafe function or block + let xb = XB; //~ ERROR use of mutable static requires unsafe function or block + let xrb = &XB; //~ ERROR use of mutable static requires unsafe function or block +} diff --git a/src/test/compile-fail/safe-extern-statics.rs b/src/test/compile-fail/safe-extern-statics.rs new file mode 100644 index 0000000000000..7e96897ee882b --- /dev/null +++ b/src/test/compile-fail/safe-extern-statics.rs @@ -0,0 +1,32 @@ +// 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. + +// aux-build:extern-statics.rs + +#![allow(unused)] +#![deny(safe_extern_statics)] + +extern crate extern_statics; +use extern_statics::*; + +extern { + static A: u8; +} + +fn main() { + let a = A; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler + let ra = &A; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler + let xa = XA; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler + let xra = &XA; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler +} diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs index 554853ade5be6..8e718f328ff91 100644 --- a/src/test/run-pass/check-static-recursion-foreign.rs +++ b/src/test/run-pass/check-static-recursion-foreign.rs @@ -27,6 +27,6 @@ extern "C" { static test_static: c_int; } -static B: &'static c_int = &test_static; +static B: &'static c_int = unsafe { &test_static }; pub fn main() {} From 765700ba7a3743b9af5cb12092ea1293dbe07068 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 8 Sep 2016 23:48:08 +0200 Subject: [PATCH 640/768] Work around pointer aliasing issue in Vec::extend_from_slice, extend_with_element Due to missing noalias annotations for &mut T in general (issue #31681), in larger programs extend_from_slice and extend_with_element may both compile very poorly. What is observed is that the .set_len() calls are not lifted out of the loop, even for `Vec`. Use a local length variable for the Vec length instead, and use a scope guard to write this value back to self.len when the scope ends or on panic. Then the alias analysis is easy. This affects extend_from_slice, extend_with_element, the vec![x; n] macro, Write impls for Vec, BufWriter, etc (but may / may not have triggered since inlining can be enough for the compiler to get it right). --- src/libcollections/vec.rs | 68 +++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 876314613f523..7388e88343432 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1046,21 +1046,27 @@ impl Vec { self.reserve(n); unsafe { - let len = self.len(); - let mut ptr = self.as_mut_ptr().offset(len as isize); + let mut ptr = self.as_mut_ptr().offset(self.len() as isize); + // Use SetLenOnDrop to work around bug where compiler + // may not realize the store through `ptr` trough self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); + // Write all elements except the last one - for i in 1..n { + for _ in 1..n { ptr::write(ptr, value.clone()); ptr = ptr.offset(1); // Increment the length in every step in case clone() panics - self.set_len(len + i); + local_len.increment_len(1); } if n > 0 { // We can write the last element directly without cloning needlessly ptr::write(ptr, value); - self.set_len(len + n); + local_len.increment_len(1); } + + // len set by scope guard } } @@ -1085,20 +1091,56 @@ impl Vec { pub fn extend_from_slice(&mut self, other: &[T]) { self.reserve(other.len()); - for i in 0..other.len() { + // Unsafe code so this can be optimised to a memcpy (or something + // similarly fast) when T is Copy. LLVM is easily confused, so any + // extra operations during the loop can prevent this optimisation. + unsafe { let len = self.len(); - - // Unsafe code so this can be optimised to a memcpy (or something - // similarly fast) when T is Copy. LLVM is easily confused, so any - // extra operations during the loop can prevent this optimisation. - unsafe { - ptr::write(self.get_unchecked_mut(len), other.get_unchecked(i).clone()); - self.set_len(len + 1); + let ptr = self.get_unchecked_mut(len) as *mut T; + // Use SetLenOnDrop to work around bug where compiler + // may not realize the store through `ptr` trough self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); + + for i in 0..other.len() { + ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone()); + local_len.increment_len(1); } + + // len set by scope guard } } } +// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +// +// The idea is: The length field in SetLenOnDrop is a local variable +// that the optimizer will see does not alias with any stores through the Vec's data +// pointer. This is a workaround for alias analysis issue #32155 +struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline] + fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { local_len: *len, len: len } + } + + #[inline] + fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } +} + +impl<'a> Drop for SetLenOnDrop<'a> { + #[inline] + fn drop(&mut self) { + *self.len = self.local_len; + } +} + impl Vec { /// Removes consecutive repeated elements in the vector. /// From 8154a6bc69b42813ffda91adcefd9f277338acf3 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 14 Aug 2016 18:01:25 +0100 Subject: [PATCH 641/768] rustdoc: Don't add extra newlines for fully opaque structs Changes the definition for opaque structs to look like `pub struct Vec { /* fields omitted */ }` to save space on the page. Also only use one line for empty braced structs. --- src/librustdoc/html/render.rs | 21 +++++++++++++++------ src/test/rustdoc/structfields.rs | 10 ++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2be6177ea344e..d01a5e312a3a2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2509,19 +2509,28 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, if let Some(g) = g { write!(w, "{}", WhereClause(g))? } - write!(w, " {{\n{}", tab)?; + let mut has_visible_fields = false; + write!(w, " {{")?; for field in fields { if let clean::StructFieldItem(ref ty) = field.inner { - write!(w, " {}{}: {},\n{}", + write!(w, "\n{} {}{}: {},", + tab, VisSpace(&field.visibility), field.name.as_ref().unwrap(), - *ty, - tab)?; + *ty)?; + has_visible_fields = true; } } - if it.has_stripped_fields().unwrap() { - write!(w, " // some fields omitted\n{}", tab)?; + if has_visible_fields { + if it.has_stripped_fields().unwrap() { + write!(w, "\n{} // some fields omitted", tab)?; + } + write!(w, "\n{}", tab)?; + } else if it.has_stripped_fields().unwrap() { + // If there are no visible fields we can just display + // `{ /* fields omitted */ }` to save space. + write!(w, " /* fields omitted */ ")?; } write!(w, "}}")?; } diff --git a/src/test/rustdoc/structfields.rs b/src/test/rustdoc/structfields.rs index c0bfe3ffe3cf9..75d9be856d74c 100644 --- a/src/test/rustdoc/structfields.rs +++ b/src/test/rustdoc/structfields.rs @@ -48,3 +48,13 @@ pub enum Qux { // @has - //pre "// some fields omitted" }, } + +// @has structfields/struct.Baz.html //pre "pub struct Baz { /* fields omitted */ }" +pub struct Baz { + x: u8, + #[doc(hidden)] + pub y: u8, +} + +// @has structfields/struct.Quux.html //pre "pub struct Quux {}" +pub struct Quux {} From 89bc13c37d0fc58b583f07a5902f62e598c69b0e Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Thu, 8 Sep 2016 17:51:06 -0700 Subject: [PATCH 642/768] tweaking the nodejs cmd sanity check --- src/bootstrap/sanity.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c345893954f46..e5e66f1035d17 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -77,8 +77,8 @@ pub fn check(build: &mut Build) { // If a manual nodejs was added to the config, // of if a nodejs install is detected through config, use it. - if build.config.nodejs.is_some() { - need_cmd("nodejs".as_ref()) + if let Some(ref s) = build.config.nodejs { + need_cmd(s.as_ref()); } // We're gonna build some custom C code here and there, host triples From 93cdce4cf36bbc3419d586b8cbab17885b449d5f Mon Sep 17 00:00:00 2001 From: Liigo Date: Tue, 6 Sep 2016 15:59:16 +0800 Subject: [PATCH 643/768] rustdoc: don't collapse `docblock-short` --- src/librustdoc/html/render.rs | 2 +- src/librustdoc/html/static/rustdoc.css | 8 ++++---- src/test/rustdoc/issue-32374.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2be6177ea344e..fb7a11fc8cffc 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1834,7 +1834,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, {name} - + {stab_docs} {docs} ", diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index c97cacd10c381..a27f92177f49f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -239,23 +239,23 @@ nav.sub { } .line-numbers span { cursor: pointer; } -.docblock.short p { +.docblock-short p { display: inline; } -.docblock.short.nowrap { +.docblock-short.nowrap { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.docblock.short p { +.docblock-short p { overflow: hidden; text-overflow: ellipsis; margin: 0; } -.docblock.short code { white-space: nowrap; } +.docblock-short code { white-space: nowrap; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { border-bottom: 1px solid; diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs index cdb4094ffe051..262a1ffce7473 100644 --- a/src/test/rustdoc/issue-32374.rs +++ b/src/test/rustdoc/issue-32374.rs @@ -13,7 +13,7 @@ #![unstable(feature="test", issue = "32374")] -// @has issue_32374/index.html '//*[@class="docblock short"]' \ +// @has issue_32374/index.html '//*[@class="docblock-short"]' \ // '[Deprecated] [Unstable]' // @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \ From 26d5f99ec061e439a00a85110135953a3d5c35ae Mon Sep 17 00:00:00 2001 From: Liigo Date: Fri, 9 Sep 2016 11:54:12 +0800 Subject: [PATCH 644/768] rustdoc: more docblock-short styles --- src/librustdoc/html/static/rustdoc.css | 6 +++--- src/librustdoc/html/static/styles/main.css | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index a27f92177f49f..9f86f5d9d20fe 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -130,11 +130,11 @@ code, pre { font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace; white-space: pre-wrap; } -.docblock code { +.docblock code, .docblock-short code { border-radius: 3px; padding: 0 0.2em; } -.docblock pre code { +.docblock pre code, .docblock-short pre code { padding: 0; } pre { @@ -409,7 +409,7 @@ a { background: transparent; } -.docblock a:hover, .stability a { +.docblock a:hover, .docblock-short a:hover, .stability a { text-decoration: underline; } diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index c64fb1b67f3d7..fceea85cc704f 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -34,7 +34,7 @@ div.stability > em > code { background-color: initial; } -.docblock code { +.docblock code, .docblock-short code { background-color: #F5F5F5; } pre { @@ -113,7 +113,7 @@ a { color: #000; } -.docblock a, .stability a { +.docblock a, .docblock-short a, .stability a { color: #3873AD; } From 5e9149d73f7d2912079f08e48eb257e8a6d4f0b3 Mon Sep 17 00:00:00 2001 From: orbea Date: Thu, 8 Sep 2016 23:18:20 -0700 Subject: [PATCH 645/768] Allow setting --docdir --- configure | 3 +++ mk/install.mk | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 71fb164f89122..6b822f6bc485f 100755 --- a/configure +++ b/configure @@ -671,6 +671,7 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary" valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples" valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples" valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" +valopt_nosave docdir "${CFG_PREFIX}/share/doc/rust" "install man pages in PATH" # On Windows this determines root of the subtree for target libraries. # Host runtime libs always go to 'bin'. @@ -1116,6 +1117,7 @@ putvar CFG_STDCPP_NAME # a little post-processing of various config values CFG_PREFIX=${CFG_PREFIX%/} CFG_MANDIR=${CFG_MANDIR%/} +CFG_DOCDIR=${CFG_DOCDIR%/} CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')" CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')" CFG_SUPPORTED_TARGET="" @@ -1797,6 +1799,7 @@ putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK putvar CFG_NACL_CROSS_PATH putvar CFG_MANDIR +putvar CFG_DOCDIR putvar CFG_USING_LIBCPP # Avoid spurious warnings from clang by feeding it original source on diff --git a/mk/install.mk b/mk/install.mk index d2e5449a2f513..be212869f0103 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -12,7 +12,8 @@ RUN_INSTALLER = cd tmp/empty_dir && \ sh ../../tmp/dist/$(1)/install.sh \ --prefix="$(DESTDIR)$(CFG_PREFIX)" \ --libdir="$(DESTDIR)$(CFG_LIBDIR)" \ - --mandir="$(DESTDIR)$(CFG_MANDIR)" + --mandir="$(DESTDIR)$(CFG_MANDIR)" \ + --docdir="$(DESTDIR)$(CFG_DOCDIR)" install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) From 0e32d1186830c8ad201dd79f1312a71e324eb98e Mon Sep 17 00:00:00 2001 From: Jared Wyles Date: Sat, 6 Aug 2016 08:26:09 +1000 Subject: [PATCH 646/768] Update the wording for E0063. This will truncate the fields to 3. Instead of listing every field it will now show missing `a`, `z`, `b`, and 1 other field --- src/librustc_typeck/check/mod.rs | 38 +++++++++++++++++++++++------ src/test/compile-fail/E0063.rs | 42 +++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b059c2ab9f3a8..8d121eeb58977 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3158,14 +3158,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.sess.span_err(span, "union expressions should have exactly one field"); } } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - span_err!(tcx.sess, span, E0063, - "missing field{} {} in initializer of `{}`", - if remaining_fields.len() == 1 {""} else {"s"}, - remaining_fields.keys() - .map(|n| format!("`{}`", n)) - .collect::>() - .join(", "), - adt_ty); + let len = remaining_fields.len(); + + let mut displayable_field_names = remaining_fields + .keys() + .map(|x| x.as_str()) + .collect::>(); + + displayable_field_names.sort(); + + let truncated_fields_error = if len <= 3 { + "".to_string() + } else { + format!(" and {} other field{}", (len - 3), if len - 3 == 1 {""} else {"s"}) + }; + + let remaining_fields_names = displayable_field_names.iter().take(3) + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "); + + struct_span_err!(tcx.sess, span, E0063, + "missing field{} {}{} in initializer of `{}`", + if remaining_fields.len() == 1 {""} else {"s"}, + remaining_fields_names, + truncated_fields_error, + adt_ty) + .span_label(span, &format!("missing {}{}", + remaining_fields_names, + truncated_fields_error)) + .emit(); } } diff --git a/src/test/compile-fail/E0063.rs b/src/test/compile-fail/E0063.rs index c94f807d807ca..e7044102abc71 100644 --- a/src/test/compile-fail/E0063.rs +++ b/src/test/compile-fail/E0063.rs @@ -8,11 +8,47 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Foo { +// ignore-tidy-linelength + +struct SingleFoo { + x: i32 +} + +struct PluralFoo { + x: i32, + y: i32, + z: i32 +} + +struct TruncatedFoo { + a: i32, + b: i32, x: i32, - y: i32 + y: i32, + z: i32 } +struct TruncatedPluralFoo { + a: i32, + b: i32, + c: i32, + x: i32, + y: i32, + z: i32 +} + + fn main() { - let x = Foo { x: 0 }; //~ ERROR E0063 + let w = SingleFoo { }; + //~^ ERROR missing field `x` in initializer of `SingleFoo` + //~| NOTE missing `x` + let x = PluralFoo {x: 1}; + //~^ ERROR missing fields `y`, `z` in initializer of `PluralFoo` + //~| NOTE missing `y`, `z` + let y = TruncatedFoo{x:1}; + //~^ missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo` + //~| NOTE `a`, `b`, `y` and 1 other field + let z = TruncatedPluralFoo{x:1}; + //~^ ERROR missing fields `a`, `b`, `c` and 2 other fields in initializer of `TruncatedPluralFoo` + //~| NOTE missing `a`, `b`, `c` and 2 other fields } From 19b84088d76b8ded63cbaf12991213f4f437e689 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 9 Sep 2016 23:00:23 +0200 Subject: [PATCH 647/768] Add s390x support This adds support for building the Rust compiler and standard library for s390x-linux, allowing a full cross-bootstrap sequence to complete. This includes: - Makefile/configure changes to allow native s390x builds - Full Rust compiler support for the s390x C ABI (only the non-vector ABI is supported at this point) - Port of the standard library to s390x - Update the liblibc submodule to a version including s390x support - Testsuite fixes to allow clean "make check" on s390x Caveats: - Resets base cpu to "z10" to bring support in sync with the default behaviour of other compilers on the platforms. (Usually, upstream supports all older processors; a distribution build may then chose to require a more recent base version.) (Also, using zEC12 causes failures in the valgrind tests since valgrind doesn't fully support this CPU yet.) - z13 vector ABI is not yet supported. To ensure compatible code generation, the -vector feature is passed to LLVM. Note that this means that even when compiling for z13, no vector instructions will be used. In the future, support for the vector ABI should be added (this will require common code support for different ABIs that need different data_layout strings on the same platform). - Two test cases are (temporarily) ignored on s390x to allow passing the test suite. The underlying issues still need to be fixed: * debuginfo/simd.rs fails because of incorrect debug information. This seems to be a LLVM bug (also seen with C code). * run-pass/union/union-basic.rs simply seems to be incorrect for all big-endian platforms. Signed-off-by: Ulrich Weigand --- configure | 4 + mk/cfg/s390x-unknown-linux-gnu.mk | 25 ++- src/liballoc_jemalloc/lib.rs | 3 +- src/liballoc_system/lib.rs | 3 +- src/liblibc | 2 +- src/libpanic_unwind/gcc.rs | 3 + .../target/s390x_unknown_linux_gnu.rs | 8 +- src/librustc_trans/abi.rs | 9 +- src/librustc_trans/cabi_s390x.rs | 150 ++++++++++++++++++ src/librustc_trans/lib.rs | 1 + src/libstd/env.rs | 6 + src/libstd/os/linux/raw.rs | 5 + src/libstd/os/raw.rs | 6 +- src/libstd/sys/unix/rand.rs | 14 +- src/libunwind/libunwind.rs | 3 + src/test/compile-fail/asm-bad-clobber.rs | 1 + src/test/compile-fail/asm-in-bad-modifier.rs | 2 + src/test/compile-fail/asm-misplaced-option.rs | 1 + src/test/compile-fail/asm-out-assign-imm.rs | 2 + src/test/compile-fail/asm-out-no-modifier.rs | 2 + src/test/compile-fail/asm-out-read-uninit.rs | 2 + src/test/debuginfo/simd.rs | 5 + src/test/run-make/atomic-lock-free/Makefile | 2 + src/test/run-pass/conditional-compile-arch.rs | 3 + src/test/run-pass/union/union-basic.rs | 3 + src/tools/compiletest/src/util.rs | 2 +- 26 files changed, 253 insertions(+), 14 deletions(-) create mode 100644 src/librustc_trans/cabi_s390x.rs diff --git a/configure b/configure index 71fb164f89122..792a1ed9c3cbd 100755 --- a/configure +++ b/configure @@ -524,6 +524,10 @@ case $CFG_CPUTYPE in CFG_CPUTYPE=powerpc64le ;; + s390x) + CFG_CPUTYPE=s390x + ;; + x86_64 | x86-64 | x64 | amd64) CFG_CPUTYPE=x86_64 ;; diff --git a/mk/cfg/s390x-unknown-linux-gnu.mk b/mk/cfg/s390x-unknown-linux-gnu.mk index 34aee77ae2107..eb1cb2329c4f3 100644 --- a/mk/cfg/s390x-unknown-linux-gnu.mk +++ b/mk/cfg/s390x-unknown-linux-gnu.mk @@ -1 +1,24 @@ -# rustbuild-only target +# s390x-unknown-linux-gnu configuration +CROSS_PREFIX_s390x-unknown-linux-gnu=s390x-linux-gnu- +CC_s390x-unknown-linux-gnu=$(CC) +CXX_s390x-unknown-linux-gnu=$(CXX) +CPP_s390x-unknown-linux-gnu=$(CPP) +AR_s390x-unknown-linux-gnu=$(AR) +CFG_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).so +CFG_STATIC_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).a +CFG_LIB_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.dylib.dSYM +CFG_CFLAGS_s390x-unknown-linux-gnu := -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_s390x-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CXXFLAGS_s390x-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_s390x-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 +CFG_GCCISH_DEF_FLAG_s390x-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_s390x-unknown-linux-gnu := +CFG_INSTALL_NAME_s390x-unknown-linux-gnu = +CFG_EXE_SUFFIX_s390x-unknown-linux-gnu = +CFG_WINDOWSY_s390x-unknown-linux-gnu := +CFG_UNIXY_s390x-unknown-linux-gnu := 1 +CFG_LDPATH_s390x-unknown-linux-gnu := +CFG_RUN_s390x-unknown-linux-gnu=$(2) +CFG_RUN_TARG_s390x-unknown-linux-gnu=$(call CFG_RUN_s390x-unknown-linux-gnu,,$(2)) +CFG_GNU_TRIPLE_s390x-unknown-linux-gnu := s390x-unknown-linux-gnu diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index aae0528e42cc9..5bbf1c35e0dd4 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -78,7 +78,8 @@ const MIN_ALIGN: usize = 8; target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64", - target_arch = "mips64")))] + target_arch = "mips64", + target_arch = "s390x")))] const MIN_ALIGN: usize = 16; // MALLOCX_ALIGN(a) macro diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 2c0c6d068caae..01407d1acd2ec 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -33,7 +33,8 @@ const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64", - target_arch = "mips64")))] + target_arch = "mips64", + target_arch = "s390x")))] const MIN_ALIGN: usize = 16; #[no_mangle] diff --git a/src/liblibc b/src/liblibc index 49d64cae0699e..d4f6a19c55a03 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 49d64cae0699ed9d9ed84810d737a26b0b519da8 +Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index c2e8eccbd22a4..33b24fbaa2659 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -130,6 +130,9 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 +#[cfg(target_arch = "s390x")] +const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7 + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index 895d33d8d755a..79f2d290e3760 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -12,8 +12,12 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - // NOTE(zEC12) matches C toolchain - base.cpu = "zEC12".to_string(); + // z10 is the oldest CPU supported by LLVM + base.cpu = "z10".to_string(); + // FIXME: The data_layout string below and the ABI implementation in + // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI. + // Pass the -vector feature string to LLVM to respect this assumption. + base.features = "-vector".to_string(); base.max_atomic_width = 64; Ok(Target { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 42289ec094f32..1a6c34b55af65 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -20,6 +20,7 @@ use cabi_arm; use cabi_aarch64; use cabi_powerpc; use cabi_powerpc64; +use cabi_s390x; use cabi_mips; use cabi_mips64; use cabi_asmjs; @@ -301,6 +302,9 @@ impl FnType { let win_x64_gnu = target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; + let linux_s390x = target.target_os == "linux" + && target.arch == "s390x" + && target.target_env == "gnu"; let rust_abi = match abi { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, _ => false @@ -326,7 +330,9 @@ impl FnType { if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. - if is_return || rust_abi || !win_x64_gnu { + // The same is true for s390x-unknown-linux-gnu. + if is_return || rust_abi || + (!win_x64_gnu && !linux_s390x) { arg.ignore(); } } @@ -511,6 +517,7 @@ impl FnType { "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), + "s390x" => cabi_s390x::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs new file mode 100644 index 0000000000000..19404b667e1fc --- /dev/null +++ b/src/librustc_trans/cabi_s390x.rs @@ -0,0 +1,150 @@ +// 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. + +// FIXME: The assumes we're using the non-vector ABI, i.e. compiling +// for a pre-z13 machine or using -mno-vx. + +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; +use abi::{FnType, ArgType}; +use context::CrateContext; +use type_::Type; + +use std::cmp; + +fn align_up_to(off: usize, a: usize) -> usize { + return (off + a - 1) / a * a; +} + +fn align(off: usize, ty: Type) -> usize { + let a = ty_align(ty); + return align_up_to(off, a); +} + +fn ty_align(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + Vector => ty_size(ty), + _ => bug!("ty_align: unhandled type") + } +} + +fn ty_size(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) + } + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => bug!("ty_size: unhandled type") + } +} + +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(64); + } else { + ret.make_indirect(ccx); + } +} + +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { + if arg.ty.kind() == Struct { + fn is_single_fp_element(tys: &[Type]) -> bool { + if tys.len() != 1 { + return false; + } + match tys[0].kind() { + Float | Double => true, + Struct => is_single_fp_element(&tys[0].field_types()), + _ => false + } + } + + if is_single_fp_element(&arg.ty.field_types()) { + match ty_size(arg.ty) { + 4 => arg.cast = Some(Type::f32(ccx)), + 8 => arg.cast = Some(Type::f64(ccx)), + _ => arg.make_indirect(ccx) + } + } else { + match ty_size(arg.ty) { + 1 => arg.cast = Some(Type::i8(ccx)), + 2 => arg.cast = Some(Type::i16(ccx)), + 4 => arg.cast = Some(Type::i32(ccx)), + 8 => arg.cast = Some(Type::i64(ccx)), + _ => arg.make_indirect(ccx) + } + } + return; + } + + if is_reg_ty(arg.ty) { + arg.extend_integer_width_to(64); + } else { + arg.make_indirect(ccx); + } +} + +fn is_reg_ty(ty: Type) -> bool { + match ty.kind() { + Integer + | Pointer + | Float + | Double => ty_size(ty) <= 8, + _ => false + } +} + +pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { continue; } + classify_arg_ty(ccx, arg); + } +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6f5bac840a1dc..3e60369acbff3 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -102,6 +102,7 @@ mod cabi_mips; mod cabi_mips64; mod cabi_powerpc; mod cabi_powerpc64; +mod cabi_s390x; mod cabi_x86; mod cabi_x86_64; mod cabi_x86_win64; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 9fcc3a80b98b4..63bf051c9bcd0 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -662,6 +662,7 @@ pub mod consts { /// - mips64 /// - powerpc /// - powerpc64 + /// - s390x #[stable(feature = "env", since = "1.0.0")] pub const ARCH: &'static str = super::arch::ARCH; @@ -942,6 +943,11 @@ mod arch { pub const ARCH: &'static str = "powerpc64"; } +#[cfg(target_arch = "s390x")] +mod arch { + pub const ARCH: &'static str = "s390x"; +} + #[cfg(target_arch = "le32")] mod arch { pub const ARCH: &'static str = "le32"; diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index 0f62877500b2c..1c19e58818d74 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -160,6 +160,11 @@ mod arch { pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; } +#[cfg(target_arch = "s390x")] +mod arch { + pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; +} + #[cfg(target_arch = "aarch64")] mod arch { use os::raw::{c_long, c_int}; diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 55d8ad17460dd..6c5c1b90a4a92 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -17,14 +17,16 @@ all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", - target_arch = "powerpc64"))))] + target_arch = "powerpc64", + target_arch = "s390x"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; #[cfg(not(any(target_os = "android", target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", - target_arch = "powerpc64")))))] + target_arch = "powerpc64", + target_arch = "s390x")))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index e4ca8344ee287..6b50ca9bcdf6d 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -45,7 +45,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64")))] + target_arch = "powerpc64", + target_arch = "s390x")))] fn getrandom(buf: &mut [u8]) -> libc::c_long { #[cfg(target_arch = "x86_64")] const NR_GETRANDOM: libc::c_long = 318; @@ -53,6 +54,8 @@ mod imp { const NR_GETRANDOM: libc::c_long = 355; #[cfg(target_arch = "arm")] const NR_GETRANDOM: libc::c_long = 384; + #[cfg(target_arch = "s390x")] + const NR_GETRANDOM: libc::c_long = 349; #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] const NR_GETRANDOM: libc::c_long = 359; #[cfg(target_arch = "aarch64")] @@ -71,7 +74,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64"))))] + target_arch = "powerpc64", + target_arch = "s390x"))))] fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } fn getrandom_fill_bytes(v: &mut [u8]) { @@ -110,7 +114,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64")))] + target_arch = "powerpc64", + target_arch = "s390x")))] fn is_getrandom_available() -> bool { use sync::atomic::{AtomicBool, Ordering}; use sync::Once; @@ -139,7 +144,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64"))))] + target_arch = "powerpc64", + target_arch = "s390x"))))] fn is_getrandom_available() -> bool { false } pub struct OsRng { diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index 8292a68417810..3900ba65293c0 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -62,6 +62,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] pub const unwinder_private_data_size: usize = 2; +#[cfg(target_arch = "s390x")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(target_arch = "asmjs")] pub const unwinder_private_data_size: usize = 20; diff --git a/src/test/compile-fail/asm-bad-clobber.rs b/src/test/compile-fail/asm-bad-clobber.rs index 714343a372d06..85832ddefe25f 100644 --- a/src/test/compile-fail/asm-bad-clobber.rs +++ b/src/test/compile-fail/asm-bad-clobber.rs @@ -11,6 +11,7 @@ // ignore-android // ignore-arm // ignore-aarch64 +// ignore-s390x #![feature(asm, rustc_attrs)] diff --git a/src/test/compile-fail/asm-in-bad-modifier.rs b/src/test/compile-fail/asm-in-bad-modifier.rs index 3cb608a9c5ed2..a4d076fc90da2 100644 --- a/src/test/compile-fail/asm-in-bad-modifier.rs +++ b/src/test/compile-fail/asm-in-bad-modifier.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/compile-fail/asm-misplaced-option.rs b/src/test/compile-fail/asm-misplaced-option.rs index 1020a5ba8a42e..fbfc20f8d048a 100644 --- a/src/test/compile-fail/asm-misplaced-option.rs +++ b/src/test/compile-fail/asm-misplaced-option.rs @@ -11,6 +11,7 @@ // ignore-android // ignore-arm // ignore-aarch64 +// ignore-s390x #![feature(asm, rustc_attrs)] diff --git a/src/test/compile-fail/asm-out-assign-imm.rs b/src/test/compile-fail/asm-out-assign-imm.rs index 0541faa021356..1329959fe4938 100644 --- a/src/test/compile-fail/asm-out-assign-imm.rs +++ b/src/test/compile-fail/asm-out-assign-imm.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/compile-fail/asm-out-no-modifier.rs b/src/test/compile-fail/asm-out-no-modifier.rs index 9cf43bebe65ab..d610f9e344024 100644 --- a/src/test/compile-fail/asm-out-no-modifier.rs +++ b/src/test/compile-fail/asm-out-no-modifier.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs index 5e71a2c731dd2..360f89dda9ce3 100644 --- a/src/test/compile-fail/asm-out-read-uninit.rs +++ b/src/test/compile-fail/asm-out-read-uninit.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index 620e1a73b4d64..80ac901b60fd3 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -12,6 +12,11 @@ // ignore-lldb // ignore-tidy-linelength +// FIXME: LLVM generates invalid debug info for variables requiring +// dynamic stack realignment, which is the case on s390x for vector +// types with with non-vector ABI. +// ignore-s390x + // compile-flags:-g // gdb-command:run diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile index 78e7bb231372f..e2ccbe2ad1473 100644 --- a/src/test/run-make/atomic-lock-free/Makefile +++ b/src/test/run-make/atomic-lock-free/Makefile @@ -27,4 +27,6 @@ ifeq ($(UNAME),Linux) nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add + $(RUSTC) --target=s390x-unknown-linux-gnu atomic_lock_free.rs + nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add endif diff --git a/src/test/run-pass/conditional-compile-arch.rs b/src/test/run-pass/conditional-compile-arch.rs index 44971e9252edd..368ffe6e713f4 100644 --- a/src/test/run-pass/conditional-compile-arch.rs +++ b/src/test/run-pass/conditional-compile-arch.rs @@ -25,5 +25,8 @@ pub fn main() { } #[cfg(target_arch = "powerpc64")] pub fn main() { } +#[cfg(target_arch = "s390x")] +pub fn main() { } + #[cfg(target_arch = "asmjs")] pub fn main() { } diff --git a/src/test/run-pass/union/union-basic.rs b/src/test/run-pass/union/union-basic.rs index d23af4b41b73f..dc14c12b6a22e 100644 --- a/src/test/run-pass/union/union-basic.rs +++ b/src/test/run-pass/union/union-basic.rs @@ -10,6 +10,9 @@ // aux-build:union.rs +// FIXME: This test case makes little-endian assumptions. +// ignore-s390x + #![feature(untagged_unions)] extern crate union; diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index d2872a0a2b7ca..2db53947d881d 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -38,7 +38,7 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[("aarch64", "aarch ("msp430", "msp430"), ("powerpc", "powerpc"), ("powerpc64", "powerpc64"), - ("s390x", "systemz"), + ("s390x", "s390x"), ("sparc", "sparc"), ("x86_64", "x86_64"), ("xcore", "xcore"), From fe41520fceb00427e797cc0b42f449f54967b104 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 9 Sep 2016 14:53:15 -0700 Subject: [PATCH 648/768] Add ExpnId to expanded procedural macro code --- src/libsyntax_ext/deriving/custom.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 716cf3a94b516..465fc0016e5e8 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -10,12 +10,14 @@ use std::panic; +use errors::FatalError; use rustc_macro::{TokenStream, __internal}; use syntax::ast::{self, ItemKind}; -use syntax::codemap::Span; +use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span}; use syntax::ext::base::*; use syntax::fold::{self, Folder}; -use errors::FatalError; +use syntax::parse::token::intern; +use syntax::print::pprust; pub struct CustomDerive { inner: fn(TokenStream) -> TokenStream, @@ -31,7 +33,7 @@ impl MultiItemModifier for CustomDerive { fn expand(&self, ecx: &mut ExtCtxt, span: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, item: Annotatable) -> Vec { let item = match item { @@ -53,7 +55,17 @@ impl MultiItemModifier for CustomDerive { } } - let input_span = item.span; + let input_span = Span { + expn_id: ecx.codemap().record_expansion(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: MacroAttribute(intern(&pprust::meta_item_to_string(meta_item))), + span: Some(span), + allow_internal_unstable: true, + }, + }), + ..item.span + }; let input = __internal::new_token_stream(item); let res = __internal::set_parse_sess(&ecx.parse_sess, || { let inner = self.inner; From fb85dd398bad8043f73a349d42a1d8180b1048c4 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Thu, 8 Sep 2016 22:02:49 +0300 Subject: [PATCH 649/768] fix span for errors E0537, E0535 & E0536 --- src/libsyntax/parse/attr.rs | 10 +++++----- src/test/{compile-fail => ui/span}/E0535.rs | 0 src/test/ui/span/E0535.stderr | 8 ++++++++ src/test/{compile-fail => ui/span}/E0536.rs | 0 src/test/ui/span/E0536.stderr | 8 ++++++++ src/test/{compile-fail => ui/span}/E0537.rs | 0 src/test/ui/span/E0537.stderr | 8 ++++++++ 7 files changed, 29 insertions(+), 5 deletions(-) rename src/test/{compile-fail => ui/span}/E0535.rs (100%) create mode 100644 src/test/ui/span/E0535.stderr rename src/test/{compile-fail => ui/span}/E0536.rs (100%) create mode 100644 src/test/ui/span/E0536.stderr rename src/test/{compile-fail => ui/span}/E0537.rs (100%) create mode 100644 src/test/ui/span/E0537.stderr diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 27dd055cd3ae7..a0defbc09dc04 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -125,7 +125,7 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Bracket))?; let meta_item = self.parse_meta_item()?; - let hi = self.span.hi; + let hi = self.last_span.hi; self.expect(&token::CloseDelim(token::Bracket))?; (mk_sp(lo, hi), meta_item, style) @@ -231,12 +231,12 @@ impl<'a> Parser<'a> { token::Eq => { self.bump(); let lit = self.parse_unsuffixed_lit()?; - let hi = self.span.hi; + let hi = self.last_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit)))) } token::OpenDelim(token::Paren) => { let inner_items = self.parse_meta_seq()?; - let hi = self.span.hi; + let hi = self.last_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::List(name, inner_items)))) } _ => { @@ -253,14 +253,14 @@ impl<'a> Parser<'a> { match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::Literal(lit))) + return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::Literal(lit))) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) } Err(ref mut err) => self.diagnostic().cancel(err) } diff --git a/src/test/compile-fail/E0535.rs b/src/test/ui/span/E0535.rs similarity index 100% rename from src/test/compile-fail/E0535.rs rename to src/test/ui/span/E0535.rs diff --git a/src/test/ui/span/E0535.stderr b/src/test/ui/span/E0535.stderr new file mode 100644 index 0000000000000..23070e1555b9b --- /dev/null +++ b/src/test/ui/span/E0535.stderr @@ -0,0 +1,8 @@ +error[E0535]: invalid argument + --> $DIR/E0535.rs:11:10 + | +11 | #[inline(unknown)] //~ ERROR E0535 + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/E0536.rs b/src/test/ui/span/E0536.rs similarity index 100% rename from src/test/compile-fail/E0536.rs rename to src/test/ui/span/E0536.rs diff --git a/src/test/ui/span/E0536.stderr b/src/test/ui/span/E0536.stderr new file mode 100644 index 0000000000000..c33b89953e274 --- /dev/null +++ b/src/test/ui/span/E0536.stderr @@ -0,0 +1,8 @@ +error[E0536]: expected 1 cfg-pattern + --> $DIR/E0536.rs:11:7 + | +11 | #[cfg(not())] //~ ERROR E0536 + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/E0537.rs b/src/test/ui/span/E0537.rs similarity index 100% rename from src/test/compile-fail/E0537.rs rename to src/test/ui/span/E0537.rs diff --git a/src/test/ui/span/E0537.stderr b/src/test/ui/span/E0537.stderr new file mode 100644 index 0000000000000..9d66ddbaae317 --- /dev/null +++ b/src/test/ui/span/E0537.stderr @@ -0,0 +1,8 @@ +error[E0537]: invalid predicate `unknown` + --> $DIR/E0537.rs:11:7 + | +11 | #[cfg(unknown())] //~ ERROR E0537 + | ^^^^^^^^^ + +error: aborting due to previous error + From b693a2e0adfd4c7b366d0ab147ca9f6fade51051 Mon Sep 17 00:00:00 2001 From: dangcheng Date: Sat, 10 Sep 2016 16:30:59 +0800 Subject: [PATCH 650/768] fix mistake (File::open -> File::create) --- src/doc/book/traits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index 9cbb514e28065..605dc2a152df9 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -275,7 +275,7 @@ won’t have its methods: [write]: ../std/io/trait.Write.html ```rust,ignore -let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; // byte string literal. buf: &[u8; 8] let result = f.write(buf); # result.unwrap(); // ignore the error @@ -294,7 +294,7 @@ We need to `use` the `Write` trait first: ```rust,ignore use std::io::Write; -let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; let result = f.write(buf); # result.unwrap(); // ignore the error From 38009bfa91d9e928babb03e749b33b2476288227 Mon Sep 17 00:00:00 2001 From: Kylo Ginsberg Date: Sat, 10 Sep 2016 07:58:30 -0700 Subject: [PATCH 651/768] book: fix a typo --- src/doc/book/references-and-borrowing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md index 57bfbce8b84de..2ec3a00c0df51 100644 --- a/src/doc/book/references-and-borrowing.md +++ b/src/doc/book/references-and-borrowing.md @@ -152,7 +152,7 @@ the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well If it wasn’t, we couldn’t take a mutable borrow to an immutable value. You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`, -this is because `y` is a `&mut` reference. You'll need to use astrisks to +this is because `y` is a `&mut` reference. You'll need to use asterisks to access the contents of a reference as well. Otherwise, `&mut` references are like references. There _is_ a large From 2a2c9d38c78ece0a6c5de80e382a136173e64b14 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 652/768] Improve shallow `Clone` deriving --- src/libcore/clone.rs | 19 +- src/libsyntax_ext/deriving/clone.rs | 179 +++++++++++------- src/libsyntax_ext/deriving/generic/mod.rs | 27 ++- .../borrowck/borrowck-union-borrow-nested.rs | 6 +- .../borrowck/borrowck-union-borrow.rs | 6 +- src/test/compile-fail/union/union-copy.rs | 4 +- .../compile-fail/union/union-derive-clone.rs | 41 ++++ src/test/compile-fail/union/union-derive.rs | 1 - src/test/run-pass/union/union-c-interop.rs | 7 +- src/test/run-pass/union/union-derive.rs | 9 +- 10 files changed, 199 insertions(+), 100 deletions(-) create mode 100644 src/test/compile-fail/union/union-derive-clone.rs diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 748bb62a1f3eb..3333cbfc1fc4e 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -106,10 +106,23 @@ pub trait Clone : Sized { } } -// FIXME(aburka): this method is used solely by #[derive] to -// assert that every component of a type implements Clone. +// FIXME(aburka): these structs are used solely by #[derive] to +// assert that every component of a type implements Clone or Copy. // -// This should never be called by user code. +// These structs should never appear in user code. +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[unstable(feature = "derive_clone_copy", + reason = "deriving hack, should not be public", + issue = "0")] +pub struct AssertParamIsClone { _field: ::marker::PhantomData } +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[unstable(feature = "derive_clone_copy", + reason = "deriving hack, should not be public", + issue = "0")] +pub struct AssertParamIsCopy { _field: ::marker::PhantomData } +#[cfg(stage0)] #[doc(hidden)] #[inline(always)] #[unstable(feature = "derive_clone_copy", diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index c7afaaf4796a4..aa7c2c301dd7a 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -11,20 +11,14 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{Expr, Generics, ItemKind, MetaItem, VariantData}; +use syntax::ast::{self, Expr, Generics, ItemKind, MetaItem, VariantData}; use syntax::attr; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; -use syntax::parse::token::InternedString; +use syntax::parse::token::{keywords, InternedString}; use syntax::ptr::P; use syntax_pos::Span; -#[derive(PartialEq)] -enum Mode { - Deep, - Shallow, -} - pub fn expand_deriving_clone(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, @@ -40,29 +34,38 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, // if we used the short form with generics, we'd have to bound the generics with // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something // that is Clone but not Copy. and until specialization we can't write both impls. + // - the item is a union with Copy fields + // Unions with generic parameters still can derive Clone because they require Copy + // for deriving, Clone alone is not enough. + // Whever Clone is implemented for fields is irrelevant so we don't assert it. let bounds; - let unify_fieldless_variants; let substructure; + let is_shallow; match *item { Annotatable::Item(ref annitem) => { match annitem.node { ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) - if ty_params.is_empty() && - attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => { - + if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") && + ty_params.is_empty() => { + bounds = vec![]; + is_shallow = true; + substructure = combine_substructure(Box::new(|c, s, sub| { + cs_clone_shallow("Clone", c, s, sub, false) + })); + } + ItemKind::Union(..) => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; - unify_fieldless_variants = true; + is_shallow = true; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone("Clone", c, s, sub, Mode::Shallow) + cs_clone_shallow("Clone", c, s, sub, true) })); } - _ => { bounds = vec![]; - unify_fieldless_variants = false; + is_shallow = false; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone("Clone", c, s, sub, Mode::Deep) + cs_clone("Clone", c, s, sub) })); } } @@ -80,7 +83,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, - supports_unions: false, + supports_unions: true, methods: vec![MethodDef { name: "clone", generics: LifetimeBounds::empty(), @@ -89,37 +92,85 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ret_ty: Self_, attributes: attrs, is_unsafe: false, - unify_fieldless_variants: unify_fieldless_variants, + unify_fieldless_variants: false, combine_substructure: substructure, }], associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand_ext(cx, mitem, item, push, is_shallow) +} + +fn cs_clone_shallow(name: &str, + cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + is_union: bool) + -> P { + fn assert_ty_bounds(cx: &mut ExtCtxt, stmts: &mut Vec, + ty: P, span: Span, helper_name: &str) { + // Generate statement `let _: helper_name;`, + // set the expn ID so we can use the unstable struct. + let span = super::allow_unstable(cx, span, "derive(Clone)"); + let assert_path = cx.path_all(span, true, + cx.std_path(&["clone", helper_name]), + vec![], vec![ty], vec![]); + let local = P(ast::Local { + pat: cx.pat_wild(span), + ty: Some(cx.ty_path(assert_path)), + init: None, + id: ast::DUMMY_NODE_ID, + span: span, + attrs: ast::ThinVec::new(), + }); + let stmt = ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: span, + }; + stmts.push(stmt); + } + fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec, variant: &VariantData) { + for field in variant.fields() { + // let _: AssertParamIsClone; + assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsClone"); + } + } + + let mut stmts = Vec::new(); + if is_union { + // let _: AssertParamIsCopy; + let self_ty = cx.ty_path(cx.path_ident(trait_span, keywords::SelfType.ident())); + assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy"); + } else { + match *substr.fields { + StaticStruct(vdata, ..) => { + process_variant(cx, &mut stmts, vdata); + } + StaticEnum(enum_def, ..) => { + for variant in &enum_def.variants { + process_variant(cx, &mut stmts, &variant.node.data); + } + } + _ => cx.span_bug(trait_span, &format!("unexpected substructure in \ + shallow `derive({})`", name)) + } + } + stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); + cx.expr_block(cx.block(trait_span, stmts)) } fn cs_clone(name: &str, cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, - mode: Mode) + substr: &Substructure) -> P { let ctor_path; let all_fields; - let fn_path = match mode { - Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), - Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), - }; + let fn_path = cx.std_path(&["clone", "Clone", "clone"]); let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; - - let span = if mode == Mode::Shallow { - // set the expn ID so we can call the unstable method - super::allow_unstable(cx, field.span, "derive(Clone)") - } else { - field.span - }; - cx.expr_call_global(span, fn_path.clone(), args) + cx.expr_call_global(field.span, fn_path.clone(), args) }; let vdata; @@ -145,43 +196,31 @@ fn cs_clone(name: &str, } } - match mode { - Mode::Shallow => { - let mut stmts = all_fields.iter().map(|f| { - let call = subcall(cx, f); - cx.stmt_expr(call) - }).collect::>(); - stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); - cx.expr_block(cx.block(trait_span, stmts)) - } - Mode::Deep => { - match *vdata { - VariantData::Struct(..) => { - let fields = all_fields.iter() - .map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", - name)) - } - }; - let call = subcall(cx, field); - cx.field_imm(field.span, ident, call) - }) - .collect::>(); + match *vdata { + VariantData::Struct(..) => { + let fields = all_fields.iter() + .map(|field| { + let ident = match field.name { + Some(i) => i, + None => { + cx.span_bug(trait_span, + &format!("unnamed field in normal struct in \ + `derive({})`", + name)) + } + }; + let call = subcall(cx, field); + cx.field_imm(field.span, ident, call) + }) + .collect::>(); - cx.expr_struct(trait_span, ctor_path, fields) - } - VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } - VariantData::Unit(..) => cx.expr_path(ctor_path), - } + cx.expr_struct(trait_span, ctor_path, fields) + } + VariantData::Tuple(..) => { + let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); + let path = cx.expr_path(ctor_path); + cx.expr_call(trait_span, path, subcalls) } + VariantData::Unit(..) => cx.expr_path(ctor_path), } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 600f5d335c472..339a6c477ccd5 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -401,18 +401,29 @@ impl<'a> TraitDef<'a> { mitem: &ast::MetaItem, item: &'a Annotatable, push: &mut FnMut(Annotatable)) { + self.expand_ext(cx, mitem, item, push, false); + } + + pub fn expand_ext(&self, + cx: &mut ExtCtxt, + mitem: &ast::MetaItem, + item: &'a Annotatable, + push: &mut FnMut(Annotatable), + from_scratch: bool) { match *item { Annotatable::Item(ref item) => { let newitem = match item.node { ast::ItemKind::Struct(ref struct_def, ref generics) => { - self.expand_struct_def(cx, &struct_def, item.ident, generics) + self.expand_struct_def(cx, &struct_def, item.ident, generics, from_scratch) } ast::ItemKind::Enum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics) + self.expand_enum_def(cx, enum_def, &item.attrs, + item.ident, generics, from_scratch) } ast::ItemKind::Union(ref struct_def, ref generics) => { if self.supports_unions { - self.expand_struct_def(cx, &struct_def, item.ident, generics) + self.expand_struct_def(cx, &struct_def, item.ident, + generics, from_scratch) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -661,7 +672,8 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt, struct_def: &'a VariantData, type_ident: Ident, - generics: &Generics) + generics: &Generics, + from_scratch: bool) -> P { let field_tys: Vec> = struct_def.fields() .iter() @@ -674,7 +686,7 @@ impl<'a> TraitDef<'a> { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { + let body = if from_scratch || method_def.is_static() { method_def.expand_static_struct_method_body(cx, self, struct_def, @@ -709,7 +721,8 @@ impl<'a> TraitDef<'a> { enum_def: &'a EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, - generics: &Generics) + generics: &Generics, + from_scratch: bool) -> P { let mut field_tys = Vec::new(); @@ -727,7 +740,7 @@ impl<'a> TraitDef<'a> { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { + let body = if from_scratch || method_def.is_static() { method_def.expand_static_enum_method_body(cx, self, enum_def, diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs index 19975d79b60be..8b6b8d9ecb08e 100644 --- a/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs @@ -18,16 +18,12 @@ struct S { b: u16, } +#[derive(Clone, Copy)] union U { s: S, c: u32, } -impl Clone for U { - fn clone(&self) -> Self { *self } -} -impl Copy for U {} - fn main() { unsafe { { diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs index e8989a3c2d499..ecc698acc317f 100644 --- a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs @@ -12,16 +12,12 @@ #![feature(untagged_unions)] +#[derive(Clone, Copy)] union U { a: u8, b: u64, } -impl Clone for U { - fn clone(&self) -> Self { *self } -} -impl Copy for U {} - fn main() { unsafe { let mut u = U { b: 0 }; diff --git a/src/test/compile-fail/union/union-copy.rs b/src/test/compile-fail/union/union-copy.rs index 6e08ae0074d48..9014b3f2956b7 100644 --- a/src/test/compile-fail/union/union-copy.rs +++ b/src/test/compile-fail/union/union-copy.rs @@ -10,16 +10,16 @@ #![feature(untagged_unions)] +#[derive(Clone)] union U { a: u8 } +#[derive(Clone)] union W { a: String } -impl Clone for U { fn clone(&self) { panic!(); } } -impl Clone for W { fn clone(&self) { panic!(); } } impl Copy for U {} // OK impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type diff --git a/src/test/compile-fail/union/union-derive-clone.rs b/src/test/compile-fail/union/union-derive-clone.rs new file mode 100644 index 0000000000000..6e226d7d79f9f --- /dev/null +++ b/src/test/compile-fail/union/union-derive-clone.rs @@ -0,0 +1,41 @@ +// 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. + +#![feature(untagged_unions)] + +#[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied +union U1 { + a: u8, +} + +#[derive(Clone)] +union U2 { + a: u8, // OK +} + +impl Copy for U2 {} + +#[derive(Clone, Copy)] +union U3 { + a: u8, // OK +} + +#[derive(Clone, Copy)] +union U4 { + a: T, // OK +} + +#[derive(Clone)] +struct CloneNoCopy; + +fn main() { + let u = U4 { a: CloneNoCopy }; + let w = u.clone(); //~ ERROR no method named `clone` found for type `U4` +} diff --git a/src/test/compile-fail/union/union-derive.rs b/src/test/compile-fail/union/union-derive.rs index 0f78e96f640c7..01ce9696284df 100644 --- a/src/test/compile-fail/union/union-derive.rs +++ b/src/test/compile-fail/union/union-derive.rs @@ -13,7 +13,6 @@ #![feature(untagged_unions)] #[derive( - Clone, //~ ERROR this trait cannot be derived for unions PartialEq, //~ ERROR this trait cannot be derived for unions Eq, //~ ERROR this trait cannot be derived for unions PartialOrd, //~ ERROR this trait cannot be derived for unions diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs index a9f97620ebd46..bea4d5f923e21 100644 --- a/src/test/run-pass/union/union-c-interop.rs +++ b/src/test/run-pass/union/union-c-interop.rs @@ -10,14 +10,14 @@ #![feature(untagged_unions)] -#[derive(Copy)] +#[derive(Clone, Copy)] #[repr(C)] struct LARGE_INTEGER_U { LowPart: u32, HighPart: u32, } -#[derive(Copy)] +#[derive(Clone, Copy)] #[repr(C)] union LARGE_INTEGER { __unnamed__: LARGE_INTEGER_U, @@ -25,9 +25,6 @@ union LARGE_INTEGER { QuadPart: u64, } -impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } } -impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } } - #[link(name = "rust_test_helpers")] extern "C" { fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER; diff --git a/src/test/run-pass/union/union-derive.rs b/src/test/run-pass/union/union-derive.rs index b71c23990a474..8314416e2b10a 100644 --- a/src/test/run-pass/union/union-derive.rs +++ b/src/test/run-pass/union/union-derive.rs @@ -14,18 +14,23 @@ #[derive( Copy, + Clone, )] union U { a: u8, b: u16, } -impl Clone for U { - fn clone(&self) -> Self { *self } +#[derive(Clone, Copy)] +union W { + a: T, } fn main() { let u = U { b: 0 }; let u1 = u; let u2 = u.clone(); + + let w = W { a: 0 }; + let w1 = w.clone(); } From 63fecad2e7c1f58e962a100d4159ddd47ebc627f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Sep 2016 20:39:49 -0700 Subject: [PATCH 653/768] Inherit overflow checks for sum and product --- src/libcore/iter/iterator.rs | 6 ++-- src/libcore/iter/traits.rs | 19 ++++------ src/test/run-pass/iter-sum-overflow-debug.rs | 35 +++++++++++++++++++ src/test/run-pass/iter-sum-overflow-ndebug.rs | 23 ++++++++++++ 4 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/iter-sum-overflow-debug.rs create mode 100644 src/test/run-pass/iter-sum-overflow-ndebug.rs diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6b616f8018156..0e74bbe9c2600 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1867,7 +1867,8 @@ pub trait Iterator { /// # Panics /// /// When calling `sum` and a primitive integer type is being returned, this - /// method will panic if the computation overflows. + /// method will panic if the computation overflows and debug assertions are + /// enabled. /// /// # Examples /// @@ -1894,7 +1895,8 @@ pub trait Iterator { /// # Panics /// /// When calling `product` and a primitive integer type is being returned, - /// this method will panic if the computation overflows. + /// method will panic if the computation overflows and debug assertions are + /// enabled. /// /// # Examples /// diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 59e23c4d96056..563fb213d3763 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +use ops::{Mul, Add}; /// Conversion from an `Iterator`. /// @@ -581,41 +582,35 @@ pub trait Product: Sized { fn product>(iter: I) -> Self; } +// NB: explicitly use Add and Mul here to inherit overflow checks macro_rules! integer_sum_product { ($($a:ident)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { + #[rustc_inherit_overflow_checks] fn sum>(iter: I) -> $a { - iter.fold(0, |a, b| { - a.checked_add(b).expect("overflow in sum") - }) + iter.fold(0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { - iter.fold(1, |a, b| { - a.checked_mul(b).expect("overflow in product") - }) + iter.fold(1, Mul::mul) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { - iter.fold(0, |a, b| { - a.checked_add(*b).expect("overflow in sum") - }) + iter.cloned().fold(0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { - iter.fold(1, |a, b| { - a.checked_mul(*b).expect("overflow in product") - }) + iter.cloned().fold(1, Mul::mul) } } )*) diff --git a/src/test/run-pass/iter-sum-overflow-debug.rs b/src/test/run-pass/iter-sum-overflow-debug.rs new file mode 100644 index 0000000000000..6c07afb37b8a0 --- /dev/null +++ b/src/test/run-pass/iter-sum-overflow-debug.rs @@ -0,0 +1,35 @@ +// 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. + +// compile-flags: -C debug_assertions=yes + +use std::panic; + +fn main() { + let r = panic::catch_unwind(|| { + [1, i32::max_value()].iter().sum::(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + [2, i32::max_value()].iter().product::(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + [1, i32::max_value()].iter().cloned().sum::(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + [2, i32::max_value()].iter().cloned().product::(); + }); + assert!(r.is_err()); +} diff --git a/src/test/run-pass/iter-sum-overflow-ndebug.rs b/src/test/run-pass/iter-sum-overflow-ndebug.rs new file mode 100644 index 0000000000000..65ac1ef29ed6a --- /dev/null +++ b/src/test/run-pass/iter-sum-overflow-ndebug.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=no + +fn main() { + assert_eq!([1i32, i32::max_value()].iter().sum::(), + 1i32.wrapping_add(i32::max_value())); + assert_eq!([2i32, i32::max_value()].iter().product::(), + 2i32.wrapping_mul(i32::max_value())); + + assert_eq!([1i32, i32::max_value()].iter().cloned().sum::(), + 1i32.wrapping_add(i32::max_value())); + assert_eq!([2i32, i32::max_value()].iter().cloned().product::(), + 2i32.wrapping_mul(i32::max_value())); +} From 72e103fe90f678f6c6028f17cdd9a5b825a8c5f9 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Thu, 8 Sep 2016 20:04:05 -0700 Subject: [PATCH 654/768] Tweak std::mem docs Fixes #29362. --- src/libcore/intrinsics.rs | 47 +++--- src/libcore/mem.rs | 294 ++++++++++++++++++++++++++------------ 2 files changed, 231 insertions(+), 110 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8271b85b01a3b..06b506ab014b4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -262,22 +262,25 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type; both types - /// must have the same size. Neither the original, nor the result, may be an - /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html). + /// Reinterprets the bits of a value of one type as another type. + /// + /// Both types must have the same size. Neither the original, nor the result, + /// may be an [invalid value](../../nomicon/meet-safe-and-unsafe.html). /// /// `transmute` is semantically equivalent to a bitwise move of one type - /// into another. It copies the bits from the destination type into the - /// source type, then forgets the original. It's equivalent to C's `memcpy` - /// under the hood, just like `transmute_copy`. + /// into another. It copies the bits from the source value into the + /// destination value, then forgets the original. It's equivalent to C's + /// `memcpy` under the hood, just like `transmute_copy`. /// - /// `transmute` is incredibly unsafe. There are a vast number of ways to - /// cause undefined behavior with this function. `transmute` should be + /// `transmute` is **incredibly** unsafe. There are a vast number of ways to + /// cause [undefined behavior][ub] with this function. `transmute` should be /// the absolute last resort. /// /// The [nomicon](../../nomicon/transmutes.html) has additional /// documentation. /// + /// [ub]: ../../reference.html#behavior-considered-undefined + /// /// # Examples /// /// There are a few things that `transmute` is really useful for. @@ -292,7 +295,8 @@ extern "rust-intrinsic" { /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// - /// Turning a pointer into a function pointer: + /// Turning a pointer into a function pointer. This is *not* portable to + /// machines where function pointers and data pointers have different sizes. /// /// ``` /// fn foo() -> i32 { @@ -305,8 +309,8 @@ extern "rust-intrinsic" { /// assert_eq!(function(), 0); /// ``` /// - /// Extending a lifetime, or shortening an invariant lifetime; this is - /// advanced, very unsafe rust: + /// Extending a lifetime, or shortening an invariant lifetime. This is + /// advanced, very unsafe Rust! /// /// ``` /// struct R<'a>(&'a i32); @@ -322,11 +326,9 @@ extern "rust-intrinsic" { /// /// # Alternatives /// - /// However, many uses of `transmute` can be achieved through other means. - /// `transmute` can transform any type into any other, with just the caveat - /// that they're the same size, and often interesting results occur. Below - /// are common applications of `transmute` which can be replaced with safe - /// applications of `as`: + /// Don't despair: many uses of `transmute` can be achieved through other means. + /// Below are common applications of `transmute` which can be replaced with safer + /// constructs. /// /// Turning a pointer into a `usize`: /// @@ -335,6 +337,7 @@ extern "rust-intrinsic" { /// let ptr_num_transmute = unsafe { /// std::mem::transmute::<&i32, usize>(ptr) /// }; + /// /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` @@ -346,6 +349,7 @@ extern "rust-intrinsic" { /// let ref_transmuted = unsafe { /// std::mem::transmute::<*mut i32, &mut i32>(ptr) /// }; + /// /// // Use a reborrow instead /// let ref_casted = unsafe { &mut *ptr }; /// ``` @@ -357,6 +361,7 @@ extern "rust-intrinsic" { /// let val_transmuted = unsafe { /// std::mem::transmute::<&mut i32, &mut u32>(ptr) /// }; + /// /// // Now, put together `as` and reborrowing - note the chaining of `as` /// // `as` is not transitive /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; @@ -368,9 +373,11 @@ extern "rust-intrinsic" { /// // this is not a good way to do this. /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, &[82, 117, 115, 116]); + /// /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, &[82, 117, 115, 116]); + /// /// // Or, just use a byte string, if you have control over the string /// // literal /// assert_eq!(b"Rust", &[82, 117, 115, 116]); @@ -381,18 +388,21 @@ extern "rust-intrinsic" { /// ``` /// let store = [0, 1, 2, 3]; /// let mut v_orig = store.iter().collect::>(); + /// /// // Using transmute: this is Undefined Behavior, and a bad idea. /// // However, it is no-copy. /// let v_transmuted = unsafe { /// std::mem::transmute::, Vec>>( /// v_orig.clone()) /// }; + /// /// // This is the suggested, safe way. - /// // It does copy the entire Vector, though, into a new array. + /// // It does copy the entire vector, though, into a new array. /// let v_collected = v_orig.clone() /// .into_iter() /// .map(|r| Some(r)) /// .collect::>>(); + /// /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the /// // same Vec internals. Therefore the new inner type must have the @@ -412,6 +422,7 @@ extern "rust-intrinsic" { /// /// ``` /// use std::{slice, mem}; + /// /// // There are multiple ways to do this; and there are multiple problems /// // with the following, transmute, way. /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) @@ -426,6 +437,7 @@ extern "rust-intrinsic" { /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } + /// /// // This gets rid of the typesafety problems; `&mut *` will *only* give /// // you an `&mut T` from an `&mut T` or `*mut T`. /// fn split_at_mut_casts(slice: &mut [T], mid: usize) @@ -439,6 +451,7 @@ extern "rust-intrinsic" { /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } + /// /// // This is how the standard library does it. This is the best method, if /// // you need to do something like this /// fn split_at_stdlib(slice: &mut [T], mid: usize) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 9c61f76ac8895..d3b8a60b79776 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -21,54 +21,39 @@ use ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::transmute; -/// Leaks a value into the void, consuming ownership and never running its -/// destructor. +/// Leaks a value: takes ownership and "forgets" about the value **without running +/// its destructor**. /// -/// This function will take ownership of its argument, but is distinct from the -/// `mem::drop` function in that it **does not run the destructor**, leaking the -/// value and any resources that it owns. +/// Any resources the value manages, such as heap memory or a file handle, will linger +/// forever in an unreachable state. /// -/// There's only a few reasons to use this function. They mainly come -/// up in unsafe code or FFI code. -/// -/// * You have an uninitialized value, perhaps for performance reasons, and -/// need to prevent the destructor from running on it. -/// * You have two copies of a value (like when writing something like -/// [`mem::swap`][swap]), but need the destructor to only run once to -/// prevent a double `free`. -/// * Transferring resources across [FFI][ffi] boundaries. -/// -/// [swap]: fn.swap.html -/// [ffi]: ../../book/ffi.html +/// If you want to dispose of a value properly, running its destructor, see +/// [`mem::drop`][drop]. /// /// # Safety /// -/// This function is not marked as `unsafe` as Rust does not guarantee that the -/// `Drop` implementation for a value will always run. Note, however, that -/// leaking resources such as memory or I/O objects is likely not desired, so -/// this function is only recommended for specialized use cases. -/// -/// The safety of this function implies that when writing `unsafe` code -/// yourself care must be taken when leveraging a destructor that is required to -/// run to preserve memory safety. There are known situations where the -/// destructor may not run (such as if ownership of the object with the -/// destructor is returned) which must be taken into account. +/// `forget` is not marked as `unsafe`, because Rust's safety guarantees +/// do not include a guarantee that destructors will always run. For example, +/// a program can create a reference cycle using [`Rc`][rc], or call +/// [`process:exit`][exit] to exit without running destructors. Thus, allowing +/// `mem::forget` from safe code does not fundamentally change Rust's safety +/// guarantees. /// -/// # Other forms of Leakage +/// That said, leaking resources such as memory or I/O objects is usually undesirable, +/// so `forget` is only recommended for specialized use cases like those shown below. /// -/// It's important to point out that this function is not the only method by -/// which a value can be leaked in safe Rust code. Other known sources of -/// leakage are: +/// Because forgetting a value is allowed, any `unsafe` code you write must +/// allow for this possibility. You cannot return a value and expect that the +/// caller will necessarily run the value's destructor. /// -/// * `Rc` and `Arc` cycles -/// * `mpsc::{Sender, Receiver}` cycles (they use `Arc` internally) -/// * Panicking destructors are likely to leak local resources +/// [rc]: ../../std/rc/struct.Rc.html +/// [exit]: ../../std/process/fn.exit.html /// -/// # Example +/// # Examples /// /// Leak some heap memory by never deallocating it: /// -/// ```rust +/// ``` /// use std::mem; /// /// let heap_memory = Box::new(3); @@ -77,7 +62,7 @@ pub use intrinsics::transmute; /// /// Leak an I/O object, never closing the file: /// -/// ```rust,no_run +/// ```no_run /// use std::mem; /// use std::fs::File; /// @@ -85,9 +70,43 @@ pub use intrinsics::transmute; /// mem::forget(file); /// ``` /// -/// The `mem::swap` function uses `mem::forget` to good effect: +/// The practical use cases for `forget` are rather specialized and mainly come +/// up in unsafe or FFI code. +/// +/// ## Use case 1 +/// +/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. +/// You must either initialize or `forget` it on every computation path before +/// Rust drops it automatically, like at the end of a scope or after a panic. +/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// # let some_condition = false; +/// unsafe { +/// let mut uninit_vec: Vec = mem::uninitialized(); +/// +/// if some_condition { +/// // Initialize the variable. +/// ptr::write(&mut uninit_vec, Vec::new()); +/// } else { +/// // Forget the uninitialized value so its destructor doesn't run. +/// mem::forget(uninit_vec); +/// } +/// } +/// ``` +/// +/// ## Use case 2 +/// +/// You have duplicated the bytes making up a value, without doing a proper +/// [`Clone`][clone]. You need the value's destructor to run only once, +/// because a double `free` is undefined behavior. /// -/// ```rust +/// An example is the definition of [`mem::swap`][swap] in this module: +/// +/// ``` /// use std::mem; /// use std::ptr; /// @@ -109,6 +128,41 @@ pub use intrinsics::transmute; /// } /// } /// ``` +/// +/// ## Use case 3 +/// +/// You are transferring ownership across a [FFI] boundary to code written in +/// another language. You need to `forget` the value on the Rust side because Rust +/// code is no longer responsible for it. +/// +/// ```no_run +/// use std::mem; +/// +/// extern "C" { +/// fn my_c_function(x: *const u32); +/// } +/// +/// let x: Box = Box::new(3); +/// +/// // Transfer ownership into C code. +/// unsafe { +/// my_c_function(&*x); +/// } +/// mem::forget(x); +/// ``` +/// +/// In this case, C code must call back into Rust to free the object. Calling C's `free` +/// function on a [`Box`][box] is *not* safe! Also, `Box` provides an [`into_raw`][into_raw] +/// method which is the preferred way to do this in practice. +/// +/// [drop]: fn.drop.html +/// [uninit]: fn.uninitialized.html +/// [clone]: ../clone/trait.Clone.html +/// [swap]: fn.swap.html +/// [FFI]: ../../book/ffi.html +/// [box]: ../../std/boxed/struct.Box.html +/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [ub]: ../../reference.html#behavior-considered-undefined #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { @@ -133,7 +187,14 @@ pub fn size_of() -> usize { unsafe { intrinsics::size_of::() } } -/// Returns the size of the given value in bytes. +/// Returns the size of the pointed-to value in bytes. +/// +/// This is usually the same as `size_of::()`. However, when `T` *has* no +/// statically known size, e.g. a slice [`[T]`][slice] or a [trait object], +/// then `size_of_val` can be used to get the dynamically-known size. +/// +/// [slice]: ../../std/primitive.slice.html +/// [trait object]: ../../book/trait-objects.html /// /// # Examples /// @@ -141,6 +202,10 @@ pub fn size_of() -> usize { /// use std::mem; /// /// assert_eq!(4, mem::size_of_val(&5i32)); +/// +/// let x: [u8; 13] = [0; 13]; +/// let y: &[u8] = &x; +/// assert_eq!(13, mem::size_of_val(y)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -148,10 +213,14 @@ pub fn size_of_val(val: &T) -> usize { unsafe { intrinsics::size_of_val(val) } } -/// Returns the ABI-required minimum alignment of a type +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// /// # Examples /// /// ``` @@ -167,7 +236,11 @@ pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } -/// Returns the ABI-required minimum alignment of the type of the value that `val` points to +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// /// # Examples /// @@ -184,10 +257,14 @@ pub fn min_align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } -/// Returns the alignment in memory for a type. +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// /// # Examples /// /// ``` @@ -201,7 +278,11 @@ pub fn align_of() -> usize { unsafe { intrinsics::min_align_of::() } } -/// Returns the ABI-required minimum alignment of the type of the value that `val` points to +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// /// # Examples /// @@ -216,16 +297,23 @@ pub fn align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } -/// Creates a value initialized to zero. +/// Creates a value whose bytes are all zero. +/// +/// This has the same effect as allocating space with +/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for +/// [FFI] sometimes, but should generally be avoided. /// -/// This function is similar to allocating space for a local variable and zeroing it out (an unsafe -/// operation). +/// There is no guarantee that an all-zero byte-pattern represents a valid value of +/// some type `T`. If `T` has a destructor and the value is destroyed (due to +/// a panic or the end of a scope) before being initialized, then the destructor +/// will run on zeroed data, likely leading to [undefined behavior][ub]. /// -/// Care must be taken when using this function, if the type `T` has a destructor and the value -/// falls out of scope (due to unwinding or returning) before being initialized, then the -/// destructor will run on zeroed data, likely leading to crashes. +/// See also the documentation for [`mem::uninitialized`][uninit], which has +/// many of the same caveats. /// -/// This is useful for FFI functions sometimes, but should generally be avoided. +/// [uninit]: fn.uninitialized.html +/// [FFI]: ../../book/ffi.html +/// [ub]: ../../reference.html#behavior-considered-undefined /// /// # Examples /// @@ -233,6 +321,7 @@ pub fn align_of_val(val: &T) -> usize { /// use std::mem; /// /// let x: i32 = unsafe { mem::zeroed() }; +/// assert_eq!(0, x); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -241,32 +330,38 @@ pub unsafe fn zeroed() -> T { } /// Bypasses Rust's normal memory-initialization checks by pretending to -/// produce a value of type T, while doing nothing at all. +/// produce a value of type `T`, while doing nothing at all. /// /// **This is incredibly dangerous, and should not be done lightly. Deeply /// consider initializing your memory with a default value instead.** /// -/// This is useful for FFI functions and initializing arrays sometimes, +/// This is useful for [FFI] functions and initializing arrays sometimes, /// but should generally be avoided. /// -/// # Undefined Behavior +/// [FFI]: ../../book/ffi.html /// -/// It is Undefined Behavior to read uninitialized memory. Even just an +/// # Undefined behavior +/// +/// It is [undefined behavior][ub] to read uninitialized memory, even just an /// uninitialized boolean. For instance, if you branch on the value of such -/// a boolean your program may take one, both, or neither of the branches. +/// a boolean, your program may take one, both, or neither of the branches. /// -/// Note that this often also includes *writing* to the uninitialized value. -/// Rust believes the value is initialized, and will therefore try to Drop -/// the uninitialized value and its fields if you try to overwrite the memory -/// in a normal manner. The only way to safely initialize an arbitrary -/// uninitialized value is with one of the `ptr` functions: `write`, `copy`, or -/// `copy_nonoverlapping`. This isn't necessary if `T` is a primitive -/// or otherwise only contains types that don't implement Drop. +/// Writing to the uninitialized value is similarly dangerous. Rust believes the +/// value is initialized, and will therefore try to [`Drop`][drop] the uninitialized +/// value and its fields if you try to overwrite it in a normal manner. The only way +/// to safely initialize an uninitialized value is with [`ptr::write`][write], +/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. /// -/// If this value *does* need some kind of Drop, it must be initialized before +/// If the value does implement `Drop`, it must be initialized before /// it goes out of scope (and therefore would be dropped). Note that this /// includes a `panic` occurring and unwinding the stack suddenly. /// +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [write]: ../ptr/fn.write.html +/// [copy]: ../intrinsics/fn.copy.html +/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html +/// [drop]: ../ops/trait.Drop.html +/// /// # Examples /// /// Here's how to safely initialize an array of `Vec`s. @@ -309,8 +404,8 @@ pub unsafe fn zeroed() -> T { /// println!("{:?}", &data[0]); /// ``` /// -/// This example emphasizes exactly how delicate and dangerous doing this is. -/// Note that the `vec!` macro *does* let you initialize every element with a +/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` +/// can be. Note that the `vec!` macro *does* let you initialize every element with a /// value that is only `Clone`, so the following is semantically equivalent and /// vastly less dangerous, as long as you can live with an extra heap /// allocation: @@ -325,21 +420,20 @@ pub unsafe fn uninitialized() -> T { intrinsics::uninit() } -/// Swap the values at two mutable locations of the same type, without deinitializing or copying -/// either one. +/// Swaps the values at two mutable locations, without deinitializing either one. /// /// # Examples /// /// ``` /// use std::mem; /// -/// let x = &mut 5; -/// let y = &mut 42; +/// let mut x = 5; +/// let mut y = 42; /// -/// mem::swap(x, y); +/// mem::swap(&mut x, &mut y); /// -/// assert_eq!(42, *x); -/// assert_eq!(5, *y); +/// assert_eq!(42, x); +/// assert_eq!(5, y); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -361,10 +455,7 @@ pub fn swap(x: &mut T, y: &mut T) { } /// Replaces the value at a mutable location with a new one, returning the old value, without -/// deinitializing or copying either one. -/// -/// This is primarily used for transferring and swapping ownership of a value in a mutable -/// location. +/// deinitializing either one. /// /// # Examples /// @@ -373,15 +464,17 @@ pub fn swap(x: &mut T, y: &mut T) { /// ``` /// use std::mem; /// -/// let mut v: Vec = Vec::new(); +/// let mut v: Vec = vec![1, 2]; /// -/// mem::replace(&mut v, Vec::new()); +/// let old_v = mem::replace(&mut v, vec![3, 4, 5]); +/// assert_eq!(2, old_v.len()); +/// assert_eq!(3, v.len()); /// ``` /// -/// This function allows consumption of one field of a struct by replacing it with another value. -/// The normal approach doesn't always work: +/// `replace` allows consumption of a struct field by replacing it with another value. +/// Without `replace` you can run into issues like these: /// -/// ```rust,ignore +/// ```ignore /// struct Buffer { buf: Vec } /// /// impl Buffer { @@ -401,6 +494,7 @@ pub fn swap(x: &mut T, y: &mut T) { /// ``` /// # #![allow(dead_code)] /// use std::mem; +/// /// # struct Buffer { buf: Vec } /// impl Buffer { /// fn get_and_reset(&mut self) -> Vec { @@ -417,14 +511,25 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// While this does call the argument's implementation of `Drop`, it will not -/// release any borrows, as borrows are based on lexical scope. +/// While this does call the argument's implementation of [`Drop`][drop], +/// it will not release any borrows, as borrows are based on lexical scope. /// /// This effectively does nothing for /// [types which implement `Copy`](../../book/ownership.html#copy-types), /// e.g. integers. Such values are copied and _then_ moved into the function, /// so the value persists after this function call. /// +/// This function is not magic; it is literally defined as +/// +/// ``` +/// pub fn drop(_x: T) { } +/// ``` +/// +/// Because `_x` is moved into the function, it is automatically dropped before +/// the function returns. +/// +/// [drop]: ../ops/trait.Drop.html +/// /// # Examples /// /// Basic usage: @@ -461,8 +566,8 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// v.push(4); // no problems /// ``` /// -/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can -/// seemingly release a borrow of one: +/// Since `RefCell` enforces the borrow rules at runtime, `drop` can +/// release a `RefCell` borrow: /// /// ``` /// use std::cell::RefCell; @@ -478,7 +583,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("{}", *borrow); /// ``` /// -/// Integers and other types implementing `Copy` are unaffected by `drop()` +/// Integers and other types implementing `Copy` are unaffected by `drop`. /// /// ``` /// #[derive(Copy, Clone)] @@ -496,19 +601,22 @@ pub fn replace(dest: &mut T, mut src: T) -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) { } -/// Interprets `src` as `&U`, and then reads `src` without moving the contained -/// value. +/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// the contained value. /// /// This function will unsafely assume the pointer `src` is valid for -/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It -/// will also unsafely create a copy of the contained value instead of moving -/// out of `src`. +/// [`size_of::()`][size_of] bytes by transmuting `&T` to `&U` and then reading +/// the `&U`. It will also unsafely create a copy of the contained value instead of +/// moving out of `src`. /// /// It is not a compile-time error if `T` and `U` have different sizes, but it /// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers undefined behavior if `U` is larger than +/// same size. This function triggers [undefined behavior][ub] if `U` is larger than /// `T`. /// +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [size_of]: fn.size_of.html +/// /// # Examples /// /// ``` From 62cb7510ac6285c93ec691198a92f910582d31a2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 655/768] Improve `Eq` deriving --- src/libcore/cmp.rs | 13 ++++- src/libsyntax/ext/build.rs | 18 ++++++ src/libsyntax_ext/deriving/clone.rs | 15 +---- src/libsyntax_ext/deriving/cmp/eq.rs | 55 ++++++++++++------- .../compile-fail/union/union-derive-eq.rs | 30 ++++++++++ src/test/compile-fail/union/union-derive.rs | 1 - src/test/run-pass/union/union-derive.rs | 13 ++++- 7 files changed, 109 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/union/union-derive-eq.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 670978a2d49af..f990a27e52b31 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -129,7 +129,7 @@ pub trait PartialEq { /// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has /// no extra methods, it is only informing the compiler that this is an /// equivalence relation rather than a partial equivalence relation. Note that -/// the `derive` strategy requires all fields are `PartialEq`, which isn't +/// the `derive` strategy requires all fields are `Eq`, which isn't /// always desired. /// /// ## How can I implement `Eq`? @@ -165,6 +165,17 @@ pub trait Eq: PartialEq { fn assert_receiver_is_total_eq(&self) {} } +// FIXME: this struct is used solely by #[derive] to +// assert that every component of a type implements Eq. +// +// This struct should never appear in user code. +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[unstable(feature = "derive_eq", + reason = "deriving hack, should not be public", + issue = "0")] +pub struct AssertParamIsEq { _field: ::marker::PhantomData } + /// An `Ordering` is the result of a comparison between two values. /// /// # Examples diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 3dcdbc8909627..b81d95a6998c3 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -97,6 +97,7 @@ pub trait AstBuilder { typ: P, ex: P) -> P; + fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt; fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt; // blocks @@ -577,6 +578,23 @@ impl<'a> AstBuilder for ExtCtxt<'a> { }) } + // Generate `let _: Type;`, usually used for type assertions. + fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt { + let local = P(ast::Local { + pat: self.pat_wild(span), + ty: Some(ty), + init: None, + id: ast::DUMMY_NODE_ID, + span: span, + attrs: ast::ThinVec::new(), + }); + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: span, + } + } + fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index aa7c2c301dd7a..d7bc2a6faeeb9 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -115,20 +115,7 @@ fn cs_clone_shallow(name: &str, let assert_path = cx.path_all(span, true, cx.std_path(&["clone", helper_name]), vec![], vec![ty], vec![]); - let local = P(ast::Local { - pat: cx.pat_wild(span), - ty: Some(cx.ty_path(assert_path)), - init: None, - id: ast::DUMMY_NODE_ID, - span: span, - attrs: ast::ThinVec::new(), - }); - let stmt = ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Local(local), - span: span, - }; - stmts.push(stmt); + stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); } fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec, variant: &VariantData) { for field in variant.fields() { diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 425a47a991bc4..fa0fb2492c551 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -11,7 +11,7 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{Expr, MetaItem}; +use syntax::ast::{self, Expr, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; @@ -23,22 +23,6 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)) { - fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method(|cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") - }), - cx, - span, - substr) - } - let inline = cx.meta_word(span, InternedString::new("inline")); let hidden = cx.meta_list_item_word(span, InternedString::new("hidden")); let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]); @@ -50,7 +34,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - supports_unions: false, + supports_unions: true, methods: vec![MethodDef { name: "assert_receiver_is_total_eq", generics: LifetimeBounds::empty(), @@ -66,5 +50,38 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, }], associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand_ext(cx, mitem, item, push, true) +} + +fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { + fn assert_ty_bounds(cx: &mut ExtCtxt, stmts: &mut Vec, + ty: P, span: Span, helper_name: &str) { + // Generate statement `let _: helper_name;`, + // set the expn ID so we can use the unstable struct. + let span = super::allow_unstable(cx, span, "derive(Eq)"); + let assert_path = cx.path_all(span, true, + cx.std_path(&["cmp", helper_name]), + vec![], vec![ty], vec![]); + stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); + } + fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec, variant: &ast::VariantData) { + for field in variant.fields() { + // let _: AssertParamIsEq; + assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsEq"); + } + } + + let mut stmts = Vec::new(); + match *substr.fields { + StaticStruct(vdata, ..) => { + process_variant(cx, &mut stmts, vdata); + } + StaticEnum(enum_def, ..) => { + for variant in &enum_def.variants { + process_variant(cx, &mut stmts, &variant.node.data); + } + } + _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`") + } + cx.expr_block(cx.block(trait_span, stmts)) } diff --git a/src/test/compile-fail/union/union-derive-eq.rs b/src/test/compile-fail/union/union-derive-eq.rs new file mode 100644 index 0000000000000..9dfec288c1572 --- /dev/null +++ b/src/test/compile-fail/union/union-derive-eq.rs @@ -0,0 +1,30 @@ +// 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. + +#![feature(untagged_unions)] + +#[derive(Eq)] // OK +union U1 { + a: u8, +} + +impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } } + +#[derive(PartialEq)] +struct PartialEqNotEq; + +#[derive(Eq)] +union U2 { + a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied +} + +impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } } + +fn main() {} diff --git a/src/test/compile-fail/union/union-derive.rs b/src/test/compile-fail/union/union-derive.rs index 01ce9696284df..26dbdfd0b4118 100644 --- a/src/test/compile-fail/union/union-derive.rs +++ b/src/test/compile-fail/union/union-derive.rs @@ -14,7 +14,6 @@ #[derive( PartialEq, //~ ERROR this trait cannot be derived for unions - Eq, //~ ERROR this trait cannot be derived for unions PartialOrd, //~ ERROR this trait cannot be derived for unions Ord, //~ ERROR this trait cannot be derived for unions Hash, //~ ERROR this trait cannot be derived for unions diff --git a/src/test/run-pass/union/union-derive.rs b/src/test/run-pass/union/union-derive.rs index 8314416e2b10a..8ff6f17394f9e 100644 --- a/src/test/run-pass/union/union-derive.rs +++ b/src/test/run-pass/union/union-derive.rs @@ -15,22 +15,33 @@ #[derive( Copy, Clone, + Eq, )] union U { a: u8, b: u16, } -#[derive(Clone, Copy)] +impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } } + +#[derive( + Clone, + Copy, + Eq +)] union W { a: T, } +impl PartialEq for W { fn eq(&self, rhs: &Self) -> bool { true } } + fn main() { let u = U { b: 0 }; let u1 = u; let u2 = u.clone(); + assert!(u1 == u2); let w = W { a: 0 }; let w1 = w.clone(); + assert!(w == w1); } From f647db4c8a8e6e49aac60e973044b6556af5a3ad Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Sat, 10 Sep 2016 13:22:19 -0700 Subject: [PATCH 656/768] Update E0297 to new error format --- src/librustc_const_eval/check_match.rs | 7 +++++-- src/test/compile-fail/E0297.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index da4445ef68947..a1e7d0a1e34de 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -410,10 +410,13 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, }, _ => bug!(), }; - span_err!(cx.tcx.sess, sp, E0297, + let pattern_string = pat_to_string(witness); + struct_span_err!(cx.tcx.sess, sp, E0297, "refutable pattern in `for` loop binding: \ `{}` not covered", - pat_to_string(witness)); + pattern_string) + .span_label(sp, &format!("pattern `{}` not covered", pattern_string)) + .emit(); }, _ => { let pattern_strings: Vec<_> = witnesses.iter().map(|w| { diff --git a/src/test/compile-fail/E0297.rs b/src/test/compile-fail/E0297.rs index 43166c1a9e83e..32c129b22a166 100644 --- a/src/test/compile-fail/E0297.rs +++ b/src/test/compile-fail/E0297.rs @@ -11,5 +11,7 @@ fn main() { let xs : Vec> = vec!(Some(1), None); - for Some(x) in xs {} //~ ERROR E0297 + for Some(x) in xs {} + //~^ ERROR E0297 + //~| NOTE pattern `None` not covered } From 3d289278ee123a67827c2b8bbff053d904d7373a Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:07:31 +0200 Subject: [PATCH 657/768] Improve Clone doc --- src/libcore/clone.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 748bb62a1f3eb..69355c6c6cc0b 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -14,10 +14,14 @@ //! assign them or pass them as arguments, the receiver will get a copy, //! leaving the original value in place. These types do not require //! allocation to copy and do not have finalizers (i.e. they do not -//! contain owned boxes or implement `Drop`), so the compiler considers +//! contain owned boxes or implement [`Drop`]), so the compiler considers //! them cheap and safe to copy. For other types copies must be made -//! explicitly, by convention implementing the `Clone` trait and calling -//! the `clone` method. +//! explicitly, by convention implementing the [`Clone`] trait and calling +//! the [`clone`][clone] method. +//! +//! [`Clone`]: trait.Clone.html +//! [clone]: trait.Clone.html#tymethod.clone +//! [`Drop`]: ../../std/ops/trait.Drop.html //! //! Basic usage example: //! @@ -46,22 +50,22 @@ /// A common trait for the ability to explicitly duplicate an object. /// -/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while +/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while /// `Clone` is always explicit and may or may not be expensive. In order to enforce -/// these characteristics, Rust does not allow you to reimplement `Copy`, but you +/// these characteristics, Rust does not allow you to reimplement [`Copy`], but you /// may reimplement `Clone` and run arbitrary code. /// -/// Since `Clone` is more general than `Copy`, you can automatically make anything -/// `Copy` be `Clone` as well. +/// Since `Clone` is more general than [`Copy`], you can automatically make anything +/// [`Copy`] be `Clone` as well. /// /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of `clone()` calls `clone()` on each field. +/// implementation of [`clone()`] calls [`clone()`] on each field. /// /// ## How can I implement `Clone`? /// -/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally: +/// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally: /// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`. /// Manual implementations should be careful to uphold this invariant; however, unsafe code /// must not rely on it to ensure memory safety. @@ -70,6 +74,9 @@ /// library only implements `Clone` up until arrays of size 32. In this case, the implementation of /// `Clone` cannot be `derive`d, but can be implemented as: /// +/// [`Copy`]: ../../std/marker/trait.Copy.html +/// [`clone()`]: trait.Clone.html#tymethod.clone +/// /// ``` /// #[derive(Copy)] /// struct Stats { From 48dc0ba307abe4e0abdc16db7ebc5915bf813f01 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:07:44 +0200 Subject: [PATCH 658/768] Improve Copy trait doc --- src/libcore/marker.rs | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 0a46813df7eb8..c22c9f0d1c717 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -126,7 +126,7 @@ pub trait Unsize { /// } /// ``` /// -/// The `PointList` `struct` cannot implement `Copy`, because `Vec` is not `Copy`. If we +/// The `PointList` `struct` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we /// attempt to derive a `Copy` implementation, we'll get an error: /// /// ```text @@ -136,10 +136,10 @@ pub trait Unsize { /// ## When can my type _not_ be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference, and copying `String` would result in two attempts to free the same buffer. +/// mutable reference, and copying [`String`] would result in two attempts to free the same buffer. /// -/// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's -/// managing some resource besides its own `size_of::()` bytes. +/// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's +/// managing some resource besides its own [`size_of::()`] bytes. /// /// ## What if I derive `Copy` on a type that can't? /// @@ -156,8 +156,7 @@ pub trait Unsize { /// /// ## Derivable /// -/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type -/// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`. +/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type. /// /// ## How can I implement `Copy`? /// @@ -178,6 +177,11 @@ pub trait Unsize { /// /// There is a small difference between the two: the `derive` strategy will also place a `Copy` /// bound on type parameters, which isn't always desired. +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`String`]: ../../std/string/struct.String.html +/// [`Drop`]: ../../std/ops/trait.Drop.html +/// [`size_of::()`]: ../../std/mem/fn.size_of.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { @@ -190,11 +194,11 @@ pub trait Copy : Clone { /// thread-safe. In other words, there is no possibility of data races /// when passing `&T` references between threads. /// -/// As one would expect, primitive types like `u8` and `f64` are all +/// As one would expect, primitive types like [`u8`] and [`f64`] are all /// `Sync`, and so are simple aggregate types containing them (like /// tuples, structs and enums). More instances of basic `Sync` types /// include "immutable" types like `&T` and those with simple -/// inherited mutability, such as `Box`, `Vec` and most other +/// inherited mutability, such as [`Box`], [`Vec`] and most other /// collection types. (Generic parameters need to be `Sync` for their /// container to be `Sync`.) /// @@ -206,27 +210,42 @@ pub trait Copy : Clone { /// race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe way, such as `Cell` and `RefCell` -/// in `std::cell`. These types allow for mutation of their contents +/// mutability" in a non-thread-safe way, such as [`Cell`] and [`RefCell`] +/// in [`std::cell`]. These types allow for mutation of their contents /// even when in an immutable, aliasable slot, e.g. the contents of -/// `&Cell` can be `.set`, and do not ensure data races are +/// [`&Cell`][`Cell`] can be [`.set`], and do not ensure data races are /// impossible, hence they cannot be `Sync`. A higher level example /// of a non-`Sync` type is the reference counted pointer -/// `std::rc::Rc`, because any reference `&Rc` can clone a new +/// [`std::rc::Rc`][`Rc`], because any reference [`&Rc`][`Rc`] can clone a new /// reference, which modifies the reference counts in a non-atomic /// way. /// /// For cases when one does need thread-safe interior mutability, -/// types like the atomics in `std::sync` and `Mutex` & `RWLock` in -/// the `sync` crate do ensure that any mutation cannot cause data +/// types like the atomics in [`std::sync`][`sync`] and [`Mutex`] / [`RwLock`] in +/// the [`sync`] crate do ensure that any mutation cannot cause data /// races. Hence these types are `Sync`. /// -/// Any types with interior mutability must also use the `std::cell::UnsafeCell` +/// Any types with interior mutability must also use the [`std::cell::UnsafeCell`] /// wrapper around the value(s) which can be mutated when behind a `&` /// reference; not doing this is undefined behavior (for example, -/// `transmute`-ing from `&T` to `&mut T` is invalid). +/// [`transmute`]-ing from `&T` to `&mut T` is invalid). /// /// This trait is automatically derived when the compiler determines it's appropriate. +/// +/// [`u8`]: ../../std/primitive.u8.html +/// [`f64`]: ../../std/primitive.f64.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`std::cell`]: ../../std/cell/index.html +/// [`.set`]: ../../std/cell/struct.Cell.html#method.set +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [`sync`]: ../../std/sync/index.html +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`RwLock`]: ../../std/sync/struct.RwLock.html +/// [`std::cell::UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html +/// [`transmute`]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] From 57a603795160250de09dd4e3634c099a2d76fb58 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:07:56 +0200 Subject: [PATCH 659/768] Improve Option doc --- src/libcore/option.rs | 78 +++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cf52849e01972..dacb396ee4028 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -10,9 +10,9 @@ //! Optional values. //! -//! Type `Option` represents an optional value: every `Option` -//! is either `Some` and contains a value, or `None`, and -//! does not. `Option` types are very common in Rust code, as +//! Type [`Option`] represents an optional value: every [`Option`] +//! is either [`Some`] and contains a value, or [`None`], and +//! does not. [`Option`] types are very common in Rust code, as //! they have a number of uses: //! //! * Initial values @@ -26,8 +26,8 @@ //! * Nullable pointers //! * Swapping things out of difficult situations //! -//! Options are commonly paired with pattern matching to query the presence -//! of a value and take action, always accounting for the `None` case. +//! [`Option`]s are commonly paired with pattern matching to query the presence +//! of a value and take action, always accounting for the [`None`] case. //! //! ``` //! fn divide(numerator: f64, denominator: f64) -> Option { @@ -57,13 +57,13 @@ //! //! Rust's pointer types must always point to a valid location; there are //! no "null" pointers. Instead, Rust has *optional* pointers, like -//! the optional owned box, `Option>`. +//! the optional owned box, [`Option`]`<`[`Box`]`>`. //! -//! The following example uses `Option` to create an optional box of -//! `i32`. Notice that in order to use the inner `i32` value first the +//! The following example uses [`Option`] to create an optional box of +//! [`i32`]. Notice that in order to use the inner [`i32`] value first the //! `check_optional` function needs to use pattern matching to -//! determine whether the box has a value (i.e. it is `Some(...)`) or -//! not (`None`). +//! determine whether the box has a value (i.e. it is [`Some(...)`][`Some`]) or +//! not ([`None`]). //! //! ``` //! let optional: Option> = None; @@ -80,14 +80,14 @@ //! } //! ``` //! -//! This usage of `Option` to create safe nullable pointers is so +//! This usage of [`Option`] to create safe nullable pointers is so //! common that Rust does special optimizations to make the -//! representation of `Option>` a single pointer. Optional pointers +//! representation of [`Option`]`<`[`Box`]`>` a single pointer. Optional pointers //! in Rust are stored as efficiently as any other pointer type. //! //! # Examples //! -//! Basic pattern matching on `Option`: +//! Basic pattern matching on [`Option`]: //! //! ``` //! let msg = Some("howdy"); @@ -101,7 +101,7 @@ //! let unwrapped_msg = msg.unwrap_or("default message"); //! ``` //! -//! Initialize a result to `None` before a loop: +//! Initialize a result to [`None`] before a loop: //! //! ``` //! enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) } @@ -136,6 +136,12 @@ //! None => println!("there are no animals :("), //! } //! ``` +//! +//! [`Option`]: enum.Option.html +//! [`Some`]: enum.Option.html#variant.Some +//! [`None`]: enum.Option.html#variant.None +//! [`Box`]: ../../std/boxed/struct.Box.html +//! [`i32`]: ../../std/primitive.i32.html #![stable(feature = "rust1", since = "1.0.0")] @@ -156,7 +162,7 @@ pub enum Option { None, /// Some value `T` #[stable(feature = "rust1", since = "1.0.0")] - Some(#[stable(feature = "rust1", since = "1.0.0")] T) + Some(#[stable(feature = "rust1", since = "1.0.0")] T), } ///////////////////////////////////////////////////////////////////////////// @@ -168,7 +174,7 @@ impl Option { // Querying the contained values ///////////////////////////////////////////////////////////////////////// - /// Returns `true` if the option is a `Some` value + /// Returns `true` if the option is a `Some` value. /// /// # Examples /// @@ -188,7 +194,7 @@ impl Option { } } - /// Returns `true` if the option is a `None` value + /// Returns `true` if the option is a `None` value. /// /// # Examples /// @@ -209,15 +215,17 @@ impl Option { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Converts from `Option` to `Option<&T>` + /// Converts from `Option` to `Option<&T>`. /// /// # Examples /// /// Convert an `Option` into an `Option`, preserving the original. - /// The `map` method takes the `self` argument by value, consuming the original, + /// The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. /// + /// [`map`]: enum.Option.html#method.map + /// /// ``` /// let num_as_str: Option = Some("10".to_string()); /// // First, cast `Option` to `Option<&String>` with `as_ref`, @@ -234,7 +242,7 @@ impl Option { } } - /// Converts from `Option` to `Option<&mut T>` + /// Converts from `Option` to `Option<&mut T>`. /// /// # Examples /// @@ -357,7 +365,7 @@ impl Option { // Transforming contained values ///////////////////////////////////////////////////////////////////////// - /// Maps an `Option` to `Option` by applying a function to a contained value + /// Maps an `Option` to `Option` by applying a function to a contained value. /// /// # Examples /// @@ -423,8 +431,12 @@ impl Option { } } - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to - /// `Ok(v)` and `None` to `Err(err)`. + /// Transforms the `Option` into a [`Result`], mapping `Some(v)` to + /// [`Ok(v)`] and `None` to [`Err(err)`][Err]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [Err]: ../../std/result/enum.Result.html#variant.Err /// /// # Examples /// @@ -444,8 +456,12 @@ impl Option { } } - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to - /// `Ok(v)` and `None` to `Err(err())`. + /// Transforms the `Option` into a [`Result`], mapping `Some(v)` to + /// [`Ok(v)`] and `None` to [`Err(err())`][Err]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [Err]: ../../std/result/enum.Result.html#variant.Err /// /// # Examples /// @@ -789,7 +805,9 @@ impl DoubleEndedIterator for Item { impl ExactSizeIterator for Item {} impl FusedIterator for Item {} -/// An iterator over a reference of the contained item in an Option. +/// An iterator over a reference of the contained item in an [`Option`]. +/// +/// [`Option`]: enum.Option.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } @@ -823,7 +841,9 @@ impl<'a, A> Clone for Iter<'a, A> { } } -/// An iterator over a mutable reference of the contained item in an Option. +/// An iterator over a mutable reference of the contained item in an [`Option`]. +/// +/// [`Option`]: enum.Option.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } @@ -850,7 +870,9 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, A> FusedIterator for IterMut<'a, A> {} -/// An iterator over the item contained inside an Option. +/// An iterator over the item contained inside an [`Option`]. +/// +/// [`Option`]: enum.Option.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { inner: Item } From e3153cfd8896d97be89e3b1b26e44a3ebf8a6374 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:08:04 +0200 Subject: [PATCH 660/768] Improve Result doc --- src/libcore/result.rs | 95 +++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 94b6d5fa0031a..96845259299be 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -10,9 +10,9 @@ //! Error handling with the `Result` type. //! -//! `Result` is the type used for returning and propagating -//! errors. It is an enum with the variants, `Ok(T)`, representing -//! success and containing a value, and `Err(E)`, representing error +//! [`Result`][`Result`] is the type used for returning and propagating +//! errors. It is an enum with the variants, [`Ok(T)`], representing +//! success and containing a value, and [`Err(E)`], representing error //! and containing an error value. //! //! ``` @@ -23,11 +23,11 @@ //! } //! ``` //! -//! Functions return `Result` whenever errors are expected and -//! recoverable. In the `std` crate `Result` is most prominently used +//! Functions return [`Result`] whenever errors are expected and +//! recoverable. In the `std` crate, [`Result`] is most prominently used //! for [I/O](../../std/io/index.html). //! -//! A simple function returning `Result` might be +//! A simple function returning [`Result`] might be //! defined and used like so: //! //! ``` @@ -50,8 +50,8 @@ //! } //! ``` //! -//! Pattern matching on `Result`s is clear and straightforward for -//! simple cases, but `Result` comes with some convenience methods +//! Pattern matching on [`Result`]s is clear and straightforward for +//! simple cases, but [`Result`] comes with some convenience methods //! that make working with it more succinct. //! //! ``` @@ -80,14 +80,14 @@ //! //! A common problem with using return values to indicate errors is //! that it is easy to ignore the return value, thus failing to handle -//! the error. Result is annotated with the #[must_use] attribute, +//! the error. [`Result`] is annotated with the `#[must_use]` attribute, //! which will cause the compiler to issue a warning when a Result -//! value is ignored. This makes `Result` especially useful with +//! value is ignored. This makes [`Result`] especially useful with //! functions that may encounter errors but don't otherwise return a //! useful value. //! -//! Consider the `write_all` method defined for I/O types -//! by the [`Write`](../../std/io/trait.Write.html) trait: +//! Consider the [`write_all`] method defined for I/O types +//! by the [`Write`] trait: //! //! ``` //! use std::io; @@ -97,8 +97,8 @@ //! } //! ``` //! -//! *Note: The actual definition of `Write` uses `io::Result`, which -//! is just a synonym for `Result`.* +//! *Note: The actual definition of [`Write`] uses [`io::Result`], which +//! is just a synonym for [`Result`]``.* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write @@ -119,7 +119,7 @@ //! warning (by default, controlled by the `unused_must_use` lint). //! //! You might instead, if you don't want to handle the error, simply -//! assert success with `expect`. This will panic if the +//! assert success with [`expect`]. This will panic if the //! write fails, providing a marginally useful message indicating why: //! //! ```{.no_run} @@ -139,7 +139,7 @@ //! assert!(file.write_all(b"important message").is_ok()); //! ``` //! -//! Or propagate the error up the call stack with `try!`: +//! Or propagate the error up the call stack with [`try!`]: //! //! ``` //! # use std::fs::File; @@ -156,7 +156,7 @@ //! # The `try!` macro //! //! When writing code that calls many functions that return the -//! `Result` type, the error handling can be tedious. The `try!` +//! [`Result`] type, the error handling can be tedious. The [`try!`] //! macro hides some of the boilerplate of propagating errors up the //! call stack. //! @@ -219,9 +219,9 @@ //! //! *It's much nicer!* //! -//! Wrapping an expression in `try!` will result in the unwrapped -//! success (`Ok`) value, unless the result is `Err`, in which case -//! `Err` is returned early from the enclosing function. Its simple definition +//! Wrapping an expression in [`try!`] will result in the unwrapped +//! success ([`Ok`]) value, unless the result is [`Err`], in which case +//! [`Err`] is returned early from the enclosing function. Its simple definition //! makes it clear: //! //! ``` @@ -230,9 +230,21 @@ //! } //! ``` //! -//! `try!` is imported by the prelude and is available everywhere, but it can only -//! be used in functions that return `Result` because of the early return of -//! `Err` that it provides. +//! [`try!`] is imported by the prelude and is available everywhere, but it can only +//! be used in functions that return [`Result`] because of the early return of +//! [`Err`] that it provides. +//! +//! [`expect`]: enum.Result.html#method.expect +//! [`Write`]: ../../std/io/trait.Write.html +//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all +//! [`io::Result`]: ../../std/io/type.Result.html +//! [`try!`]: ../../std/macro.try.html +//! [`Result`]: enum.Result.html +//! [`Ok(T)`]: enum.Result.html#variant.Ok +//! [`Err(E)`]: enum.Result.html#variant.Err +//! [`io::Error`]: ../../std/io/struct.Error.html +//! [`Ok`]: enum.Result.html#variant.Ok +//! [`Err`]: enum.Result.html#variant.Err #![stable(feature = "rust1", since = "1.0.0")] @@ -264,7 +276,7 @@ impl Result { // Querying the contained values ///////////////////////////////////////////////////////////////////////// - /// Returns true if the result is `Ok` + /// Returns true if the result is `Ok`. /// /// # Examples /// @@ -286,7 +298,7 @@ impl Result { } } - /// Returns true if the result is `Err` + /// Returns true if the result is `Err`. /// /// # Examples /// @@ -309,11 +321,13 @@ impl Result { // Adapter for each variant ///////////////////////////////////////////////////////////////////////// - /// Converts from `Result` to `Option` + /// Converts from `Result` to [`Option`]. /// - /// Converts `self` into an `Option`, consuming `self`, + /// Converts `self` into an [`Option`], consuming `self`, /// and discarding the error, if any. /// + /// [`Option`]: ../../std/option/enum.Option.html + /// /// # Examples /// /// Basic usage: @@ -334,11 +348,13 @@ impl Result { } } - /// Converts from `Result` to `Option` + /// Converts from `Result` to [`Option`]. /// - /// Converts `self` into an `Option`, consuming `self`, + /// Converts `self` into an [`Option`], consuming `self`, /// and discarding the success value, if any. /// + /// [`Option`]: ../../std/option/enum.Option.html + /// /// # Examples /// /// Basic usage: @@ -363,7 +379,7 @@ impl Result { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Converts from `Result` to `Result<&T, &E>` + /// Converts from `Result` to `Result<&T, &E>`. /// /// Produces a new `Result`, containing a reference /// into the original, leaving the original in place. @@ -388,7 +404,7 @@ impl Result { } } - /// Converts from `Result` to `Result<&mut T, &mut E>` + /// Converts from `Result` to `Result<&mut T, &mut E>`. /// /// # Examples /// @@ -563,7 +579,7 @@ impl Result { /// Calls `op` if the result is `Ok`, otherwise returns the `Err` value of `self`. /// - /// This function can be used for control flow based on result values. + /// This function can be used for control flow based on `Result` values. /// /// # Examples /// @@ -646,7 +662,7 @@ impl Result { } /// Unwraps a result, yielding the content of an `Ok`. - /// Else it returns `optb`. + /// Else, it returns `optb`. /// /// # Examples /// @@ -837,7 +853,10 @@ impl<'a, T, E> IntoIterator for &'a mut Result { // The Result Iterators ///////////////////////////////////////////////////////////////////////////// -/// An iterator over a reference to the `Ok` variant of a `Result`. +/// An iterator over a reference to the [`Ok`] variant of a [`Result`]. +/// +/// [`Ok`]: enum.Result.html#variant.Ok +/// [`Result`]: enum.Result.html #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { inner: Option<&'a T> } @@ -872,7 +891,10 @@ impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } } } -/// An iterator over a mutable reference to the `Ok` variant of a `Result`. +/// An iterator over a mutable reference to the [`Ok`] variant of a [`Result`]. +/// +/// [`Ok`]: enum.Result.html#variant.Ok +/// [`Result`]: enum.Result.html #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { inner: Option<&'a mut T> } @@ -902,10 +924,11 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} -/// An iterator over the value in a `Ok` variant of a `Result`. This struct is +/// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is /// created by the [`into_iter`] method on [`Result`][`Result`] (provided by /// the [`IntoIterator`] trait). /// +/// [`Ok`]: enum.Result.html#variant.Ok /// [`Result`]: enum.Result.html /// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter /// [`IntoIterator`]: ../iter/trait.IntoIterator.html From 49e77dbf25ed6526fb5d37c32e55797fb04522f0 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Sun, 11 Sep 2016 17:00:09 +0530 Subject: [PATCH 661/768] Documentation of what does for each type --- src/liballoc/arc.rs | 2 ++ src/liballoc/boxed.rs | 1 + src/liballoc/rc.rs | 1 + src/libcollections/binary_heap.rs | 1 + src/libcollections/borrow.rs | 1 + src/libcollections/btree/map.rs | 1 + src/libcollections/btree/set.rs | 1 + src/libcollections/linked_list.rs | 1 + src/libcollections/string.rs | 1 + src/libcollections/vec.rs | 1 + src/libcollections/vec_deque.rs | 1 + src/libcore/cell.rs | 3 +++ src/libcore/hash/sip.rs | 1 + src/libcore/option.rs | 1 + src/libcore/slice.rs | 2 ++ src/libcore/str/mod.rs | 1 + src/libcore/sync/atomic.rs | 2 ++ src/libcoretest/hash/mod.rs | 2 ++ src/librand/reseeding.rs | 2 ++ src/librustc/session/config.rs | 1 + src/librustc/ty/layout.rs | 1 + src/librustc_data_structures/fnv.rs | 1 + src/librustc_resolve/resolve_imports.rs | 1 + src/libstd/collections/hash/map.rs | 2 ++ src/libstd/collections/hash/set.rs | 1 + src/libstd/ffi/c_str.rs | 1 + src/libstd/ffi/os_str.rs | 2 ++ src/libstd/sync/condvar.rs | 1 + src/libstd/sync/mutex.rs | 1 + src/libstd/sync/rwlock.rs | 1 + src/libsyntax/ast.rs | 1 + src/libsyntax/ptr.rs | 1 + 32 files changed, 41 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index b54b71cabd1e9..a2923091fb559 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -718,6 +718,7 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { + /// Creates a new `Weak`. fn default() -> Weak { Weak::new() } @@ -923,6 +924,7 @@ impl fmt::Pointer for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Arc { + /// Creates a new `Arc`, with the `Default` value for T. fn default() -> Arc { Arc::new(Default::default()) } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 70c429cc3600a..bc9b6e805efc9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -290,6 +290,7 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { + /// Creates a `Box`, with the `Default` value for T. fn default() -> Box { box Default::default() } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c24c7ca47ad05..dadddbc2cb3e5 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -870,6 +870,7 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { + /// Creates a new `Weak`. fn default() -> Weak { Weak::new() } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 0b923468c7416..1fe921543bd4e 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -263,6 +263,7 @@ impl Clone for BinaryHeap { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BinaryHeap { + /// Creates an empty `BinaryHeap`. #[inline] fn default() -> BinaryHeap { BinaryHeap::new() diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 3ad1d08298581..ef136f3356aa4 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -249,6 +249,7 @@ impl<'a, B: ?Sized> Default for Cow<'a, B> where B: ToOwned, ::Owned: Default { + /// Creates a `Cow<'a, B>` pointer. fn default() -> Cow<'a, B> { Owned(::Owned::default()) } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 624083a8eaf35..36cb5a1fd9f6d 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1667,6 +1667,7 @@ impl Hash for BTreeMap { } impl Default for BTreeMap { + /// Creates an empty `BTreeMap`. fn default() -> BTreeMap { BTreeMap::new() } diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 5d7b00f57c83b..24da81c3e937f 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -674,6 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { + /// Creates a new `BTreeSet`. fn default() -> BTreeSet { BTreeSet::new() } diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 769c5162a4560..690c4f4af3589 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -164,6 +164,7 @@ impl LinkedList { #[stable(feature = "rust1", since = "1.0.0")] impl Default for LinkedList { + /// Creates an empty `LinkedList`. #[inline] fn default() -> Self { Self::new() diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 3a304c6292930..773e94f1b414e 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1567,6 +1567,7 @@ impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] impl Default for String { + /// Creates an empty `String`. #[inline] fn default() -> String { String::new() diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 876314613f523..cb1d0de6e5ebc 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1610,6 +1610,7 @@ impl Drop for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Vec { + /// Creates an empty `Vec`. fn default() -> Vec { Vec::new() } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 96624f121b2af..efee4914a1129 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -84,6 +84,7 @@ impl Drop for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Default for VecDeque { + /// Creates a `VecDeque` with a constant initial capacity. #[inline] fn default() -> VecDeque { VecDeque::new() diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index f0710a1d93578..51221f1b9b9e9 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -317,6 +317,7 @@ impl Clone for Cell { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Cell { + /// Creates a `Cell`, with the `Default` value for T. #[inline] fn default() -> Cell { Cell::new(Default::default()) @@ -758,6 +759,7 @@ impl Clone for RefCell { #[stable(feature = "rust1", since = "1.0.0")] impl Default for RefCell { + /// Creates a `RefCell`, with the `Default` value for T. #[inline] fn default() -> RefCell { RefCell::new(Default::default()) @@ -1139,6 +1141,7 @@ impl UnsafeCell { #[stable(feature = "unsafe_cell_default", since = "1.9.0")] impl Default for UnsafeCell { + /// Creates an `UnsafeCell`, with the `Default` value for T. fn default() -> UnsafeCell { UnsafeCell::new(Default::default()) } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index bd6cae92b050c..dc53683d6337c 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -333,6 +333,7 @@ impl Clone for Hasher { } impl Default for Hasher { + /// Creates a `Hasher` with the two initial keys set to 0. #[inline] fn default() -> Hasher { Hasher::new_with_keys(0, 0) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cf52849e01972..4c449c6562e2e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -698,6 +698,7 @@ fn expect_failed(msg: &str) -> ! { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { + /// Creates an instance of None. #[inline] fn default() -> Option { None } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index b22bdb43414fd..53d2b3ded6734 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -755,11 +755,13 @@ impl ops::IndexMut> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Default for &'a [T] { + /// Creates an empty Slice. fn default() -> &'a [T] { &[] } } #[stable(feature = "mut_slice_default", since = "1.5.0")] impl<'a, T> Default for &'a mut [T] { + /// Creates a mutable empty Slice. fn default() -> &'a mut [T] { &mut [] } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 18e43c02c648f..1f1ae6f12ab45 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1987,5 +1987,6 @@ impl AsRef<[u8]> for str { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Default for &'a str { + /// Creates an empty str fn default() -> &'a str { "" } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 75ddd2021a8f7..a5efda702dfae 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -95,6 +95,7 @@ pub struct AtomicBool { #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicBool { + /// Creates an `AtomicBool` initialised as false. fn default() -> Self { Self::new(false) } @@ -117,6 +118,7 @@ pub struct AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicPtr { + /// Creates an `AtomicPtr` with an initial mutable null pointer. fn default() -> AtomicPtr { AtomicPtr::new(::ptr::null_mut()) } diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 4ea42644ecdfd..dec8b57518f2a 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -18,6 +18,7 @@ struct MyHasher { } impl Default for MyHasher { + /// Constructs a `MyHasher` with initial value zero. fn default() -> MyHasher { MyHasher { hash: 0 } } @@ -90,6 +91,7 @@ impl Hasher for CustomHasher { } impl Default for CustomHasher { + /// Constructs a `CustomHasher` with initial value zero. fn default() -> CustomHasher { CustomHasher { output: 0 } } diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index c7d560eb1f8e2..48395c12fafeb 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -113,6 +113,7 @@ impl Reseeder for ReseedWithDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl Default for ReseedWithDefault { + /// Creates an instance of `ReseedWithDefault`. fn default() -> ReseedWithDefault { ReseedWithDefault } @@ -137,6 +138,7 @@ mod tests { } } impl Default for Counter { + /// Constructs a `Counter` with initial value zero. fn default() -> Counter { Counter { i: 0 } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2009e18f6ee20..5708f961adad0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -84,6 +84,7 @@ pub enum ErrorOutputType { } impl Default for ErrorOutputType { + /// Creates an `HumanReadble`, initialised with `ColorConfig` enum type `Auto`. fn default() -> ErrorOutputType { ErrorOutputType::HumanReadable(ColorConfig::Auto) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e3f3da916a0a9..6fec698cfac9b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -45,6 +45,7 @@ pub struct TargetDataLayout { } impl Default for TargetDataLayout { + /// Creates an instance of `TargetDataLayout`. fn default() -> TargetDataLayout { TargetDataLayout { endian: Endian::Big, diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index 47f623266f3b7..ae90c2fac8321 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -35,6 +35,7 @@ pub fn FnvHashSet() -> FnvHashSet { pub struct FnvHasher(u64); impl Default for FnvHasher { + /// Creates a `FnvHasher`, with a 64-bit hex initial value. #[inline] fn default() -> FnvHasher { FnvHasher(0xcbf29ce484222325) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 74f88433b3584..29add1f9b9d49 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -109,6 +109,7 @@ enum SingleImports<'a> { } impl<'a> Default for SingleImports<'a> { + /// Creates a `SingleImports<'a>` of None type. fn default() -> Self { SingleImports::None } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4eb2c8f064414..48c54c16ed850 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1218,6 +1218,7 @@ impl Default for HashMap where K: Eq + Hash, S: BuildHasher + Default, { + /// Creates a `HashMap`, with initial `Default` hasher. fn default() -> HashMap { HashMap::with_hasher(Default::default()) } @@ -2026,6 +2027,7 @@ impl Hasher for DefaultHasher { #[stable(feature = "rust1", since = "1.0.0")] impl Default for RandomState { + /// Constructs a new `RandomState`. #[inline] fn default() -> RandomState { RandomState::new() diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ca5137e957362..b5652bcabf168 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -665,6 +665,7 @@ impl Default for HashSet where T: Eq + Hash, S: BuildHasher + Default, { + /// Creates a `HashSet` with initial `Default` hasher. fn default() -> HashSet { HashSet::with_hasher(Default::default()) } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 38222c014f61b..044112ea1365e 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -339,6 +339,7 @@ impl<'a> Default for &'a CStr { #[stable(feature = "cstr_default", since = "1.10.0")] impl Default for CString { + /// Creates a new `CString`, by calling the `Default` of `CStr`, and then owns it. fn default() -> CString { let a: &CStr = Default::default(); a.to_owned() diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 36cf4ef758d8e..d93d3c7362261 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -170,6 +170,7 @@ impl ops::Deref for OsString { #[stable(feature = "osstring_default", since = "1.9.0")] impl Default for OsString { + /// Constructs an empty `OsString`. #[inline] fn default() -> OsString { OsString::new() @@ -342,6 +343,7 @@ impl OsStr { #[stable(feature = "osstring_default", since = "1.9.0")] impl<'a> Default for &'a OsStr { + /// Creates an empty `OsStr`. #[inline] fn default() -> &'a OsStr { OsStr::new("") diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 4c946e613ea91..3db8b05b954c3 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -241,6 +241,7 @@ impl Condvar { #[stable(feature = "condvar_default", since = "1.9.0")] impl Default for Condvar { + /// Creates a `Condvar` which is ready to be waited on and notified. fn default() -> Condvar { Condvar::new() } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index c8ae88c233106..098a3e44258c7 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -287,6 +287,7 @@ impl Drop for Mutex { #[stable(feature = "mutex_default", since = "1.9.0")] impl Default for Mutex { + /// Creates a `Mutex`, with the `Default` value for T. fn default() -> Mutex { Mutex::new(Default::default()) } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 4801bcffd081c..7f053c6704b56 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -311,6 +311,7 @@ impl fmt::Debug for RwLock { #[stable(feature = "rw_lock_default", since = "1.9.0")] impl Default for RwLock { + /// Creates a new `RwLock`, with the `Default` value for T. fn default() -> RwLock { RwLock::new(Default::default()) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 105f911dd575c..40c8ba93bd5d9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -362,6 +362,7 @@ impl Generics { } impl Default for Generics { + /// Creates an instance of `Generics`. fn default() -> Generics { Generics { lifetimes: Vec::new(), diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index c3f8a977a659b..a65c54ac1e264 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -154,6 +154,7 @@ impl P<[T]> { } impl Default for P<[T]> { + /// Creates a new `P`, with the `Default` value for T. fn default() -> P<[T]> { P::new() } From c8b656bea5e90f1e174bee7e65cbd362914264b3 Mon Sep 17 00:00:00 2001 From: Richard Janis Goldschmidt Date: Sun, 11 Sep 2016 16:48:04 +0200 Subject: [PATCH 662/768] Remove unnecessary `cmp::min` from BufWriter::write The first branch of the if statement already checks if `buf.len() >= self.buf.capacity()`, which makes the `cmp::min(buf.len(), self.buf.capacity())` redundant: the result will always be `buf.len()`. Therefore, we can pass the `buf` slice directly into `Write::write`. --- src/libstd/io/buffered.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a26a932ad2de6..dbb45d54f38d1 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -468,8 +468,7 @@ impl Write for BufWriter { self.panicked = false; r } else { - let amt = cmp::min(buf.len(), self.buf.capacity()); - Write::write(&mut self.buf, &buf[..amt]) + Write::write(&mut self.buf, buf) } } fn flush(&mut self) -> io::Result<()> { From 41881e85bd832127f2a6eee5821eaae353dea281 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Sun, 11 Sep 2016 22:58:01 +0530 Subject: [PATCH 663/768] Documentation for default types modified --- src/liballoc/arc.rs | 2 +- src/libcollections/borrow.rs | 2 +- src/libcollections/btree/set.rs | 2 +- src/libcollections/vec_deque.rs | 2 +- src/libcore/option.rs | 2 +- src/libcore/slice.rs | 4 ++-- src/libcore/sync/atomic.rs | 2 +- src/libcoretest/hash/mod.rs | 2 -- src/librustc/session/config.rs | 1 - src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/set.rs | 2 +- src/libstd/ffi/c_str.rs | 2 +- src/libsyntax/ptr.rs | 2 +- 13 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index a2923091fb559..3d579641b9658 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -718,7 +718,7 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Creates a new `Weak`. + /// Constructs a new `Weak` without an accompanying instance of T. fn default() -> Weak { Weak::new() } diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index ef136f3356aa4..700f88dc0f267 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -249,7 +249,7 @@ impl<'a, B: ?Sized> Default for Cow<'a, B> where B: ToOwned, ::Owned: Default { - /// Creates a `Cow<'a, B>` pointer. + /// Creates an owned Cow<'a, B> with the default value for the contained owned value. fn default() -> Cow<'a, B> { Owned(::Owned::default()) } diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 24da81c3e937f..49da3aa480c31 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -674,7 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Creates a new `BTreeSet`. + /// Makes a empty `BTreeSet` with a reasonable choice of B. fn default() -> BTreeSet { BTreeSet::new() } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index efee4914a1129..2e561dabb4794 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -84,7 +84,7 @@ impl Drop for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Default for VecDeque { - /// Creates a `VecDeque` with a constant initial capacity. + /// Creates an empty `VecDeque`. #[inline] fn default() -> VecDeque { VecDeque::new() diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 4c449c6562e2e..7733b90ec01a8 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -698,7 +698,7 @@ fn expect_failed(msg: &str) -> ! { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { - /// Creates an instance of None. + /// Returns None. #[inline] fn default() -> Option { None } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 53d2b3ded6734..7b147faccd20f 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -755,13 +755,13 @@ impl ops::IndexMut> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Default for &'a [T] { - /// Creates an empty Slice. + /// Creates an empty slice. fn default() -> &'a [T] { &[] } } #[stable(feature = "mut_slice_default", since = "1.5.0")] impl<'a, T> Default for &'a mut [T] { - /// Creates a mutable empty Slice. + /// Creates a mutable empty slice. fn default() -> &'a mut [T] { &mut [] } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index a5efda702dfae..f5f37be52de6e 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -118,7 +118,7 @@ pub struct AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicPtr { - /// Creates an `AtomicPtr` with an initial mutable null pointer. + /// Creates a null `AtomicPtr`. fn default() -> AtomicPtr { AtomicPtr::new(::ptr::null_mut()) } diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index dec8b57518f2a..4ea42644ecdfd 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -18,7 +18,6 @@ struct MyHasher { } impl Default for MyHasher { - /// Constructs a `MyHasher` with initial value zero. fn default() -> MyHasher { MyHasher { hash: 0 } } @@ -91,7 +90,6 @@ impl Hasher for CustomHasher { } impl Default for CustomHasher { - /// Constructs a `CustomHasher` with initial value zero. fn default() -> CustomHasher { CustomHasher { output: 0 } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5708f961adad0..2009e18f6ee20 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -84,7 +84,6 @@ pub enum ErrorOutputType { } impl Default for ErrorOutputType { - /// Creates an `HumanReadble`, initialised with `ColorConfig` enum type `Auto`. fn default() -> ErrorOutputType { ErrorOutputType::HumanReadable(ColorConfig::Auto) } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 48c54c16ed850..eb1653f18cba1 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1218,7 +1218,7 @@ impl Default for HashMap where K: Eq + Hash, S: BuildHasher + Default, { - /// Creates a `HashMap`, with initial `Default` hasher. + /// Creates an empty `HashMap`, with the `Default` value for the hasher. fn default() -> HashMap { HashMap::with_hasher(Default::default()) } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b5652bcabf168..ff56747fee6af 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -665,7 +665,7 @@ impl Default for HashSet where T: Eq + Hash, S: BuildHasher + Default, { - /// Creates a `HashSet` with initial `Default` hasher. + /// Creates an empty `HashSet` with the `Default` value for the hasher. fn default() -> HashSet { HashSet::with_hasher(Default::default()) } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 044112ea1365e..0f7dc3889f0b8 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -339,7 +339,7 @@ impl<'a> Default for &'a CStr { #[stable(feature = "cstr_default", since = "1.10.0")] impl Default for CString { - /// Creates a new `CString`, by calling the `Default` of `CStr`, and then owns it. + /// Creates an empty `CString`. fn default() -> CString { let a: &CStr = Default::default(); a.to_owned() diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index a65c54ac1e264..5875015893144 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -154,7 +154,7 @@ impl P<[T]> { } impl Default for P<[T]> { - /// Creates a new `P`, with the `Default` value for T. + /// Creates an empty `P<[T]>`. fn default() -> P<[T]> { P::new() } From 54c680cdb136bb991bdf60c31edcb1304da9005e Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sat, 10 Sep 2016 10:47:05 -0700 Subject: [PATCH 664/768] Tweak array docs Fixes #29331. --- src/libstd/primitive_docs.rs | 86 +++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 2b92da6c684a4..fdc84467015f9 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -249,37 +249,58 @@ 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`. +/// 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`. +/// There are two syntactic forms for creating an array: /// -/// The type `[T; N]` is `Copy` if `T: Copy`. +/// * A list with each element, i.e. `[x, y, z]`. +/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. +/// The type of `x` must be [`Copy`][copy]. /// /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if /// the element type allows it: /// -/// - `Clone` (only if `T: Copy`) -/// - `Debug` -/// - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) -/// - `PartialEq`, `PartialOrd`, `Ord`, `Eq` -/// - `Hash` -/// - `AsRef`, `AsMut` -/// - `Borrow`, `BorrowMut` -/// - `Default` -/// -/// This limitation to `N in 0..33` exists because Rust does not yet support -/// generics over the size of an array type. `[Foo; 3]` and `[Bar; 3]` are -/// instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are +/// - [`Clone`][clone] (only if `T: Copy`) +/// - [`Debug`][debug] +/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) +/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] +/// - [`Hash`][hash] +/// - [`AsRef`][asref], [`AsMut`][asmut] +/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut] +/// - [`Default`][default] +/// +/// This limitation on the size `N` exists because Rust does not yet support +/// code that is generic over the size of an array type. `[Foo; 3]` and `[Bar; 3]` +/// are instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are /// entirely different types. As a stopgap, trait implementations are -/// statically generated for `N in 0..33`. +/// statically generated up to size 32. /// -/// Arrays coerce to [slices (`[T]`)][slice], so their methods can be called on -/// arrays. Slices are dynamic and do not coerce to arrays; consequently more -/// methods are defined on `slice` where they support both types. +/// Arrays of *any* size are [`Copy`][copy] if the element type is `Copy`. This +/// works because the `Copy` trait is specially known to the compiler. +/// +/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on +/// an array. Indeed, this provides most of the API for working with arrays. +/// Slices have a dynamic size and do not coerce to arrays. +/// +/// There is no way to move elements out of an array. See [`mem::replace`][replace] +/// for an alternative. /// /// [slice]: primitive.slice.html +/// [copy]: marker/trait.Copy.html +/// [clone]: clone/trait.Clone.html +/// [debug]: fmt/trait.Debug.html +/// [intoiterator]: iter/trait.IntoIterator.html +/// [partialeq]: cmp/trait.PartialEq.html +/// [partialord]: cmp/trait.PartialOrd.html +/// [eq]: cmp/trait.Eq.html +/// [ord]: cmp/trait.Ord.html +/// [hash]: hash/trait.Hash.html +/// [asref]: convert/trait.AsRef.html +/// [asmut]: convert/trait.AsMut.html +/// [borrow]: borrow/trait.Borrow.html +/// [borrowmut]: borrow/trait.BorrowMut.html +/// [default]: default/trait.Default.html +/// [replace]: mem/fn.replace.html /// /// # Examples /// @@ -295,7 +316,30 @@ mod prim_pointer { } /// for x in &array { /// print!("{} ", x); /// } +/// ``` +/// +/// An array itself is not iterable: +/// +/// ```ignore +/// let array: [i32; 3] = [0; 3]; +/// +/// for x in array { } +/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied +/// ``` /// +/// The solution is to coerce the array to a slice by calling a slice method: +/// +/// ``` +/// # let array: [i32; 3] = [0; 3]; +/// for x in array.iter() { } +/// ``` +/// +/// If the array has 32 or fewer elements (see above), you can also use the +/// array reference's `IntoIterator` implementation: +/// +/// ``` +/// # let array: [i32; 3] = [0; 3]; +/// for x in &array { } /// ``` /// mod prim_array { } From 6b99e011626a6f73747307907cdadbc8ab9ebffd Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Sun, 11 Sep 2016 16:45:49 -0600 Subject: [PATCH 665/768] Delete stray ` character in error message. --- src/librustc_lint/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a6049acdb10d4..e8d9e90456efc 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyTuple(_) => { FfiUnsafe("found Rust tuple type in foreign module; \ - consider using a struct instead`") + consider using a struct instead") } ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => { From f1bd90778997865480fa666fbf2eef1b164a0f72 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 12 Sep 2016 01:53:43 +0300 Subject: [PATCH 666/768] use `adt::trans_const` when translating constant closures and tuples Fixes #36401 --- src/librustc_trans/mir/constant.rs | 86 ++++++++++++++++++++---------- src/test/run-pass/issue-36401.rs | 25 +++++++++ 2 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 src/test/run-pass/issue-36401.rs diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 15dc7bb4421c1..e9f324c0b08f0 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -38,6 +38,7 @@ use value::Value; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use std::fmt; use std::ptr; use super::operand::{OperandRef, OperandValue}; @@ -149,6 +150,12 @@ impl<'tcx> Const<'tcx> { } } +impl<'tcx> fmt::Debug for Const<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty) + } +} + #[derive(Copy, Clone)] enum Base { /// A constant value without an unique address. @@ -472,7 +479,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span) -> Result, ConstEvalErr> { - match *operand { + debug!("const_operand({:?} @ {:?})", operand, span); + let result = match *operand { mir::Operand::Consume(ref lvalue) => { Ok(self.const_lvalue(lvalue, span)?.to_const(span)) } @@ -501,13 +509,33 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } } - } + }; + debug!("const_operand({:?} @ {:?}) = {:?}", operand, span, + result.as_ref().ok()); + result + } + + fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef]) + -> Const<'tcx> + { + let elem_ty = array_ty.builtin_index().unwrap_or_else(|| { + bug!("bad array type {:?}", array_ty) + }); + let llunitty = type_of::type_of(self.ccx, elem_ty); + // If the array contains enums, an LLVM array won't work. + let val = if fields.iter().all(|&f| val_ty(f) == llunitty) { + C_array(llunitty, fields) + } else { + C_struct(self.ccx, fields, false) + }; + Const::new(val, array_ty) } fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, dest_ty: Ty<'tcx>, span: Span) -> Result, ConstEvalErr> { let tcx = self.ccx.tcx(); + debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span); let val = match *rvalue { mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?, @@ -515,15 +543,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let elem = self.const_operand(elem, span)?; let size = count.value.as_u64(tcx.sess.target.uint_type); let fields = vec![elem.llval; size as usize]; - - let llunitty = type_of::type_of(self.ccx, elem.ty); - // If the array contains enums, an LLVM array won't work. - let val = if val_ty(elem.llval) == llunitty { - C_array(llunitty, &fields) - } else { - C_struct(self.ccx, &fields, false) - }; - Const::new(val, dest_ty) + self.const_array(dest_ty, &fields) } mir::Rvalue::Aggregate(ref kind, ref operands) => { @@ -547,22 +567,26 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { self.monomorphize(&substs)); } - let val = if let mir::AggregateKind::Adt(adt_def, index, _, _) = *kind { - let repr = adt::represent_type(self.ccx, dest_ty); - let disr = Disr::from(adt_def.variants[index].disr_val); - adt::trans_const(self.ccx, &repr, disr, &fields) - } else if let ty::TyArray(elem_ty, _) = dest_ty.sty { - let llunitty = type_of::type_of(self.ccx, elem_ty); - // If the array contains enums, an LLVM array won't work. - if fields.iter().all(|&f| val_ty(f) == llunitty) { - C_array(llunitty, &fields) - } else { - C_struct(self.ccx, &fields, false) + match *kind { + mir::AggregateKind::Vec => { + self.const_array(dest_ty, &fields) } - } else { - C_struct(self.ccx, &fields, false) - }; - Const::new(val, dest_ty) + mir::AggregateKind::Adt(..) | + mir::AggregateKind::Closure(..) | + mir::AggregateKind::Tuple => { + let disr = match *kind { + mir::AggregateKind::Adt(adt_def, index, _, _) => { + Disr::from(adt_def.variants[index].disr_val) + } + _ => Disr(0) + }; + let repr = adt::represent_type(self.ccx, dest_ty); + Const::new( + adt::trans_const(self.ccx, &repr, disr, &fields), + dest_ty + ) + } + } } mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -786,6 +810,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { _ => span_bug!(span, "{:?} in constant", rvalue) }; + debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val); + Ok(val) } @@ -935,6 +961,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { constant: &mir::Constant<'tcx>) -> Const<'tcx> { + debug!("trans_constant({:?})", constant); let ty = bcx.monomorphize(&constant.ty); let result = match constant.literal.clone() { mir::Literal::Item { def_id, substs } => { @@ -959,11 +986,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }; - result.unwrap_or_else(|_| { + let result = result.unwrap_or_else(|_| { // We've errored, so we don't have to produce working code. let llty = type_of::type_of(bcx.ccx(), ty); Const::new(C_undef(llty), ty) - }) + }); + + debug!("trans_constant({:?}) = {:?}", constant, result); + result } } diff --git a/src/test/run-pass/issue-36401.rs b/src/test/run-pass/issue-36401.rs new file mode 100644 index 0000000000000..7b08eba9e4988 --- /dev/null +++ b/src/test/run-pass/issue-36401.rs @@ -0,0 +1,25 @@ +// 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. + +#[derive(Debug)] +pub enum Event { + Key(u8), + Resize, + Unknown(u16), +} + +static XTERM_SINGLE_BYTES : [(u8, Event); 1] = [(1, Event::Resize)]; + +fn main() { + match XTERM_SINGLE_BYTES[0] { + (1, Event::Resize) => {}, + ref bad => panic!("unexpected {:?}", bad) + } +} From f1c6cad96398d558e6ecca9cc144a1b96da9e4c5 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 01:42:56 -0700 Subject: [PATCH 667/768] Use question_mark feature in linkchecker. --- src/tools/linkchecker/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 27adabbc72e58..3e2bc9032a1cc 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -24,6 +24,8 @@ //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc, //! but this should catch the majority of "broken link" cases. +#![feature(question_mark)] + extern crate url; use std::env; @@ -243,15 +245,14 @@ fn load_file(cache: &mut Cache, None } Entry::Vacant(entry) => { - let mut fp = try!(File::open(file.clone()).map_err(|err| { + let mut fp = File::open(file.clone()).map_err(|err| { if let FromRedirect(true) = redirect { LoadError::BrokenRedirect(file.clone(), err) } else { LoadError::IOError(err) } - })); - try!(fp.read_to_string(&mut contents) - .map_err(|err| LoadError::IOError(err))); + })?; + fp.read_to_string(&mut contents).map_err(|err| LoadError::IOError(err))?; let maybe = maybe_redirect(&contents); if maybe.is_some() { From f0a414e74e4bd4d70fcf93198791432705df9b92 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 01:47:03 -0700 Subject: [PATCH 668/768] Use question_mark feature in compiletest. --- src/tools/compiletest/src/runtest.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 228d6ada01dcc..bfb85dd479d56 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2113,23 +2113,23 @@ actual:\n\ } fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { - for e in try!(path.read_dir()) { - let entry = try!(e); + for e in path.read_dir()? { + let entry = e?; let path = entry.path(); - if try!(entry.file_type()).is_dir() { - try!(self.aggressive_rm_rf(&path)); + if entry.file_type()?.is_dir() { + self.aggressive_rm_rf(&path)?; } else { // Remove readonly files as well on windows (by default we can't) - try!(fs::remove_file(&path).or_else(|e| { + fs::remove_file(&path).or_else(|e| { if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied { - let mut meta = try!(entry.metadata()).permissions(); + let mut meta = entry.metadata()?.permissions(); meta.set_readonly(false); - try!(fs::set_permissions(&path, meta)); + fs::set_permissions(&path, meta)?; fs::remove_file(&path) } else { Err(e) } - })) + })?; } } fs::remove_dir(path) From 6d88ab57b3e308456c79694e281dbd4f08603f13 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:10:09 -0700 Subject: [PATCH 669/768] Fix typo in bootstrap/lib.rs. --- src/bootstrap/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea2546..a1424bf3aaa4a 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -46,7 +46,7 @@ use util::{exe, mtime, libdir, add_lib_path}; /// * The error itself /// /// This is currently used judiciously throughout the build system rather than -/// using a `Result` with `try!`, but this may change on day... +/// using a `Result` with `try!`, but this may change one day... macro_rules! t { ($e:expr) => (match $e { Ok(e) => e, From bfd123d1e9fce7b0cfb4462966b09a76e65b00d6 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:12:25 -0700 Subject: [PATCH 670/768] Use question_mark feature in libcore. --- src/libcore/num/bignum.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index bc503ba3e46ae..1ca550c67463c 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -474,9 +474,9 @@ macro_rules! define_bignum { let sz = if self.size < 1 {1} else {self.size}; let digitlen = mem::size_of::<$ty>() * 2; - try!(write!(f, "{:#x}", self.base[sz-1])); + write!(f, "{:#x}", self.base[sz-1])?; for &v in self.base[..sz-1].iter().rev() { - try!(write!(f, "_{:01$x}", v, digitlen)); + write!(f, "_{:01$x}", v, digitlen)?; } ::result::Result::Ok(()) } From 8391760bd846740ea13f9c415a00af10a0b735d1 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:21:36 -0700 Subject: [PATCH 671/768] Use question_mark feature in librustc_errors. --- src/librustc_errors/emitter.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index dcdbe2a85259b..1bdc9ef30881f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -882,45 +882,45 @@ impl Destination { match style { Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { - try!(self.start_attr(term::Attr::Bold)); + self.start_attr(term::Attr::Bold)?; if cfg!(windows) { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))?; } else { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; } } Style::ErrorCode => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))?; } Style::Quotation => {} Style::OldSchoolNote => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?; } Style::OldSchoolNoteText | Style::HeaderMsg => { - try!(self.start_attr(term::Attr::Bold)); + self.start_attr(term::Attr::Bold)?; if cfg!(windows) { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))?; } } Style::UnderlinePrimary | Style::LabelPrimary => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(lvl.color()))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; } Style::UnderlineSecondary | Style::LabelSecondary => { - try!(self.start_attr(term::Attr::Bold)); + self.start_attr(term::Attr::Bold)?; if cfg!(windows) { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))?; } else { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; } } Style::NoStyle => {} Style::Level(l) => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(l.color()))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(l.color()))?; } } Ok(()) @@ -960,4 +960,4 @@ impl Write for Destination { Raw(ref mut w) => w.flush(), } } -} \ No newline at end of file +} From 8a9e52a8e734972b9b16cbfc3902743eb432cfbc Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:31:17 -0700 Subject: [PATCH 672/768] Use question_mark feature in librustc_incremental. --- src/librustc_incremental/persist/hash.rs | 4 ++-- src/librustc_incremental/persist/load.rs | 8 ++++---- src/librustc_incremental/persist/save.rs | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 95bee669d3256..bafaafd4afa0e 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // Load up the hashes for the def-ids from this crate. let mut decoder = Decoder::new(data, 0); - let svh_in_hashes_file = try!(Svh::decode(&mut decoder)); + let svh_in_hashes_file = Svh::decode(&mut decoder)?; if svh_in_hashes_file != expected_svh { // We should not be able to get here. If we do, then @@ -202,7 +202,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { bug!("mismatch between SVH in crate and SVH in incr. comp. hashes") } - let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder)); + let serialized_hashes = SerializedMetadataHashes::decode(&mut decoder)?; for serialized_hash in serialized_hashes.hashes { // the hashes are stored with just a def-index, which is // always relative to the old crate; convert that to use diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 48f95430f26b6..6e6464e49683a 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -125,11 +125,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { // Decode the list of work_products let mut work_product_decoder = Decoder::new(work_products_data, 0); - let work_products = try!(>::decode(&mut work_product_decoder)); + let work_products = >::decode(&mut work_product_decoder)?; // Deserialize the directory and dep-graph. let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0); - let prev_commandline_args_hash = try!(u64::decode(&mut dep_graph_decoder)); + let prev_commandline_args_hash = u64::decode(&mut dep_graph_decoder)?; if prev_commandline_args_hash != tcx.sess.opts.dep_tracking_hash() { // We can't reuse the cache, purge it. @@ -142,8 +142,8 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return Ok(()); } - let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder)); - let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder)); + let directory = DefIdDirectory::decode(&mut dep_graph_decoder)?; + let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?; // Retrace the paths in the directory to find their current location (if any). let retraced = directory.retrace(tcx); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index d31252be5e857..41212d8e138da 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -110,7 +110,7 @@ pub fn encode_dep_graph(preds: &Predecessors, -> io::Result<()> { // First encode the commandline arguments hash let tcx = builder.tcx(); - try!(tcx.sess.opts.dep_tracking_hash().encode(encoder)); + tcx.sess.opts.dep_tracking_hash().encode(encoder)?; // Create a flat list of (Input, WorkProduct) edges for // serialization. @@ -149,8 +149,8 @@ pub fn encode_dep_graph(preds: &Predecessors, debug!("graph = {:#?}", graph); // Encode the directory and then the graph data. - try!(builder.directory().encode(encoder)); - try!(graph.encode(encoder)); + builder.directory().encode(encoder)?; + graph.encode(encoder)?; Ok(()) } @@ -222,8 +222,8 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, } // Encode everything. - try!(svh.encode(encoder)); - try!(serialized_hashes.encode(encoder)); + svh.encode(encoder)?; + serialized_hashes.encode(encoder)?; Ok(()) } From e10e0bcf2d4e8a5c98c4cfb577f161187b74bfcc Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:32:28 -0700 Subject: [PATCH 673/768] Use question_mark feature in librustc_mir. --- src/librustc_mir/pretty.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index d46a7b2bb9506..01e2c6308ba01 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -77,12 +77,12 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id, promotion_id, pass_name, disambiguator); file_path.push(&file_name); let _ = fs::File::create(&file_path).and_then(|mut file| { - try!(writeln!(file, "// MIR for `{}`", node_path)); - try!(writeln!(file, "// node_id = {}", node_id)); - try!(writeln!(file, "// pass_name = {}", pass_name)); - try!(writeln!(file, "// disambiguator = {}", disambiguator)); - try!(writeln!(file, "")); - try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary)); + writeln!(file, "// MIR for `{}`", node_path)?; + writeln!(file, "// node_id = {}", node_id)?; + writeln!(file, "// pass_name = {}", pass_name)?; + writeln!(file, "// disambiguator = {}", disambiguator)?; + writeln!(file, "")?; + write_mir_fn(tcx, src, mir, &mut file, auxiliary)?; Ok(()) }); } From 14d3937e659b383a32ec9c90e5805386150c0054 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 06:50:17 -0700 Subject: [PATCH 674/768] Use question_mark feature in librustc. --- src/librustc/hir/print.rs | 4 ++-- src/librustc/infer/higher_ranked/mod.rs | 2 +- src/librustc/util/fs.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index f236bd4884d5b..eebc8fa9e5d5d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1756,9 +1756,9 @@ impl<'a> State<'a> { self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; } } else { - try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))); + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; } - try!(self.pclose()); + self.pclose()?; } PatKind::Path(None, ref path) => { self.print_path(path, true, 0)?; diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 322752ccea3e5..7c02de05d26d5 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("higher_ranked_match: skol_map={:?}", skol_map); // Equate types now that bound regions have been replaced. - try!(self.equate(a_is_expected).relate(&a_match, &b_match)); + self.equate(a_is_expected).relate(&a_match, &b_match)?; // Map each skolemized region to a vector of other regions that it // must be equated with. (Note that this vector may include other diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index d7800ccaa5dd3..c290d8f893e9e 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -68,7 +68,7 @@ pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result
  • Date: Sat, 27 Aug 2016 07:16:17 -0700 Subject: [PATCH 675/768] Use question_mark feature in libserialize. --- src/libserialize/json.rs | 11 +++++------ src/libserialize/serialize.rs | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 0782601e1796e..6ccc0be41bc0f 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -475,15 +475,14 @@ impl<'a> Encoder<'a> { } macro_rules! emit_enquoted_if_mapkey { - ($enc:ident,$e:expr) => { + ($enc:ident,$e:expr) => ({ if $enc.is_emitting_map_key { - try!(write!($enc.writer, "\"{}\"", $e)); - Ok(()) + write!($enc.writer, "\"{}\"", $e)?; } else { - try!(write!($enc.writer, "{}", $e)); - Ok(()) + write!($enc.writer, "{}", $e)?; } - } + Ok(()) + }) } impl<'a> ::Encoder for Encoder<'a> { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index b75ec5dad8ddd..8e271597dfcb6 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -511,10 +511,10 @@ macro_rules! tuple { let len: usize = count_idents!($($name,)*); d.read_tuple(len, |d| { let mut i = 0; - let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, - |d| -> Result<$name,D::Error> { + let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, + |d| -> Result<$name,D::Error> { Decodable::decode(d) - })),)*); + })?,)*); Ok(ret) }) } @@ -527,7 +527,7 @@ macro_rules! tuple { $(let $name = $name; n += 1;)* s.emit_tuple(n, |s| { let mut i = 0; - $(try!(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s)));)* + $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)* Ok(()) }) } From 637f1492e7beb768c039b962fb04b6855d6e9461 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:33:36 -0700 Subject: [PATCH 676/768] Use question_mark feature in libstd. --- src/libstd/sync/mpsc/oneshot.rs | 2 +- src/libstd/sync/mpsc/stream.rs | 3 +-- src/libstd/sys/common/backtrace.rs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 7a35ea6bbaaa2..7389280b853db 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -150,7 +150,7 @@ impl Packet { let timed_out = !wait_token.wait_max_until(deadline); // Try to reset the state if timed_out { - try!(self.abort_selection().map_err(Upgraded)); + self.abort_selection().map_err(Upgraded)?; } } else { wait_token.wait(); diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index aa1254c8641f5..61c8316467d9a 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -187,8 +187,7 @@ impl Packet { if let Some(deadline) = deadline { let timed_out = !wait_token.wait_max_until(deadline); if timed_out { - try!(self.abort_selection(/* was_upgrade = */ false) - .map_err(Upgraded)); + self.abort_selection(/* was_upgrade = */ false).map_err(Upgraded)?; } } else { wait_token.wait(); diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index a509b80eaca91..a8540fed9286f 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -153,11 +153,11 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { macro_rules! demangle { ($($pat:expr => $demangled:expr),*) => ({ $(if rest.starts_with($pat) { - try!(writer.write_all($demangled)); + writer.write_all($demangled)?; rest = &rest[$pat.len()..]; } else)* { - try!(writer.write_all(rest.as_bytes())); + writer.write_all(rest.as_bytes())?; break; } From 0dbf77e722e6f30568664808808716d8d3650dc5 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:48:39 -0700 Subject: [PATCH 677/768] Use question_mark feature in librustc_back. --- src/librustc_back/target/aarch64_apple_ios.rs | 2 +- src/librustc_back/target/apple_ios_base.rs | 4 ++-- src/librustc_back/target/armv7_apple_ios.rs | 2 +- src/librustc_back/target/armv7s_apple_ios.rs | 2 +- src/librustc_back/target/i386_apple_ios.rs | 2 +- src/librustc_back/target/i586_pc_windows_msvc.rs | 2 +- .../target/i586_unknown_linux_gnu.rs | 2 +- src/librustc_back/target/mod.rs | 16 ++++++++-------- src/librustc_back/target/x86_64_apple_ios.rs | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 6530ccb0630db..660ed0ac7b843 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::Arm64)); + let base = opts(Arch::Arm64)?; Ok(Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 8bd9feabdbebe..17492b8bdcb64 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -68,7 +68,7 @@ fn build_pre_link_args(arch: Arch) -> Result, String> { let arch_name = arch.to_string(); - let sdk_root = try!(get_sdk_root(sdk_name)); + let sdk_root = get_sdk_root(sdk_name)?; Ok(vec!["-arch".to_string(), arch_name.to_string(), "-Wl,-syslibroot".to_string(), sdk_root]) @@ -85,7 +85,7 @@ fn target_cpu(arch: Arch) -> String { } pub fn opts(arch: Arch) -> Result { - let pre_link_args = try!(build_pre_link_args(arch)); + let pre_link_args = build_pre_link_args(arch)?; Ok(TargetOptions { cpu: target_cpu(arch), dynamic_linking: false, diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index a806204d0a6bc..71533a09b1672 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::Armv7)); + let base = opts(Arch::Armv7)?; Ok(Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index aaa3570fa62ee..f24b9969910ef 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::Armv7s)); + let base = opts(Arch::Armv7s)?; Ok(Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index f391d4118ea74..94146fe9d9885 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::I386)); + let base = opts(Arch::I386)?; Ok(Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/i586_pc_windows_msvc.rs b/src/librustc_back/target/i586_pc_windows_msvc.rs index 445ee6c412283..9b88cde598937 100644 --- a/src/librustc_back/target/i586_pc_windows_msvc.rs +++ b/src/librustc_back/target/i586_pc_windows_msvc.rs @@ -11,7 +11,7 @@ use target::TargetResult; pub fn target() -> TargetResult { - let mut base = try!(super::i686_pc_windows_msvc::target()); + let mut base = super::i686_pc_windows_msvc::target()?; base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-pc-windows-msvc".to_string(); Ok(base) diff --git a/src/librustc_back/target/i586_unknown_linux_gnu.rs b/src/librustc_back/target/i586_unknown_linux_gnu.rs index 1ca8606149bff..40fb4a67acdf1 100644 --- a/src/librustc_back/target/i586_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i586_unknown_linux_gnu.rs @@ -11,7 +11,7 @@ use target::TargetResult; pub fn target() -> TargetResult { - let mut base = try!(super::i686_unknown_linux_gnu::target()); + let mut base = super::i686_unknown_linux_gnu::target()?; base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-unknown-linux-gnu".to_string(); Ok(base) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d48370b23b69d..e9fce9cee00d1 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -77,12 +77,12 @@ macro_rules! supported_targets { match target { $( $triple => { - let mut t = try!($module::target()); + let mut t = $module::target()?; t.options.is_builtin = true; // round-trip through the JSON parser to ensure at // run-time that the parser works correctly - t = try!(Target::from_json(t.to_json())); + t = Target::from_json(t.to_json())?; debug!("Got builtin target: {:?}", t); Ok(t) }, @@ -442,12 +442,12 @@ impl Target { }; let mut base = Target { - llvm_target: try!(get_req_field("llvm-target")), - target_endian: try!(get_req_field("target-endian")), - target_pointer_width: try!(get_req_field("target-pointer-width")), - data_layout: try!(get_req_field("data-layout")), - arch: try!(get_req_field("arch")), - target_os: try!(get_req_field("os")), + llvm_target: get_req_field("llvm-target")?, + target_endian: get_req_field("target-endian")?, + target_pointer_width: get_req_field("target-pointer-width")?, + data_layout: get_req_field("data-layout")?, + arch: get_req_field("arch")?, + target_os: get_req_field("os")?, target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), options: Default::default(), diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 4afc9bcb946c2..3b8b636b6dc66 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::X86_64)); + let base = opts(Arch::X86_64)?; Ok(Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), From 509aa235ba4a2d453cf545f2553b8173dcd5f25b Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:51:55 -0700 Subject: [PATCH 678/768] Use question_mark feature in librustc_const_eval. --- src/librustc_const_eval/eval.rs | 41 +++++++++++++++------------------ 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4f4c16d3f6a61..4ced9d87f0a5a 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -278,9 +278,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let pat = match expr.node { hir::ExprTup(ref exprs) => - PatKind::Tuple(try!(exprs.iter() - .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) - .collect()), None), + PatKind::Tuple(exprs.iter() + .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) + .collect::>()?, None), hir::ExprCall(ref callee, ref args) => { let def = tcx.expect_def(callee.id); @@ -297,34 +297,31 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })), _ => bug!() }; - let pats = try!(args.iter() - .map(|expr| const_expr_to_pat(tcx, &**expr, - pat_id, span)) - .collect()); + let pats = args.iter() + .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span)) + .collect::>()?; PatKind::TupleStruct(path, pats, None) } hir::ExprStruct(ref path, ref fields, None) => { let field_pats = - try!(fields.iter() - .map(|field| Ok(codemap::Spanned { - span: syntax_pos::DUMMY_SP, - node: hir::FieldPat { - name: field.name.node, - pat: try!(const_expr_to_pat(tcx, &field.expr, - pat_id, span)), - is_shorthand: false, - }, - })) - .collect()); + fields.iter() + .map(|field| Ok(codemap::Spanned { + span: syntax_pos::DUMMY_SP, + node: hir::FieldPat { + name: field.name.node, + pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?, + is_shorthand: false, + }, + })) + .collect::>()?; PatKind::Struct(path.clone(), field_pats, false) } hir::ExprVec(ref exprs) => { - let pats = try!(exprs.iter() - .map(|expr| const_expr_to_pat(tcx, &expr, - pat_id, span)) - .collect()); + let pats = exprs.iter() + .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) + .collect::>()?; PatKind::Vec(pats, None, hir::HirVec::new()) } From 694d601dbc2df575c32a490a529656a864dc0a2e Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:53:05 -0700 Subject: [PATCH 679/768] Use question_mark feature in librustc_metadata. --- src/librustc_metadata/loader.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 44d7861066da3..a4f8ee4779905 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -809,7 +809,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), Some(blob) => { - try!(verify_decompressed_encoding_version(&blob, filename)); + verify_decompressed_encoding_version(&blob, filename)?; Ok(blob) } }; @@ -858,7 +858,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat match flate::inflate_bytes(bytes) { Ok(inflated) => { let blob = MetadataVec(inflated); - try!(verify_decompressed_encoding_version(&blob, filename)); + verify_decompressed_encoding_version(&blob, filename)?; return Ok(blob); } Err(_) => {} From 5b59c141438f10f7351992f1ff38c20e63a9a441 Mon Sep 17 00:00:00 2001 From: dangcheng Date: Mon, 12 Sep 2016 12:02:35 +0800 Subject: [PATCH 680/768] change error message --- src/doc/book/traits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index 605dc2a152df9..d07fb6b7c45bf 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -275,7 +275,7 @@ won’t have its methods: [write]: ../std/io/trait.Write.html ```rust,ignore -let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; // byte string literal. buf: &[u8; 8] let result = f.write(buf); # result.unwrap(); // ignore the error @@ -294,7 +294,7 @@ We need to `use` the `Write` trait first: ```rust,ignore use std::io::Write; -let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; let result = f.write(buf); # result.unwrap(); // ignore the error From 4c274b6aea00c2327211e8295f4d97ee6e624a2b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2016 13:03:21 +1000 Subject: [PATCH 681/768] Avoid an unnecessary intermediate value in char_lit(). This makes the function more concise and easier to understand. --- src/libsyntax/parse/mod.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index af95e44a567ba..31fa2cda5db5e 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -287,26 +287,21 @@ pub fn char_lit(lit: &str) -> (char, isize) { use std::char; let mut chars = lit.chars(); - let c = match (chars.next(), chars.next()) { + match (chars.next(), chars.next()) { (Some(c), None) if c != '\\' => return (c, 1), (Some('\\'), Some(c)) => match c { - '"' => Some('"'), - 'n' => Some('\n'), - 'r' => Some('\r'), - 't' => Some('\t'), - '\\' => Some('\\'), - '\'' => Some('\''), - '0' => Some('\0'), - _ => { None } + '"' => return ('"', 2), + 'n' => return ('\n', 2), + 'r' => return ('\r', 2), + 't' => return ('\t', 2), + '\\' => return ('\\', 2), + '\'' => return ('\'', 2), + '0' => return ('\0', 2), + _ => {} }, _ => panic!("lexer accepted invalid char escape `{}`", lit) }; - match c { - Some(x) => return (x, 2), - None => { } - } - let msg = format!("lexer should have rejected a bad character escape {}", lit); let msg2 = &msg[..]; From 826f673664023e79e86409296d3d67527c9b0a5a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2016 14:31:51 +1000 Subject: [PATCH 682/768] Lazily construct panic messages in char_lit(). This reduces the time taken to run `rustc -Zparse-only rustc-benchmarks/issue-32278-big-array-of-strings` from 0.18s to 0.15s on my machine, and reduces the number of instructions (as measured by Cachegrind) from 1.34B to 1.01B. With the change applied, the time to fully compile that benchmark is 1.96s, so this is a 1.5% improvement. --- src/libsyntax/parse/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 31fa2cda5db5e..a1eceb6921c6d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -302,9 +302,6 @@ pub fn char_lit(lit: &str) -> (char, isize) { _ => panic!("lexer accepted invalid char escape `{}`", lit) }; - let msg = format!("lexer should have rejected a bad character escape {}", lit); - let msg2 = &msg[..]; - fn esc(len: usize, lit: &str) -> Option<(char, isize)> { u32::from_str_radix(&lit[2..len], 16).ok() .and_then(char::from_u32) @@ -313,7 +310,10 @@ pub fn char_lit(lit: &str) -> (char, isize) { let unicode_escape = || -> Option<(char, isize)> { if lit.as_bytes()[2] == b'{' { - let idx = lit.find('}').expect(msg2); + let idx = lit.find('}').unwrap_or_else(|| { + panic!("lexer should have rejected a bad character escape {}", lit) + }); + let subslice = &lit[3..idx]; u32::from_str_radix(subslice, 16).ok() .and_then(char::from_u32) @@ -329,7 +329,9 @@ pub fn char_lit(lit: &str) -> (char, isize) { 'u' => unicode_escape(), 'U' => esc(10, lit), _ => None, - }.expect(msg2); + }.unwrap_or_else(|| { + panic!("lexer should have rejected a bad character escape {}", lit) + }) } /// Parse a string representing a string literal into its final form. Does From 9ca578687b88d2c7817d5709b2700fb6777348f2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 12 Sep 2016 17:43:44 -0400 Subject: [PATCH 683/768] check stack discipline of tasks --- src/librustc/dep_graph/shadow.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index f9f75d006775f..72a321425ef06 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -17,8 +17,10 @@ //! runtime impact. Therefore, it is largely compiled out if //! debug-assertions are not enabled. //! -//! The basic sanity check, always enabled, is that there is always a -//! task (or ignore) on the stack when you do read/write. +//! The basic sanity check, enabled if you have debug assertions +//! enabled, is that there is always a task (or ignore) on the stack +//! when you do read/write, and that the tasks are pushed/popped +//! according to a proper stack discipline. //! //! Optionally, if you specify RUST_FORBID_DEP_GRAPH_EDGE, you can //! specify an edge filter to be applied to each edge as it is @@ -81,13 +83,23 @@ impl ShadowGraph { DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), DepMessage::PushIgnore => stack.push(None), - DepMessage::PopTask(_) | + DepMessage::PopTask(ref n) => { + match stack.pop() { + Some(Some(m)) => { + if *n != m { + bug!("stack mismatch: found {:?} expected {:?}", m, n) + } + } + Some(None) => bug!("stack mismatch: found Ignore expected {:?}", n), + None => bug!("stack mismatch: found empty stack, expected {:?}", n), + } + } DepMessage::PopIgnore => { - // we could easily check that the stack is - // well-formed here, but since we use closures and - // RAII accessors, this bug basically never - // happens, so it seems not worth the overhead - stack.pop(); + match stack.pop() { + Some(Some(m)) => bug!("stack mismatch: found {:?} expected ignore", m), + Some(None) => (), + None => bug!("stack mismatch: found empty stack, expected ignore"), + } } DepMessage::Query => (), } From 7bd25a304851afdf0ba1897a950220ed3ad0a215 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 12 Sep 2016 15:55:02 -0700 Subject: [PATCH 684/768] Remove stray attribute --- src/libcore/iter/traits.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 563fb213d3763..b55d6f96af9bf 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -587,7 +587,6 @@ macro_rules! integer_sum_product { ($($a:ident)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { - #[rustc_inherit_overflow_checks] fn sum>(iter: I) -> $a { iter.fold(0, Add::add) } From be2fa70c1604f4383463fa4e64cd9f4567ff47e8 Mon Sep 17 00:00:00 2001 From: knight42 Date: Thu, 8 Sep 2016 18:54:45 +0800 Subject: [PATCH 685/768] Implement std::str::replacen --- src/libcollections/str.rs | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 999c84ba70538..6a6b450e51863 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1594,6 +1594,49 @@ impl str { result } + /// Replaces first N matches of a pattern with another string. + /// + /// `replacen` creates a new [`String`], and copies the data from this string slice into it. + /// While doing so, it attempts to find matches of a pattern. If it finds any, it + /// replaces them with the replacement string slice at most `N` times. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(str_replacen)] + /// let s = "foo foo 123 foo"; + /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); + /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); + /// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1)); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// # #![feature(str_replacen)] + /// let s = "this is old"; + /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); + /// ``` + #[unstable(feature = "str_replacen", + issue = "36436", + reason = "only need to replace first N matches")] + pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { + // Hope to reduce the times of re-allocation + let mut result = String::with_capacity(32); + let mut last_end = 0; + for (start, part) in self.match_indices(pat).take(count) { + result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(to); + last_end = start + part.len(); + } + result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result + } + /// Returns the lowercase equivalent of this string slice, as a new [`String`]. /// /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property From ebda77072a56a43d33d5723196a5ae37544a1ab9 Mon Sep 17 00:00:00 2001 From: knight42 Date: Thu, 8 Sep 2016 18:55:04 +0800 Subject: [PATCH 686/768] Add tests for str::replacen --- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/str.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 32a07e3e7e621..878581a4f296e 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -21,6 +21,7 @@ #![feature(rand)] #![feature(step_by)] #![feature(str_escape)] +#![feature(str_replacen)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index a61925cd3be5a..62e164a569aa6 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -218,6 +218,20 @@ fn test_is_empty() { assert!(!"a".is_empty()); } +#[test] +fn test_replacen() { + assert_eq!("".replacen('a', "b", 5), ""); + assert_eq!("acaaa".replacen("a", "b", 3), "bcbba"); + assert_eq!("aaaa".replacen("a", "b", 0), "aaaa"); + + let test = "test"; + assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast "); + assert_eq!(" test test ".replacen(test, "toast", 0), " test test "); + assert_eq!(" test test ".replacen(test, "", 5), " "); + + assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789"); +} + #[test] fn test_replace() { let a = "a"; From 0a62676c73ce8050941d571427dfb621b004a3b8 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 12 Sep 2016 17:47:59 -0400 Subject: [PATCH 687/768] fix "X is not a member of trait Y" span labels The span labels for associated types and consts were hardcoded to `Foo` rather than substituting the name of the trait. This also normalizes the wording for associated methods', traits', and consts' span labels. Fixes #36428. --- src/librustc_resolve/lib.rs | 6 +++--- src/test/compile-fail/E0407.rs | 2 +- src/test/compile-fail/E0438.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c5b505fba38e9..a11ef6e221dc2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -247,7 +247,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "method `{}` is not a member of trait `{}`", method, trait_); - err.span_label(span, &format!("not a member of `{}`", trait_)); + err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { @@ -257,7 +257,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "type `{}` is not a member of trait `{}`", type_, trait_); - err.span_label(span, &format!("not a member of trait `Foo`")); + err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { @@ -267,7 +267,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "const `{}` is not a member of trait `{}`", const_, trait_); - err.span_label(span, &format!("not a member of trait `Foo`")); + err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => { diff --git a/src/test/compile-fail/E0407.rs b/src/test/compile-fail/E0407.rs index 2a150b7451210..c207dbfca5565 100644 --- a/src/test/compile-fail/E0407.rs +++ b/src/test/compile-fail/E0407.rs @@ -18,7 +18,7 @@ impl Foo for Bar { fn a() {} fn b() {} //~^ ERROR E0407 - //~| NOTE not a member of `Foo` + //~| NOTE not a member of trait `Foo` } fn main() { diff --git a/src/test/compile-fail/E0438.rs b/src/test/compile-fail/E0438.rs index f549d62aebfea..2e2df4bee5a35 100644 --- a/src/test/compile-fail/E0438.rs +++ b/src/test/compile-fail/E0438.rs @@ -10,11 +10,11 @@ #![feature(associated_consts)] -trait Foo {} +trait Bar {} -impl Foo for i32 { +impl Bar for i32 { const BAR: bool = true; //~ ERROR E0438 - //~| NOTE not a member of trait `Foo` + //~| NOTE not a member of trait `Bar` } fn main () { From 3fd5fdd8d3e64e957a7eafe3d6d0b10ef4170d59 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 24 Jul 2016 21:42:11 -0500 Subject: [PATCH 688/768] crate-ify compiler-rt into compiler-builtins libcompiler-rt.a is dead, long live libcompiler-builtins.rlib This commit moves the logic that used to build libcompiler-rt.a into a compiler-builtins crate on top of the core crate and below the std crate. This new crate still compiles the compiler-rt instrinsics using gcc-rs but produces an .rlib instead of a static library. Also, with this commit rustc no longer passes -lcompiler-rt to the linker. This effectively makes the "no-compiler-rt" field of target specifications a no-op. Users of `no_std` will have to explicitly add the compiler-builtins crate to their crate dependency graph *if* they need the compiler-rt intrinsics. Users of the `std` have to do nothing extra as the std crate depends on compiler-builtins. Finally, this a step towards lazy compilation of std with Cargo as the compiler-rt intrinsics can now be built by Cargo instead of having to be supplied by the user by some other method. closes #34400 --- mk/clean.mk | 1 - mk/crates.mk | 8 +- mk/main.mk | 5 +- mk/platform.mk | 2 - mk/rt.mk | 340 ++++++++------- src/bootstrap/clean.rs | 1 - src/bootstrap/compile.rs | 22 +- src/bootstrap/lib.rs | 11 - src/bootstrap/native.rs | 397 +---------------- src/bootstrap/step.rs | 5 +- src/libcompiler_builtins/Cargo.toml | 15 + src/libcompiler_builtins/build.rs | 402 ++++++++++++++++++ src/libcompiler_builtins/lib.rs | 16 + src/librustc/middle/cstore.rs | 2 + .../target/asmjs_unknown_emscripten.rs | 1 - src/librustc_back/target/le32_unknown_nacl.rs | 1 - src/librustc_back/target/mod.rs | 6 - src/librustc_metadata/csearch.rs | 4 + src/librustc_metadata/cstore.rs | 5 + src/librustc_trans/back/link.rs | 13 +- src/libstd/Cargo.toml | 1 + src/libstd/lib.rs | 3 + src/libsyntax/feature_gate.rs | 10 + src/rustc/std_shim/Cargo.lock | 9 + .../feature-gate-compiler-builtins.rs | 14 + 25 files changed, 693 insertions(+), 601 deletions(-) create mode 100644 src/libcompiler_builtins/Cargo.toml create mode 100644 src/libcompiler_builtins/build.rs create mode 100644 src/libcompiler_builtins/lib.rs create mode 100644 src/test/compile-fail/feature-gate-compiler-builtins.rs diff --git a/mk/clean.mk b/mk/clean.mk index ac34ac506bb17..3574f25d9b744 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -102,7 +102,6 @@ define CLEAN_TARGET_STAGE_N clean$(1)_T_$(2)_H_$(3): \ $$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \ $$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS_ALL),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool)) - $$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows diff --git a/mk/crates.mk b/mk/crates.mk index 06ad07de136b1..d2c79441d866f 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -51,7 +51,7 @@ TARGET_CRATES := libc std term \ getopts collections test rand \ - core alloc \ + compiler_builtins core alloc \ rustc_unicode rustc_bitflags \ alloc_system alloc_jemalloc \ panic_abort panic_unwind unwind @@ -65,6 +65,7 @@ HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc f TOOLS := compiletest rustdoc rustc rustbook error_index_generator DEPS_core := +DEPS_compiler_builtins := core DEPS_alloc := core libc alloc_system DEPS_alloc_system := core libc DEPS_alloc_jemalloc := core libc native:jemalloc @@ -77,12 +78,14 @@ DEPS_panic_abort := libc alloc DEPS_panic_unwind := libc alloc unwind DEPS_unwind := libc +RUSTFLAGS_compiler_builtins := -lstatic=compiler-rt + # FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...` RUSTFLAGS1_panic_abort := -C panic=abort RUSTFLAGS2_panic_abort := -C panic=abort RUSTFLAGS3_panic_abort := -C panic=abort -DEPS_std := core libc rand alloc collections rustc_unicode \ +DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \ native:backtrace \ alloc_system panic_abort panic_unwind unwind DEPS_arena := std @@ -153,6 +156,7 @@ TOOL_SOURCE_rustc := $(S)src/driver/driver.rs TOOL_SOURCE_rustbook := $(S)src/tools/rustbook/main.rs TOOL_SOURCE_error_index_generator := $(S)src/tools/error_index_generator/main.rs +ONLY_RLIB_compiler_builtins := 1 ONLY_RLIB_core := 1 ONLY_RLIB_libc := 1 ONLY_RLIB_alloc := 1 diff --git a/mk/main.mk b/mk/main.mk index 6130b58138751..dd0136e136216 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -455,7 +455,10 @@ endif TSREQ$(1)_T_$(2)_H_$(3) = \ $$(HSREQ$(1)_H_$(3)) \ $$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\ - $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) + $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ + $$(TLIB0_T_$(2)_H_$(3))/libcompiler-rt.a +# ^ This copies `libcompiler-rt.a` to the stage0 sysroot +# ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0 # Prerequisites for a working stageN compiler and libraries, for a specific # target diff --git a/mk/platform.mk b/mk/platform.mk index d601cab7221f4..6a7a20cbfdb99 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -102,8 +102,6 @@ include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk) define ADD_INSTALLED_OBJECTS INSTALLED_OBJECTS_$(1) += $$(CFG_INSTALLED_OBJECTS_$(1)) REQUIRED_OBJECTS_$(1) += $$(CFG_THIRD_PARTY_OBJECTS_$(1)) - INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) - REQUIRED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) endef $(foreach target,$(CFG_TARGET), \ diff --git a/mk/rt.mk b/mk/rt.mk index e86aec60893e9..bcbed333e0f7f 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -37,6 +37,16 @@ ################################################################################ NATIVE_LIBS := hoedown miniz rust_test_helpers +# A macro to add a generic implementation of intrinsics iff a arch optimized implementation is not +# already in the list. +# $(1) is the target +# $(2) is the intrinsic +define ADD_INTRINSIC + ifeq ($$(findstring X,$$(foreach intrinsic,$$(COMPRT_OBJS_$(1)),$$(if $$(findstring $(2),$$(intrinsic)),X,))),) + COMPRT_OBJS_$(1) += $(2) + endif +endef + # $(1) is the target triple define NATIVE_LIBRARIES @@ -230,167 +240,15 @@ COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1)) COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt -# GENERIC_SOURCES in CMakeLists.txt -COMPRT_OBJS_$(1) := \ - absvdi2.o \ - absvsi2.o \ - adddf3.o \ - addsf3.o \ - addvdi3.o \ - addvsi3.o \ - apple_versioning.o \ - ashldi3.o \ - ashrdi3.o \ - clear_cache.o \ - clzdi2.o \ - clzsi2.o \ - cmpdi2.o \ - comparedf2.o \ - comparesf2.o \ - ctzdi2.o \ - ctzsi2.o \ - divdc3.o \ - divdf3.o \ - divdi3.o \ - divmoddi4.o \ - divmodsi4.o \ - divsc3.o \ - divsf3.o \ - divsi3.o \ - divxc3.o \ - extendsfdf2.o \ - extendhfsf2.o \ - ffsdi2.o \ - fixdfdi.o \ - fixdfsi.o \ - fixsfdi.o \ - fixsfsi.o \ - fixunsdfdi.o \ - fixunsdfsi.o \ - fixunssfdi.o \ - fixunssfsi.o \ - fixunsxfdi.o \ - fixunsxfsi.o \ - fixxfdi.o \ - floatdidf.o \ - floatdisf.o \ - floatdixf.o \ - floatsidf.o \ - floatsisf.o \ - floatundidf.o \ - floatundisf.o \ - floatundixf.o \ - floatunsidf.o \ - floatunsisf.o \ - int_util.o \ - lshrdi3.o \ - moddi3.o \ - modsi3.o \ - muldc3.o \ - muldf3.o \ - muldi3.o \ - mulodi4.o \ - mulosi4.o \ - muloti4.o \ - mulsc3.o \ - mulsf3.o \ - mulvdi3.o \ - mulvsi3.o \ - mulxc3.o \ - negdf2.o \ - negdi2.o \ - negsf2.o \ - negvdi2.o \ - negvsi2.o \ - paritydi2.o \ - paritysi2.o \ - popcountdi2.o \ - popcountsi2.o \ - powidf2.o \ - powisf2.o \ - powixf2.o \ - subdf3.o \ - subsf3.o \ - subvdi3.o \ - subvsi3.o \ - truncdfhf2.o \ - truncdfsf2.o \ - truncsfhf2.o \ - ucmpdi2.o \ - udivdi3.o \ - udivmoddi4.o \ - udivmodsi4.o \ - udivsi3.o \ - umoddi3.o \ - umodsi3.o - -ifeq ($$(findstring ios,$(1)),) -COMPRT_OBJS_$(1) += \ - absvti2.o \ - addtf3.o \ - addvti3.o \ - ashlti3.o \ - ashrti3.o \ - clzti2.o \ - cmpti2.o \ - ctzti2.o \ - divtf3.o \ - divti3.o \ - ffsti2.o \ - fixdfti.o \ - fixsfti.o \ - fixunsdfti.o \ - fixunssfti.o \ - fixunsxfti.o \ - fixxfti.o \ - floattidf.o \ - floattisf.o \ - floattixf.o \ - floatuntidf.o \ - floatuntisf.o \ - floatuntixf.o \ - lshrti3.o \ - modti3.o \ - multf3.o \ - multi3.o \ - mulvti3.o \ - negti2.o \ - negvti2.o \ - parityti2.o \ - popcountti2.o \ - powitf2.o \ - subtf3.o \ - subvti3.o \ - trampoline_setup.o \ - ucmpti2.o \ - udivmodti4.o \ - udivti3.o \ - umodti3.o -endif - -ifeq ($$(findstring apple,$(1)),apple) -COMPRT_OBJS_$(1) += \ - atomic_flag_clear.o \ - atomic_flag_clear_explicit.o \ - atomic_flag_test_and_set.o \ - atomic_flag_test_and_set_explicit.o \ - atomic_signal_fence.o \ - atomic_thread_fence.o -endif +# We must avoid compiling both a generic implementation (e.g. `floatdidf.c) and an arch optimized +# implementation (e.g. `x86_64/floatdidf.S) of the same symbol (e.g. `floatdidf) because that causes +# linker errors. To avoid that, we first add all the arch optimized implementations and then add the +# generic implementations if and only if its arch optimized version is not already in the list. This +# last part is handled by the ADD_INTRINSIC macro. - -ifeq ($$(findstring windows,$(1)),) -COMPRT_OBJS_$(1) += emutls.o -endif +COMPRT_OBJS_$(1) := ifeq ($$(findstring msvc,$(1)),) - -ifeq ($$(findstring freebsd,$(1)),) -COMPRT_OBJS_$(1) += gcc_personality_v0.o -endif - -COMPRT_OBJS_$(1) += emutls.o - ifeq ($$(findstring x86_64,$(1)),x86_64) COMPRT_OBJS_$(1) += \ x86_64/chkstk.o \ @@ -540,9 +398,168 @@ COMPRT_OBJS_$(1) += \ arm/unordsf2vfp.o endif +$(foreach intrinsic,absvdi2.o \ + absvsi2.o \ + adddf3.o \ + addsf3.o \ + addvdi3.o \ + addvsi3.o \ + apple_versioning.o \ + ashldi3.o \ + ashrdi3.o \ + clear_cache.o \ + clzdi2.o \ + clzsi2.o \ + cmpdi2.o \ + comparedf2.o \ + comparesf2.o \ + ctzdi2.o \ + ctzsi2.o \ + divdc3.o \ + divdf3.o \ + divdi3.o \ + divmoddi4.o \ + divmodsi4.o \ + divsc3.o \ + divsf3.o \ + divsi3.o \ + divxc3.o \ + extendsfdf2.o \ + extendhfsf2.o \ + ffsdi2.o \ + fixdfdi.o \ + fixdfsi.o \ + fixsfdi.o \ + fixsfsi.o \ + fixunsdfdi.o \ + fixunsdfsi.o \ + fixunssfdi.o \ + fixunssfsi.o \ + fixunsxfdi.o \ + fixunsxfsi.o \ + fixxfdi.o \ + floatdidf.o \ + floatdisf.o \ + floatdixf.o \ + floatsidf.o \ + floatsisf.o \ + floatundidf.o \ + floatundisf.o \ + floatundixf.o \ + floatunsidf.o \ + floatunsisf.o \ + int_util.o \ + lshrdi3.o \ + moddi3.o \ + modsi3.o \ + muldc3.o \ + muldf3.o \ + muldi3.o \ + mulodi4.o \ + mulosi4.o \ + muloti4.o \ + mulsc3.o \ + mulsf3.o \ + mulvdi3.o \ + mulvsi3.o \ + mulxc3.o \ + negdf2.o \ + negdi2.o \ + negsf2.o \ + negvdi2.o \ + negvsi2.o \ + paritydi2.o \ + paritysi2.o \ + popcountdi2.o \ + popcountsi2.o \ + powidf2.o \ + powisf2.o \ + powixf2.o \ + subdf3.o \ + subsf3.o \ + subvdi3.o \ + subvsi3.o \ + truncdfhf2.o \ + truncdfsf2.o \ + truncsfhf2.o \ + ucmpdi2.o \ + udivdi3.o \ + udivmoddi4.o \ + udivmodsi4.o \ + udivsi3.o \ + umoddi3.o \ + umodsi3.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) + +ifeq ($$(findstring ios,$(1)),) +$(foreach intrinsic,absvti2.o \ + addtf3.o \ + addvti3.o \ + ashlti3.o \ + ashrti3.o \ + clzti2.o \ + cmpti2.o \ + ctzti2.o \ + divtf3.o \ + divti3.o \ + ffsti2.o \ + fixdfti.o \ + fixsfti.o \ + fixunsdfti.o \ + fixunssfti.o \ + fixunsxfti.o \ + fixxfti.o \ + floattidf.o \ + floattisf.o \ + floattixf.o \ + floatuntidf.o \ + floatuntisf.o \ + floatuntixf.o \ + lshrti3.o \ + modti3.o \ + multf3.o \ + multi3.o \ + mulvti3.o \ + negti2.o \ + negvti2.o \ + parityti2.o \ + popcountti2.o \ + powitf2.o \ + subtf3.o \ + subvti3.o \ + trampoline_setup.o \ + ucmpti2.o \ + udivmodti4.o \ + udivti3.o \ + umodti3.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) +endif + +ifeq ($$(findstring apple,$(1)),apple) +$(foreach intrinsic,atomic_flag_clear.o \ + atomic_flag_clear_explicit.o \ + atomic_flag_test_and_set.o \ + atomic_flag_test_and_set_explicit.o \ + atomic_signal_fence.o \ + atomic_thread_fence.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) +endif + +ifeq ($$(findstring windows,$(1)),) +$(call ADD_INTRINSIC,$(1),emutls.o) +endif + +ifeq ($$(findstring msvc,$(1)),) + +ifeq ($$(findstring freebsd,$(1)),) +$(call ADD_INTRINSIC,$(1),gcc_personality_v0.o) +endif + +$(call ADD_INTRINSIC,$(1),emutls.o) +endif + ifeq ($$(findstring aarch64,$(1)),aarch64) -COMPRT_OBJS_$(1) += \ - comparetf2.o \ +$(foreach intrinsic,comparetf2.o \ extenddftf2.o \ extendsftf2.o \ fixtfdi.o \ @@ -557,7 +574,8 @@ COMPRT_OBJS_$(1) += \ floatunsitf.o \ multc3.o \ trunctfdf2.o \ - trunctfsf2.o + trunctfsf2.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) endif ifeq ($$(findstring msvc,$(1)),msvc) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index a466e2e6897f8..a1e286e162ffa 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -28,7 +28,6 @@ pub fn clean(build: &Build) { let out = build.out.join(host); - rm_rf(build, &out.join("compiler-rt")); rm_rf(build, &out.join("doc")); for stage in 0..4 { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca9..60bf52a514c37 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -35,13 +35,23 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { println!("Building stage{} std artifacts ({} -> {})", compiler.stage, compiler.host, target); - // Move compiler-rt into place as it'll be required by the compiler when - // building the standard library to link the dylib of libstd let libdir = build.sysroot_libdir(compiler, target); let _ = fs::remove_dir_all(&libdir); t!(fs::create_dir_all(&libdir)); - copy(&build.compiler_rt_built.borrow()[target], - &libdir.join(staticlib("compiler-rt", target))); + // FIXME(stage0) remove this `if` after the next snapshot + // The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap` + // never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's + // `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use + // an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make + // it to the final binary because now `libcore.rlib` also contains the symbols that + // `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its + // symbols are used instead of `libcompiler-rt.a`'s. + if compiler.stage == 0 { + let rtlib = &staticlib("compiler-rt", target); + let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib") + .join(target).join("lib").join(rtlib); + copy(&src, &libdir.join(rtlib)); + } // Some platforms have startup objects that may be required to produce the // libstd dynamic library, for example. @@ -83,12 +93,10 @@ pub fn std_link(build: &Build, // If we're linking one compiler host's output into another, then we weren't // called from the `std` method above. In that case we clean out what's - // already there and then also link compiler-rt into place. + // already there. if host != compiler.host { let _ = fs::remove_dir_all(&libdir); t!(fs::create_dir_all(&libdir)); - copy(&build.compiler_rt_built.borrow()[target], - &libdir.join(staticlib("compiler-rt", target))); } add_to_sysroot(&out_dir, &libdir); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea2546..4beba5c8852b6 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -28,7 +28,6 @@ extern crate rustc_serialize; extern crate toml; extern crate regex; -use std::cell::RefCell; use std::collections::HashMap; use std::env; use std::fs::{self, File}; @@ -131,7 +130,6 @@ pub struct Build { // Runtime state filled in later on cc: HashMap)>, cxx: HashMap, - compiler_rt_built: RefCell>, } /// The various "modes" of invoking Cargo. @@ -198,7 +196,6 @@ impl Build { package_vers: String::new(), cc: HashMap::new(), cxx: HashMap::new(), - compiler_rt_built: RefCell::new(HashMap::new()), gdb_version: None, lldb_version: None, lldb_python_dir: None, @@ -252,9 +249,6 @@ impl Build { Llvm { _dummy } => { native::llvm(self, target.target); } - CompilerRt { _dummy } => { - native::compiler_rt(self, target.target); - } TestHelpers { _dummy } => { native::test_helpers(self, target.target); } @@ -839,11 +833,6 @@ impl Build { } } - /// Root output directory for compiler-rt compiled for `target` - fn compiler_rt_out(&self, target: &str) -> PathBuf { - self.out.join(target).join("compiler-rt") - } - /// Root output directory for rust_test_helpers library compiled for /// `target` fn test_helpers_out(&self, target: &str) -> PathBuf { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a4518d6ed7619..df6408e5fe1c8 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -27,7 +27,7 @@ use cmake; use gcc; use Build; -use util::{staticlib, up_to_date}; +use util::up_to_date; /// Compile LLVM for `target`. pub fn llvm(build: &Build, target: &str) { @@ -131,401 +131,6 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version) } -/// Compiles the `compiler-rt` library, or at least the builtins part of it. -/// -/// Note that while compiler-rt has a build system associated with it, we -/// specifically don't use it here. The compiler-rt build system, written in -/// CMake, is actually *very* difficult to work with in terms of getting it to -/// compile on all the relevant platforms we want it to compile on. In the end -/// it became so much pain to work with local patches, work around the oddities -/// of the build system, etc, that we're just building everything by hand now. -/// -/// In general compiler-rt is just a bunch of intrinsics that are in practice -/// *very* stable. We just need to make sure that all the relevant functions and -/// such are compiled somewhere and placed in an object file somewhere. -/// Eventually, these should all be written in Rust! -/// -/// So below you'll find a listing of every single file in the compiler-rt repo -/// that we're compiling. We just reach in and compile with the `gcc` crate -/// which should have all the relevant flags and such already configured. -/// -/// The risk here is that if we update compiler-rt we may need to compile some -/// new intrinsics, but to be honest we surely don't use all of the intrinsics -/// listed below today so the likelihood of us actually needing a new intrinsic -/// is quite low. The failure case is also just that someone reports a link -/// error (if any) and then we just add it to the list. Overall, that cost is -/// far far less than working with compiler-rt's build system over time. -pub fn compiler_rt(build: &Build, target: &str) { - let build_dir = build.compiler_rt_out(target); - let output = build_dir.join(staticlib("compiler-rt", target)); - build.compiler_rt_built.borrow_mut().insert(target.to_string(), - output.clone()); - t!(fs::create_dir_all(&build_dir)); - - let mut cfg = gcc::Config::new(); - cfg.cargo_metadata(false) - .out_dir(&build_dir) - .target(target) - .host(&build.config.build) - .opt_level(2) - .debug(false); - - if target.contains("msvc") { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); - } else { - // Turn off various features of gcc and such, mostly copying - // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - } - - let mut sources = vec![ - "absvdi2.c", - "absvsi2.c", - "adddf3.c", - "addsf3.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "ashldi3.c", - "ashrdi3.c", - "clear_cache.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divdi3.c", - "divmoddi4.c", - "divmodsi4.c", - "divsc3.c", - "divsf3.c", - "divsi3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "lshrdi3.c", - "moddi3.c", - "modsi3.c", - "muldc3.c", - "muldf3.c", - "muldi3.c", - "mulodi4.c", - "mulosi4.c", - "muloti4.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powidf2.c", - "powisf2.c", - "powixf2.c", - "subdf3.c", - "subsf3.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", - "udivdi3.c", - "udivmoddi4.c", - "udivmodsi4.c", - "udivsi3.c", - "umoddi3.c", - "umodsi3.c", - ]; - - if !target.contains("ios") { - sources.extend(vec![ - "absvti2.c", - "addtf3.c", - "addvti3.c", - "ashlti3.c", - "ashrti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "divtf3.c", - "divti3.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "lshrti3.c", - "modti3.c", - "multf3.c", - "multi3.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "powitf2.c", - "subtf3.c", - "subvti3.c", - "trampoline_setup.c", - "ucmpti2.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c", - ]); - } - - if target.contains("apple") { - sources.extend(vec![ - "atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c", - ]); - } - - if !target.contains("windows") { - sources.push("emutls.c"); - } - - if target.contains("msvc") { - if target.contains("x86_64") { - sources.extend(vec![ - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - ]); - } - } else { - if !target.contains("freebsd") { - sources.push("gcc_personality_v0.c"); - } - - if target.contains("x86_64") { - sources.extend(vec![ - "x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", - ]); - } - - if target.contains("i386") || - target.contains("i586") || - target.contains("i686") { - sources.extend(vec![ - "i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S", - ]); - } - } - - if target.contains("arm") && !target.contains("ios") { - sources.extend(vec![ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/aeabi_idivmod.S", - "arm/aeabi_ldivmod.S", - "arm/aeabi_memcmp.S", - "arm/aeabi_memcpy.S", - "arm/aeabi_memmove.S", - "arm/aeabi_memset.S", - "arm/aeabi_uidivmod.S", - "arm/aeabi_uldivmod.S", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S", - ]); - } - - if target.contains("armv7") { - sources.extend(vec![ - "arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S", - ]); - } - - if target.contains("eabihf") { - sources.extend(vec![ - "arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S", - "arm/truncdfsf2vfp.S", - "arm/unorddf2vfp.S", - "arm/unordsf2vfp.S", - ]); - } - - if target.contains("aarch64") { - sources.extend(vec![ - "comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c", - ]); - } - - let mut out_of_date = false; - for src in sources { - let src = build.src.join("src/compiler-rt/lib/builtins").join(src); - out_of_date = out_of_date || !up_to_date(&src, &output); - cfg.file(src); - } - if !out_of_date { - return - } - cfg.compile("libcompiler-rt.a"); -} - /// Compiles the `rust_test_helpers.c` library which we used in various /// `run-pass` test suites for ABI testing. pub fn test_helpers(build: &Build, target: &str) { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 12929664886c4..5f391b70fbe88 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -82,7 +82,6 @@ macro_rules! targets { // There aren't really any parameters to this, but empty structs // with braces are unstable so we just pick something that works. (llvm, Llvm { _dummy: () }), - (compiler_rt, CompilerRt { _dummy: () }), (test_helpers, TestHelpers { _dummy: () }), (debugger_scripts, DebuggerScripts { stage: u32 }), @@ -334,8 +333,7 @@ impl<'a> Step<'a> { vec![self.libstd(compiler)] } Source::Libstd { compiler } => { - vec![self.compiler_rt(()), - self.rustc(compiler.stage).target(compiler.host)] + vec![self.rustc(compiler.stage).target(compiler.host)] } Source::LibrustcLink { compiler, host } => { vec![self.librustc(compiler), @@ -348,7 +346,6 @@ impl<'a> Step<'a> { vec![self.libstd(compiler), self.target(host).rustc(compiler.stage)] } - Source::CompilerRt { _dummy } => Vec::new(), Source::Llvm { _dummy } => Vec::new(), Source::TestHelpers { _dummy } => Vec::new(), Source::DebuggerScripts { stage: _ } => Vec::new(), diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml new file mode 100644 index 0000000000000..a52873fc326b8 --- /dev/null +++ b/src/libcompiler_builtins/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "compiler_builtins" +version = "0.0.0" + +[lib] +name = "compiler_builtins" +path = "lib.rs" + +[dependencies] +core = { path = "../libcore" } + +[build-dependencies] +gcc = "0.3.27" diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs new file mode 100644 index 0000000000000..fb8e45c1fe133 --- /dev/null +++ b/src/libcompiler_builtins/build.rs @@ -0,0 +1,402 @@ +// 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. + +//! Compiles the `compiler-rt` library, or at least the builtins part of it. +//! +//! Note that while compiler-rt has a build system associated with it, we +//! specifically don't use it here. The compiler-rt build system, written in +//! CMake, is actually *very* difficult to work with in terms of getting it to +//! compile on all the relevant platforms we want it to compile on. In the end +//! it became so much pain to work with local patches, work around the oddities +//! of the build system, etc, that we're just building everything by hand now. +//! +//! In general compiler-rt is just a bunch of intrinsics that are in practice +//! *very* stable. We just need to make sure that all the relevant functions and +//! such are compiled somewhere and placed in an object file somewhere. +//! Eventually, these should all be written in Rust! +//! +//! So below you'll find a listing of every single file in the compiler-rt repo +//! that we're compiling. We just reach in and compile with the `gcc` crate +//! which should have all the relevant flags and such already configured. +//! +//! The risk here is that if we update compiler-rt we may need to compile some +//! new intrinsics, but to be honest we surely don't use all of the intrinsics +//! listed below today so the likelihood of us actually needing a new intrinsic +//! is quite low. The failure case is also just that someone reports a link +//! error (if any) and then we just add it to the list. Overall, that cost is +//! far far less than working with compiler-rt's build system over time. + +extern crate gcc; + +use std::collections::BTreeMap; +use std::env; +use std::path::Path; + +struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, +} + +impl Sources { + fn new() -> Sources { + Sources { map: BTreeMap::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + // NOTE Some intrinsics have both a generic implementation (e.g. `floatdidf.c`) and an arch + // optimized implementation (`x86_64/floatdidf.c`). In those cases, we keep the arch + // optimized implementation and discard the generic implementation. If we don't and keep + // both implementations, the linker will yell at us about duplicate symbols! + for &src in sources { + let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } + } + } +} + +fn main() { + let target = env::var("TARGET").unwrap(); + let cfg = &mut gcc::Config::new(); + + if target.contains("msvc") { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "adddf3.c", + "addsf3.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "ashldi3.c", + "ashrdi3.c", + "clear_cache.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divdi3.c", + "divmoddi4.c", + "divmodsi4.c", + "divsc3.c", + "divsf3.c", + "divsi3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "lshrdi3.c", + "moddi3.c", + "modsi3.c", + "muldc3.c", + "muldf3.c", + "muldi3.c", + "mulodi4.c", + "mulosi4.c", + "muloti4.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powidf2.c", + "powisf2.c", + "powixf2.c", + "subdf3.c", + "subsf3.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + "udivdi3.c", + "udivmoddi4.c", + "udivmodsi4.c", + "udivsi3.c", + "umoddi3.c", + "umodsi3.c"]); + + if !target.contains("ios") { + sources.extend(&["absvti2.c", + "addtf3.c", + "addvti3.c", + "ashlti3.c", + "ashrti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "divtf3.c", + "divti3.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "lshrti3.c", + "modti3.c", + "multf3.c", + "multi3.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "powitf2.c", + "subtf3.c", + "subvti3.c", + "trampoline_setup.c", + "ucmpti2.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c"]); + } + + if target.contains("apple") { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); + } + + if !target.contains("windows") { + sources.extend(&["emutls.c"]); + } + + if target.contains("msvc") { + if target.contains("x86_64") { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if !target.contains("freebsd") { + sources.extend(&["gcc_personality_v0.c"]); + } + + if target.contains("x86_64") { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); + } + + if target.contains("i386") || target.contains("i586") || target.contains("i686") { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); + } + } + + if target.contains("arm") && !target.contains("ios") { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/aeabi_idivmod.S", + "arm/aeabi_ldivmod.S", + "arm/aeabi_memcmp.S", + "arm/aeabi_memcpy.S", + "arm/aeabi_memmove.S", + "arm/aeabi_memset.S", + "arm/aeabi_uidivmod.S", + "arm/aeabi_uldivmod.S", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); + } + + if target.contains("armv7") { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); + } + + if target.contains("eabihf") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S", + "arm/truncdfsf2vfp.S", + "arm/unorddf2vfp.S", + "arm/unordsf2vfp.S"]); + } + + if target.contains("aarch64") { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } + + for src in sources.map.values() { + cfg.file(Path::new("../compiler-rt/lib/builtins").join(src)); + } + + cfg.compile("libcompiler-rt.a"); +} diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs new file mode 100644 index 0000000000000..ad1d1edbeba29 --- /dev/null +++ b/src/libcompiler_builtins/lib.rs @@ -0,0 +1,16 @@ +// 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. + +#![cfg_attr(not(stage0), feature(compiler_builtins))] +#![no_std] +#![cfg_attr(not(stage0), compiler_builtins)] + +#![crate_name = "compiler_builtins"] +#![crate_type = "rlib"] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index d1722ac6f2f7f..b8465e63b1c8a 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -210,6 +210,7 @@ pub trait CrateStore<'tcx> { fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool; + fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool; fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy; fn extern_crate(&self, cnum: ast::CrateNum) -> Option; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; @@ -405,6 +406,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") } fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") } fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool { bug!("is_panic_runtime") } + fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_compiler_builtins") } fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy { bug!("panic_strategy") } diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 07eb191471c46..9ccfdbb129c73 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -18,7 +18,6 @@ pub fn target() -> Result { dynamic_linking: false, executables: true, exe_suffix: ".js".to_string(), - no_compiler_rt: true, linker_is_gnu: true, allow_asm: false, obj_is_bitcode: true, diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index 25132f8a044d6..9ba6591f587c4 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -22,7 +22,6 @@ pub fn target() -> TargetResult { dynamic_linking: false, executables: true, exe_suffix: ".pexe".to_string(), - no_compiler_rt: false, linker_is_gnu: true, allow_asm: false, max_atomic_width: 32, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d48370b23b69d..1a26ffaf1e134 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -306,9 +306,6 @@ pub struct TargetOptions { pub allows_weak_linkage: bool, /// Whether the linker support rpaths or not. Defaults to false. pub has_rpath: bool, - /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM - /// will emit references to the functions that compiler-rt provides. - pub no_compiler_rt: bool, /// Whether to disable linking to the default libraries, typically corresponds /// to `-nodefaultlibs`. Defaults to true. pub no_default_libraries: bool, @@ -381,7 +378,6 @@ impl Default for TargetOptions { linker_is_gnu: false, allows_weak_linkage: true, has_rpath: false, - no_compiler_rt: false, no_default_libraries: true, position_independent_executables: false, pre_link_objects_exe: Vec::new(), @@ -524,7 +520,6 @@ impl Target { key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); - key!(no_compiler_rt, bool); key!(no_default_libraries, bool); key!(position_independent_executables, bool); key!(archive_format); @@ -667,7 +662,6 @@ impl ToJson for Target { target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); - target_option_val!(no_compiler_rt); target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); target_option_val!(archive_format); diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index d7ca93235fddb..21cf3240321bf 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -346,6 +346,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).is_panic_runtime() } + fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { + self.get_crate_data(cnum).is_compiler_builtins() + } + fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy { self.get_crate_data(cnum).panic_strategy() } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 952d7008d0f27..bc3d92c11a1ea 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -340,6 +340,11 @@ impl CrateMetadata { attr::contains_name(&attrs, "needs_panic_runtime") } + pub fn is_compiler_builtins(&self) -> bool { + let attrs = decoder::get_crate_attributes(self.data()); + attr::contains_name(&attrs, "compiler_builtins") + } + pub fn panic_strategy(&self) -> PanicStrategy { decoder::get_panic_strategy(self.data()) } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b970c63a22433..3ba12ddba293d 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -573,10 +573,6 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write, fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, tempdir: &Path) { let mut ab = link_rlib(sess, None, objects, out_filename, tempdir); - if !sess.target.target.options.no_compiler_rt { - ab.add_native_library("compiler-rt"); - } - let mut all_native_libs = vec![]; each_linked_rlib(sess, &mut |cnum, path| { @@ -640,9 +636,6 @@ fn link_natively(sess: &Session, let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, outputs); - if !sess.target.target.options.no_compiler_rt { - linker.link_staticlib("compiler-rt"); - } } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -939,6 +932,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); match data[cnum as usize - 1] { + // We must always link the `compiler_builtins` crate statically. Even if it was already + // "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` is used) + _ if sess.cstore.is_compiler_builtins(cnum) => { + add_static_crate(cmd, sess, tmpdir, crate_type, + &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) + } Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 3ce6841fdd4c6..21e6acc37f3d5 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -19,6 +19,7 @@ collections = { path = "../libcollections" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } rand = { path = "../librand" } +compiler_builtins = { path = "../libcompiler_builtins" } rustc_unicode = { path = "../librustc_unicode" } unwind = { path = "../libunwind" } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4a637b5cfcff7..d227fb1404f47 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -322,6 +322,9 @@ extern crate unwind; #[cfg(stage0)] extern crate alloc_system; +// compiler-rt intrinsics +extern crate compiler_builtins; + // Make std testable by not duplicating lang items and other globals. See #2912 #[cfg(test)] extern crate std as realstd; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8b8a41fc20488..27b97a0ad665b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -298,6 +298,10 @@ declare_features! ( // elide `'static` lifetimes in `static`s and `const`s (active, static_in_const, "1.13.0", Some(35897)), + + // Used to identify the `compiler_builtins` crate + // rustc internal + (active, compiler_builtins, "1.13.0", None), ); declare_features! ( @@ -537,6 +541,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat libcore functions that are inlined \ across crates and will never be stable", cfg_fn!(rustc_attrs))), + ("compiler_builtins", Whitelisted, Gated("compiler_builtins", + "the `#[compiler_builtins]` attribute is used to \ + identify the `compiler_builtins` crate which \ + contains compiler-rt intrinsics and will never be \ + stable", + cfg_fn!(compiler_builtins))), ("allow_internal_unstable", Normal, Gated("allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE, diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index d47b541b4c3bc..747322b32f320 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -43,6 +43,14 @@ dependencies = [ "rustc_unicode 0.0.0", ] +[[package]] +name = "compiler_builtins" +version = "0.0.0" +dependencies = [ + "core 0.0.0", + "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core" version = "0.0.0" @@ -100,6 +108,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "collections 0.0.0", + "compiler_builtins 0.0.0", "core 0.0.0", "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", diff --git a/src/test/compile-fail/feature-gate-compiler-builtins.rs b/src/test/compile-fail/feature-gate-compiler-builtins.rs new file mode 100644 index 0000000000000..f9334f1d3b072 --- /dev/null +++ b/src/test/compile-fail/feature-gate-compiler-builtins.rs @@ -0,0 +1,14 @@ +// 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. + +#![compiler_builtins] //~ ERROR the `#[compiler_builtins]` attribute is + +fn main() {} + From e6da837e990a8617a3d90e906221bb32fa3fee38 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Sep 2016 10:40:22 -0500 Subject: [PATCH 689/768] it's libcompiler-rt.lib on windows --- mk/main.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index dd0136e136216..275dbb55d7483 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -456,7 +456,7 @@ TSREQ$(1)_T_$(2)_H_$(3) = \ $$(HSREQ$(1)_H_$(3)) \ $$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ - $$(TLIB0_T_$(2)_H_$(3))/libcompiler-rt.a + $$(TLIB0_T_$(2)_H_$(3))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt) # ^ This copies `libcompiler-rt.a` to the stage0 sysroot # ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0 From e5d0bb12ececde44cfe5bf67224a7557a5b5c8fb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Sep 2016 12:57:18 -0500 Subject: [PATCH 690/768] no emutls for you, windows --- mk/rt.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index bcbed333e0f7f..a67bded288e20 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -554,8 +554,6 @@ ifeq ($$(findstring msvc,$(1)),) ifeq ($$(findstring freebsd,$(1)),) $(call ADD_INTRINSIC,$(1),gcc_personality_v0.o) endif - -$(call ADD_INTRINSIC,$(1),emutls.o) endif ifeq ($$(findstring aarch64,$(1)),aarch64) From 521ffe9dbe8ed03ea8b2efdfe2b2bc1d6e1d7847 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Sep 2016 16:24:26 -0500 Subject: [PATCH 691/768] it's also compiler-rt.lib on windows-gnu --- src/bootstrap/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index dfc1c7a243b5b..6c0a32a54d919 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -23,7 +23,7 @@ use filetime::FileTime; /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { - if target.contains("windows-msvc") { + if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) From 5798003438469313c0616270b8b285d9afbb4730 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Tue, 13 Sep 2016 10:13:52 +0530 Subject: [PATCH 692/768] Doc correction: btree --- src/libcollections/btree/set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 49da3aa480c31..fc2a7f825474d 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -674,7 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Makes a empty `BTreeSet` with a reasonable choice of B. + /// Makes an empty `BTreeSet` with a reasonable choice of B. fn default() -> BTreeSet { BTreeSet::new() } From 194a91b0ce12d85a6a7ae1db20b3f4aa8408b80d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 21:46:35 -0700 Subject: [PATCH 693/768] rustbuild: Fix dependency tracking with new Cargo The recent Cargo update changed filenames, which broke a lot of incremental rustbuild builds. What it thought were the output files were indeed no longer the output files! (wreaking havoc). This commit updates this to stop guessing filenames of Cargo and just manage stamp files instead. --- src/bootstrap/compile.rs | 45 +++++++++++++++++++++++++++++++++------- src/bootstrap/lib.rs | 2 ++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca9..11fe5fe6caad9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -16,12 +16,14 @@ //! compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. +use std::cmp; use std::collections::HashMap; -use std::fs; +use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::output; +use filetime::FileTime; use util::{exe, staticlib, libdir, mtime, is_dylib, copy}; use {Build, Compiler, Mode}; @@ -66,6 +68,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); + update_mtime(&libstd_stamp(build, compiler, target)); std_link(build, target, compiler, compiler.host); } @@ -141,11 +144,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { println!("Building stage{} test artifacts ({} -> {})", compiler.stage, compiler.host, target); let out_dir = build.cargo_out(compiler, Mode::Libtest, target); - build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target)); + build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); + update_mtime(&libtest_stamp(build, compiler, target)); test_link(build, target, compiler, compiler.host); } @@ -173,7 +177,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { compiler.stage, compiler.host, target); let out_dir = build.cargo_out(compiler, Mode::Librustc, target); - build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target)); + build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build"); cargo.arg("--features").arg(build.rustc_features()) @@ -238,14 +242,14 @@ pub fn rustc_link(build: &Build, /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { - build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib") +fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. -fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { - build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib") +fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } fn compiler_file(compiler: &Path, file: &str) -> PathBuf { @@ -358,10 +362,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) { // Maybe when libstd is compiled it should clear out the rustc of the // corresponding stage? // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); - // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); + // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build"); cargo.arg("--manifest-path") .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool))); build.run(&mut cargo); } + +/// Updates the mtime of a stamp file if necessary, only changing it if it's +/// older than some other file in the same directory. +/// +/// We don't know what file Cargo is going to output (because there's a hash in +/// the file name) but we know where it's going to put it. We use this helper to +/// detect changes to that output file by looking at the modification time for +/// all files in a directory and updating the stamp if any are newer. +fn update_mtime(path: &Path) { + let mut max = None; + if let Ok(entries) = path.parent().unwrap().read_dir() { + for entry in entries.map(|e| t!(e)) { + if t!(entry.file_type()).is_file() { + let meta = t!(entry.metadata()); + let time = FileTime::from_last_modification_time(&meta); + max = cmp::max(max, Some(time)); + } + } + } + + if !max.is_none() && max <= Some(mtime(path)) { + return + } + t!(File::create(path)); +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea2546..c2dbfe1bbc58f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -585,6 +585,8 @@ impl Build { if mtime(&stamp) < mtime(input) { self.verbose(&format!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); + } else if stamp.exists() { + return } t!(fs::create_dir_all(dir)); t!(File::create(stamp)); From 2140c4ba36301a71f43f4d488c45bc8ca27bf386 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 21:24:40 -0700 Subject: [PATCH 694/768] rustc: Always link compiler-builtins last All crates depend on compiler-builtins, so we need to always include the crate last. --- src/librustc_trans/back/link.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3ba12ddba293d..3433b866691cc 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -926,17 +926,19 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // crates. let deps = sess.cstore.used_crates(LinkagePreference::RequireDynamic); + let mut compiler_builtins = None; + for &(cnum, _) in &deps { // We may not pass all crates through to the linker. Some crates may // appear statically in an existing dylib, meaning we'll pick up all the // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); match data[cnum as usize - 1] { - // We must always link the `compiler_builtins` crate statically. Even if it was already - // "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` is used) + // compiler-builtins are always placed last to ensure that they're + // linked correctly. _ if sess.cstore.is_compiler_builtins(cnum) => { - add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) + assert!(compiler_builtins.is_none()); + compiler_builtins = Some(cnum); } Linkage::NotLinked | Linkage::IncludedFromDylib => {} @@ -950,6 +952,15 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } } + // We must always link the `compiler_builtins` crate statically. Even if it + // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` + // is used) + if let Some(cnum) = compiler_builtins { + let src = sess.cstore.used_crate_source(cnum); + add_static_crate(cmd, sess, tmpdir, crate_type, + &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)); + } + // Converts a library file-stem into a cc -l argument fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { if stem.starts_with("lib") && !config.target.options.is_like_windows { From 50f94f6c95c944f08c4af264f48260e42efefd47 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 2 Sep 2016 22:01:35 +0000 Subject: [PATCH 695/768] Avoid needless reexpansions. --- src/libsyntax/ext/base.rs | 15 ++++++++++----- src/libsyntax_ext/format.rs | 19 ++++++++----------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index edd38ea23e2fd..f6eb6f1da4f19 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*; use ast; use ast::{Name, PatKind}; use attr::HasAttrs; -use codemap::{self, CodeMap, ExpnInfo}; +use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; use ext; @@ -805,8 +805,8 @@ impl<'a> ExtCtxt<'a> { /// Extract a string literal from the macro expanded version of `expr`, /// emitting `err_msg` if `expr` is not a string literal. This does not stop /// compilation on error, merely emits a non-fatal error and returns None. -pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) - -> Option<(InternedString, ast::StrStyle)> { +pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) + -> Option> { // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { expr.span.expn_id = cx.backtrace; @@ -817,7 +817,7 @@ pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) let expr = cx.expander().fold_expr(expr); match expr.node { ast::ExprKind::Lit(ref l) => match l.node { - ast::LitKind::Str(ref s, style) => return Some(((*s).clone(), style)), + ast::LitKind::Str(ref s, style) => return Some(respan(expr.span, (s.clone(), style))), _ => cx.span_err(l.span, err_msg) }, _ => cx.span_err(expr.span, err_msg) @@ -825,6 +825,11 @@ pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) None } +pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) + -> Option<(InternedString, ast::StrStyle)> { + expr_to_spanned_string(cx, expr, err_msg).map(|s| s.node) +} + /// Non-fatally assert that `tts` is empty. Note that this function /// returns even when `tts` is non-empty, macros that *need* to stop /// compilation should call @@ -851,7 +856,7 @@ pub fn get_single_str_from_tts(cx: &mut ExtCtxt, cx.span_err(sp, &format!("{} takes 1 argument", name)); return None } - let ret = cx.expander().fold_expr(panictry!(p.parse_expr())); + let ret = panictry!(p.parse_expr()); if p.token != token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 06b16095d1963..892ebcfa76129 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -17,7 +17,6 @@ use syntax::ast; use syntax::ext::base::*; use syntax::ext::base; use syntax::ext::build::AstBuilder; -use syntax::fold::Folder; use syntax::parse::token::{self, keywords}; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; @@ -702,10 +701,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let macsp = ecx.call_site(); - // Expand the format literal so that efmt.span will have a backtrace. This - // is essential for locating a bug when the format literal is generated in - // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")). - let efmt = ecx.expander().fold_expr(efmt); + let msg = "format argument must be a string literal."; + let fmt = match expr_to_spanned_string(ecx, efmt, msg) { + Some(fmt) => fmt, + None => return DummyResult::raw_expr(sp), + }; + let mut cx = Context { ecx: ecx, args: args, @@ -723,14 +724,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, str_pieces: Vec::new(), all_pieces_simple: true, macsp: macsp, - fmtsp: efmt.span, - }; - let fmt = match expr_to_string(cx.ecx, efmt, "format argument must be a string literal.") { - Some((fmt, _)) => fmt, - None => return DummyResult::raw_expr(sp), + fmtsp: fmt.span, }; - let mut parser = parse::Parser::new(&fmt); + let mut parser = parse::Parser::new(&fmt.node.0); let mut pieces = vec![]; loop { From 60440b226d2f70bdae803443ff7ad2e2af2c9b10 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 4 Sep 2016 22:49:45 +0000 Subject: [PATCH 696/768] Refactor `noop_fold_stmt_kind` out of `noop_fold_stmt`. --- src/libsyntax/fold.rs | 50 +++++++++++-------------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 7500bfe9caa80..9fb4d0203f41e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1320,51 +1320,27 @@ pub fn noop_fold_exprs(es: Vec>, folder: &mut T) -> Vec(Stmt {node, span, id}: Stmt, folder: &mut T) - -> SmallVector { +pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVector { let id = folder.new_id(id); let span = folder.new_span(span); + noop_fold_stmt_kind(node, folder).into_iter().map(|node| { + Stmt { id: id, node: node, span: span } + }).collect() +} +pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVector { match node { - StmtKind::Local(local) => SmallVector::one(Stmt { - id: id, - node: StmtKind::Local(folder.fold_local(local)), - span: span, - }), - StmtKind::Item(item) => folder.fold_item(item).into_iter().map(|item| Stmt { - id: id, - node: StmtKind::Item(item), - span: span, - }).collect(), + StmtKind::Local(local) => SmallVector::one(StmtKind::Local(folder.fold_local(local))), + StmtKind::Item(item) => folder.fold_item(item).into_iter().map(StmtKind::Item).collect(), StmtKind::Expr(expr) => { - if let Some(expr) = folder.fold_opt_expr(expr) { - SmallVector::one(Stmt { - id: id, - node: StmtKind::Expr(expr), - span: span, - }) - } else { - SmallVector::zero() - } + folder.fold_opt_expr(expr).into_iter().map(StmtKind::Expr).collect() } StmtKind::Semi(expr) => { - if let Some(expr) = folder.fold_opt_expr(expr) { - SmallVector::one(Stmt { - id: id, - node: StmtKind::Semi(expr), - span: span, - }) - } else { - SmallVector::zero() - } + folder.fold_opt_expr(expr).into_iter().map(StmtKind::Semi).collect() } - StmtKind::Mac(mac) => SmallVector::one(Stmt { - id: id, - node: StmtKind::Mac(mac.map(|(mac, semi, attrs)| { - (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) - })), - span: span, - }) + StmtKind::Mac(mac) => SmallVector::one(StmtKind::Mac(mac.map(|(mac, semi, attrs)| { + (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) + }))), } } From a9821e1658240bb2c056f260a4b6bc9789301fae Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 03:46:05 +0000 Subject: [PATCH 697/768] Refactor `ExtCtxt` to use a `Resolver` instead of a `MacroLoader`. --- src/librustc/middle/cstore.rs | 4 ++++ src/librustc_driver/driver.rs | 15 +++++++-------- src/librustc_metadata/macro_import.rs | 4 ++-- src/librustc_resolve/lib.rs | 18 +++++++++++++++++- src/libsyntax/ext/base.rs | 12 ++++++------ src/libsyntax/ext/expand.rs | 12 ++++++------ src/libsyntax/test.rs | 6 +++--- src/libsyntax_ext/rustc_macro_registrar.rs | 4 ++-- src/test/compile-fail-fulldeps/qquote.rs | 4 ++-- src/test/run-fail-fulldeps/qquote.rs | 4 ++-- src/test/run-pass-fulldeps/qquote.rs | 4 ++-- 11 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b33bc520fe216..5bbc0cd9d9071 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -39,6 +39,7 @@ use std::rc::Rc; use std::path::PathBuf; use syntax::ast; use syntax::attr; +use syntax::ext::base::LoadedMacro; use syntax::ptr::P; use syntax::parse::token::InternedString; use syntax_pos::Span; @@ -488,6 +489,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } +pub trait MacroLoader { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; +} /// Metadata encoding and decoding can make use of thread-local encoding and /// decoding contexts. These allow implementers of serialize::Encodable and diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ba6c4b9b84c37..0d9bf14f12fb2 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -638,6 +638,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, } sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?; + let mut macro_loader = + macro_import::MacroLoader::new(sess, &cstore, crate_name, krate.config.clone()); + + let resolver_arenas = Resolver::arenas(); + let mut resolver = Resolver::new(sess, make_glob_map, &mut macro_loader, &resolver_arenas); + krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their // dependencies. It's up to us to tell the system where to find all the @@ -672,14 +678,10 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, }; - let mut loader = macro_import::MacroLoader::new(sess, - &cstore, - crate_name, - krate.config.clone()); let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, - &mut loader); + &mut resolver); syntax_ext::register_builtins(&mut ecx.syntax_env); let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); if cfg!(windows) { @@ -708,9 +710,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, &sess.features.borrow()) }); - let resolver_arenas = Resolver::arenas(); - let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas); - let krate = time(sess.time_passes(), "assigning node ids", || resolver.assign_node_ids(krate)); if sess.opts.debugging_opts.input_stats { diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 22691975050e5..e41f076d64a80 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,6 +18,7 @@ use creader::{CrateReader, Macros}; use cstore::CStore; use rustc::hir::def_id::DefIndex; +use rustc::middle; use rustc::session::Session; use rustc::util::nodemap::FnvHashMap; use rustc_back::dynamic_lib::DynamicLibrary; @@ -26,7 +27,6 @@ use rustc_macro::__internal::Registry; use syntax::ast; use syntax::attr; use syntax::ext::base::LoadedMacro; -use syntax::ext; use syntax::parse::token; use syntax_ext::deriving::custom::CustomDerive; use syntax_pos::Span; @@ -55,7 +55,7 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { pub type MacroSelection = FnvHashMap; -impl<'a> ext::base::MacroLoader for MacroLoader<'a> { +impl<'a> middle::cstore::MacroLoader for MacroLoader<'a> { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c5b505fba38e9..c1e6d93a970e5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -45,6 +45,7 @@ use self::ParentLink::*; use rustc::hir::map::Definitions; use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr}; +use rustc::middle::cstore::MacroLoader; use rustc::session::Session; use rustc::lint; use rustc::hir::def::*; @@ -53,6 +54,8 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; +use syntax::ext; +use syntax::ext::base::LoadedMacro; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; @@ -1068,6 +1071,8 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, new_import_semantics: bool, // true if `#![feature(item_like_imports)]` + + macro_loader: &'a mut MacroLoader, } pub struct ResolverArenas<'a> { @@ -1149,6 +1154,12 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } +impl<'a> ext::base::Resolver for Resolver<'a> { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + self.macro_loader.load_crate(extern_crate, allows_macros) + } +} + trait Named { fn name(&self) -> Name; } @@ -1166,7 +1177,10 @@ impl Named for hir::PathSegment { } impl<'a> Resolver<'a> { - pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a ResolverArenas<'a>) + pub fn new(session: &'a Session, + make_glob_map: MakeGlobMap, + macro_loader: &'a mut MacroLoader, + arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); let graph_root = @@ -1227,6 +1241,8 @@ impl<'a> Resolver<'a> { vis: ty::Visibility::Public, }), new_import_semantics: session.features.borrow().item_like_imports, + + macro_loader: macro_loader, } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f6eb6f1da4f19..d0e11643c64c1 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -546,7 +546,7 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders } -pub trait MacroLoader { +pub trait Resolver { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; } @@ -556,8 +556,8 @@ pub enum LoadedMacro { CustomDerive(String, Box), } -pub struct DummyMacroLoader; -impl MacroLoader for DummyMacroLoader { +pub struct DummyResolver; +impl Resolver for DummyResolver { fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { Vec::new() } @@ -572,7 +572,7 @@ pub struct ExtCtxt<'a> { pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, - pub loader: &'a mut MacroLoader, + pub resolver: &'a mut Resolver, pub exported_macros: Vec, @@ -584,7 +584,7 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, ecfg: expand::ExpansionConfig<'a>, - loader: &'a mut MacroLoader) + resolver: &'a mut Resolver) -> ExtCtxt<'a> { ExtCtxt { syntax_env: initial_syntax_expander_table(&ecfg), @@ -594,7 +594,7 @@ impl<'a> ExtCtxt<'a> { ecfg: ecfg, crate_root: None, exported_macros: Vec::new(), - loader: loader, + resolver: resolver, derive_modes: HashMap::new(), recursion_count: 0, } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4715eda837490..44db1dd17ae6a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -644,7 +644,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. let is_crate_root = self.cx.syntax_env.is_crate_root(); - for def in self.cx.loader.load_crate(&*item, is_crate_root) { + for def in self.cx.resolver.load_crate(&*item, is_crate_root) { match def { LoadedMacro::Def(def) => self.cx.insert_macro(def), LoadedMacro::CustomDerive(name, ext) => { @@ -809,7 +809,7 @@ fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec { mod tests { use super::{expand_crate, ExpansionConfig}; use ast; - use ext::base::{ExtCtxt, DummyMacroLoader}; + use ext::base::{ExtCtxt, DummyResolver}; use parse; use util::parser_testing::{string_to_parser}; use visit; @@ -850,7 +850,7 @@ mod tests { src, Vec::new(), &sess).unwrap(); // should fail: - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast); } @@ -865,7 +865,7 @@ mod tests { "".to_string(), src, Vec::new(), &sess).unwrap(); - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast); } @@ -879,7 +879,7 @@ mod tests { "".to_string(), src, Vec::new(), &sess).unwrap(); - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast); } @@ -888,7 +888,7 @@ mod tests { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 3108296e778a2..dde8a8d271f62 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -28,7 +28,7 @@ use errors; use errors::snippet::{SnippetData}; use config; use entry::{self, EntryPointType}; -use ext::base::{ExtCtxt, DummyMacroLoader}; +use ext::base::{ExtCtxt, DummyResolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use fold::Folder; @@ -276,13 +276,13 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); - let mut loader = DummyMacroLoader; + let mut resolver = DummyResolver; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), - &mut loader), + &mut resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs index 7693e2416f4b0..78fed9d33dd82 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -13,7 +13,7 @@ use std::mem; use errors; use syntax::ast::{self, Ident, NodeId}; use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; -use syntax::ext::base::{ExtCtxt, DummyMacroLoader}; +use syntax::ext::base::{ExtCtxt, DummyResolver}; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::parse::ParseSess; @@ -44,7 +44,7 @@ pub fn modify(sess: &ParseSess, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut cx = ExtCtxt::new(sess, Vec::new(), ExpansionConfig::default("rustc_macro".to_string()), diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index e29ded8a052c6..3e5d17e2ffb17 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -22,11 +22,11 @@ use syntax_pos::DUMMY_SP; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut loader = syntax::ext::base::DummyMacroLoader; + let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut loader); + &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index 47e97abbbaa47..1458583ff5830 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -25,11 +25,11 @@ use syntax_pos::DUMMY_SP; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut loader = syntax::ext::base::DummyMacroLoader; + let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut loader); + &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index a4f0e35cc5ac7..2a53a62a5ab60 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -21,11 +21,11 @@ use syntax_pos::DUMMY_SP; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut loader = syntax::ext::base::DummyMacroLoader; + let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut loader); + &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { From 20b43b23230ce063ccf99a4841d85790ad311bdf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 8 Sep 2016 00:04:43 +0000 Subject: [PATCH 698/768] Rewrite the unit tests in `ext/expand.rs` as a `compile-fail` test. --- src/libsyntax/ext/expand.rs | 107 ------------------ .../compile-fail/macro-expansion-tests.rs | 46 ++++++++ 2 files changed, 46 insertions(+), 107 deletions(-) create mode 100644 src/test/compile-fail/macro-expansion-tests.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 44db1dd17ae6a..d8365391153bc 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -803,110 +803,3 @@ impl Folder for Marker { fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) } - - -#[cfg(test)] -mod tests { - use super::{expand_crate, ExpansionConfig}; - use ast; - use ext::base::{ExtCtxt, DummyResolver}; - use parse; - use util::parser_testing::{string_to_parser}; - use visit; - use visit::Visitor; - - // a visitor that extracts the paths - // from a given thingy and puts them in a mutable - // array (passed in to the traversal) - #[derive(Clone)] - struct PathExprFinderContext { - path_accumulator: Vec , - } - - impl Visitor for PathExprFinderContext { - fn visit_expr(&mut self, expr: &ast::Expr) { - if let ast::ExprKind::Path(None, ref p) = expr.node { - self.path_accumulator.push(p.clone()); - } - visit::walk_expr(self, expr); - } - } - - // these following tests are quite fragile, in that they don't test what - // *kind* of failure occurs. - - fn test_ecfg() -> ExpansionConfig<'static> { - ExpansionConfig::default("test".to_string()) - } - - // make sure that macros can't escape fns - #[should_panic] - #[test] fn macros_cant_escape_fns_test () { - let src = "fn bogus() {macro_rules! z (() => (3+4));}\ - fn inty() -> i32 { z!() }".to_string(); - let sess = parse::ParseSess::new(); - let crate_ast = parse::parse_crate_from_source_str( - "".to_string(), - src, - Vec::new(), &sess).unwrap(); - // should fail: - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast); - } - - // make sure that macros can't escape modules - #[should_panic] - #[test] fn macros_cant_escape_mods_test () { - let src = "mod foo {macro_rules! z (() => (3+4));}\ - fn inty() -> i32 { z!() }".to_string(); - let sess = parse::ParseSess::new(); - let crate_ast = parse::parse_crate_from_source_str( - "".to_string(), - src, - Vec::new(), &sess).unwrap(); - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast); - } - - // macro_use modules should allow macros to escape - #[test] fn macros_can_escape_flattened_mods_test () { - let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\ - fn inty() -> i32 { z!() }".to_string(); - let sess = parse::ParseSess::new(); - let crate_ast = parse::parse_crate_from_source_str( - "".to_string(), - src, - Vec::new(), &sess).unwrap(); - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast); - } - - fn expand_crate_str(crate_str: String) -> ast::Crate { - let ps = parse::ParseSess::new(); - let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); - // the cfg argument actually does matter, here... - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast) - } - - #[test] fn macro_tokens_should_match(){ - expand_crate_str( - "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string()); - } - - // should be able to use a bound identifier as a literal in a macro definition: - #[test] fn self_macro_parsing(){ - expand_crate_str( - "macro_rules! foo ((zz) => (287;)); - fn f(zz: i32) {foo!(zz);}".to_string() - ); - } - - // create a really evil test case where a $x appears inside a binding of $x - // but *shouldn't* bind because it was inserted by a different macro.... - // can't write this test case until we have macro-generating macros. -} diff --git a/src/test/compile-fail/macro-expansion-tests.rs b/src/test/compile-fail/macro-expansion-tests.rs new file mode 100644 index 0000000000000..a064e69bc6d59 --- /dev/null +++ b/src/test/compile-fail/macro-expansion-tests.rs @@ -0,0 +1,46 @@ +// 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. + +mod macros_cant_escape_fns { + fn f() { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } //~ ERROR macro undefined +} + +mod macros_cant_escape_mods { + mod f { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } //~ ERROR macro undefined +} + +mod macros_can_escape_flattened_mods_test { + #[macro_use] + mod f { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } +} + +fn macro_tokens_should_match() { + macro_rules! m { (a) => { 13 } } + m!(a); +} + +// should be able to use a bound identifier as a literal in a macro definition: +fn self_macro_parsing() { + macro_rules! foo { (zz) => { 287; } } + fn f(zz: i32) { + foo!(zz); + } +} + +fn main() {} From 5841678f51b9fcb085dba148639a21d95ef91423 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 22:40:14 -0700 Subject: [PATCH 699/768] rustbuild: Fix cross-compiles to MinGW on Linux Closes #36290 Closes #36291 --- src/bootstrap/compile.rs | 12 +++++++----- src/rtstartup/rsbegin.rs | 11 ++++++++++- src/rtstartup/rsend.rs | 9 ++++++++- src/rustc/std_shim/Cargo.lock | 1 + src/rustc/std_shim/Cargo.toml | 1 + src/rustc/std_shim/lib.rs | 6 ++++++ 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca9..618fa3805b37f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -117,14 +117,16 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) { return } let compiler = Compiler::new(0, &build.config.build); - let compiler = build.compiler_path(&compiler); + let compiler_path = build.compiler_path(&compiler); for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) { let file = t!(file); - build.run(Command::new(&compiler) - .arg("--emit=obj") - .arg("--out-dir").arg(into) - .arg(file.path())); + let mut cmd = Command::new(&compiler_path); + build.add_bootstrap_key(&compiler, &mut cmd); + build.run(cmd.arg("--target").arg(target) + .arg("--emit=obj") + .arg("--out-dir").arg(into) + .arg(file.path())); } for obj in ["crt2.o", "dllcrt2.o"].iter() { diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 150abc226e685..b57b7e8432167 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -22,10 +22,19 @@ // object (usually called `crtX.o), which then invokes initialization callbacks // of other runtime components (registered via yet another special image section). +#![feature(no_core, lang_items)] #![crate_type="rlib"] -#![no_std] +#![no_core] #![allow(non_camel_case_types)] +#[lang = "sized"] +trait Sized {} +#[lang = "sync"] +trait Sync {} +#[lang = "copy"] +trait Copy {} +impl Sync for T {} + #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { #[no_mangle] diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs index 915c2355b0484..4c48d9af0e1f4 100644 --- a/src/rtstartup/rsend.rs +++ b/src/rtstartup/rsend.rs @@ -10,8 +10,15 @@ // See rsbegin.rs for details. +#![feature(no_core, lang_items)] #![crate_type="rlib"] -#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "sync"] +trait Sync {} +impl Sync for T {} #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index d47b541b4c3bc..fb0885c132d5e 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -2,6 +2,7 @@ name = "std_shim" version = "0.1.0" dependencies = [ + "core 0.0.0", "std 0.0.0", ] diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 693cbe06ba987..58a7bd8a1cb75 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -41,6 +41,7 @@ debug-assertions = false [dependencies] std = { path = "../../libstd" } +core = { path = "../../libcore" } # Reexport features from std [features] diff --git a/src/rustc/std_shim/lib.rs b/src/rustc/std_shim/lib.rs index 3cf4cfab135fd..2fc5d8d6e5321 100644 --- a/src/rustc/std_shim/lib.rs +++ b/src/rustc/std_shim/lib.rs @@ -9,3 +9,9 @@ // except according to those terms. // See comments in Cargo.toml for why this exists + +// There's a bug right now where if we pass --extern std=... and we're cross +// compiling then this doesn't work with `#[macro_use] extern crate std;`. Work +// around this by not having `#[macro_use] extern crate std;` +#![no_std] +extern crate std; From 332ba1286eef931c2e48816cb207e775cc6ccd1b Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Tue, 13 Sep 2016 10:09:36 +0200 Subject: [PATCH 700/768] mk: add a all-no-docs target to build everything except docs This makes things slightly more efficient for Debian's auto-builders where the docs can be built on just one architecture, and distributed to users of all other architectures as well. --- mk/main.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index 6130b58138751..fae1546408a99 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -630,7 +630,8 @@ ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET), \ $(foreach host,$(CFG_HOST), \ all-target-$(target)-host-$(host))) -all: $(ALL_TARGET_RULES) $(GENERATED) docs +all-no-docs: $(ALL_TARGET_RULES) $(GENERATED) +all: all-no-docs docs ###################################################################### # Build system documentation From 72a636975fc5d0bb4af45af7bdd97987cc722a6a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Sep 2016 23:21:59 +0000 Subject: [PATCH 701/768] Move macro resolution into `librustc_resolve`. --- src/librustc/session/mod.rs | 9 +- src/librustc_driver/driver.rs | 9 +- src/librustc_resolve/lib.rs | 18 +- src/librustc_resolve/macros.rs | 213 ++++++++++++++++++++ src/libsyntax/ext/base.rs | 298 ++++++---------------------- src/libsyntax/ext/expand.rs | 182 +++++++---------- src/libsyntax/ext/hygiene.rs | 11 +- src/libsyntax/ext/source_util.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 4 +- src/libsyntax_ext/deriving/mod.rs | 9 +- src/libsyntax_ext/lib.rs | 88 +++++--- 11 files changed, 439 insertions(+), 406 deletions(-) create mode 100644 src/librustc_resolve/macros.rs diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3477ec6f99af1..49686d63ee43b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -21,7 +21,7 @@ use util::nodemap::{NodeMap, FnvHashMap}; use util::common::duration_to_secs_str; use mir::transform as mir_pass; -use syntax::ast::{NodeId, Name}; +use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder}; use errors::emitter::{Emitter, EmitterWriter}; use syntax::json::JsonEmitter; @@ -39,7 +39,7 @@ use llvm; use std::path::{Path, PathBuf}; use std::cell::{self, Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::env; use std::ffi::CString; use std::rc::Rc; @@ -96,10 +96,6 @@ pub struct Session { pub injected_allocator: Cell>, pub injected_panic_runtime: Cell>, - /// Names of all bang-style macros and syntax extensions - /// available in this crate - pub available_macros: RefCell>, - /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the /// macro name and defintion span in the source crate. @@ -552,7 +548,6 @@ pub fn build_session_(sopts: config::Options, next_node_id: Cell::new(1), injected_allocator: Cell::new(None), injected_panic_runtime: Cell::new(None), - available_macros: RefCell::new(HashSet::new()), imported_macro_spans: RefCell::new(HashMap::new()), incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), perf_stats: PerfStats { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 0d9bf14f12fb2..bf50c96034dd0 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -50,6 +50,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use syntax::{ast, diagnostics, visit}; use syntax::attr; +use syntax::ext::base::ExtCtxt; use syntax::parse::{self, PResult, token}; use syntax::util::node_count::NodeCounter; use syntax; @@ -643,6 +644,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, make_glob_map, &mut macro_loader, &resolver_arenas); + syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -678,16 +680,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, }; - let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess, - krate.config.clone(), - cfg, - &mut resolver); - syntax_ext::register_builtins(&mut ecx.syntax_env); + let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); if cfg!(windows) { env::set_var("PATH", &old_path); } - *sess.available_macros.borrow_mut() = ecx.syntax_env.names; ret }); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c1e6d93a970e5..6bf45ab8f6fa0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,8 +54,6 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; -use syntax::ext; -use syntax::ext::base::LoadedMacro; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; @@ -82,6 +80,7 @@ use resolve_imports::{ImportDirective, NameResolution}; // registered before they are used. mod diagnostics; +mod macros; mod check_unused; mod build_reduced_graph; mod resolve_imports; @@ -1073,6 +1072,10 @@ pub struct Resolver<'a> { new_import_semantics: bool, // true if `#![feature(item_like_imports)]` macro_loader: &'a mut MacroLoader, + macro_names: FnvHashSet, + + // Maps the `Mark` of an expansion to its containing module or block. + expansion_data: Vec, } pub struct ResolverArenas<'a> { @@ -1154,12 +1157,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } -impl<'a> ext::base::Resolver for Resolver<'a> { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { - self.macro_loader.load_crate(extern_crate, allows_macros) - } -} - trait Named { fn name(&self) -> Name; } @@ -1243,6 +1240,8 @@ impl<'a> Resolver<'a> { new_import_semantics: session.features.borrow().item_like_imports, macro_loader: macro_loader, + macro_names: FnvHashSet(), + expansion_data: vec![macros::ExpansionData::default()], } } @@ -2784,8 +2783,7 @@ impl<'a> Resolver<'a> { } fn find_best_match(&mut self, name: &str) -> SuggestionType { - if let Some(macro_name) = self.session.available_macros - .borrow().iter().find(|n| n.as_str() == name) { + if let Some(macro_name) = self.macro_names.iter().find(|n| n.as_str() == name) { return SuggestionType::Macro(format!("{}!", macro_name)); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs new file mode 100644 index 0000000000000..36f501a54d261 --- /dev/null +++ b/src/librustc_resolve/macros.rs @@ -0,0 +1,213 @@ +// 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. + +use Resolver; +use rustc::util::nodemap::FnvHashMap; +use std::cell::RefCell; +use std::mem; +use std::rc::Rc; +use syntax::ast::{self, Name}; +use syntax::errors::DiagnosticBuilder; +use syntax::ext::base::{self, LoadedMacro, MultiModifier, MultiDecorator}; +use syntax::ext::base::{NormalTT, SyntaxExtension}; +use syntax::ext::expand::{Expansion, Invocation, InvocationKind}; +use syntax::ext::hygiene::Mark; +use syntax::parse::token::intern; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::{self, Visitor}; + +#[derive(Clone, Default)] +pub struct ExpansionData { + module: Rc, +} + +// FIXME(jseyfried): merge with `::ModuleS`. +#[derive(Default)] +struct ModuleData { + parent: Option>, + macros: RefCell>>, + macros_escape: bool, +} + +impl<'a> base::Resolver for Resolver<'a> { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + self.macro_loader.load_crate(extern_crate, allows_macros) + } + + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { + expansion.visit_with(&mut ExpansionVisitor { + current_module: self.expansion_data[mark.as_u32() as usize].module.clone(), + resolver: self, + }); + } + + fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc) { + if let NormalTT(..) = *ext { + self.macro_names.insert(ident.name); + } + + let mut module = self.expansion_data[scope.as_u32() as usize].module.clone(); + while module.macros_escape { + module = module.parent.clone().unwrap(); + } + module.macros.borrow_mut().insert(ident.name, ext); + } + + fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { + self.macros_at_scope.insert(id, macros); + } + + fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { + for i in 0..attrs.len() { + let name = intern(&attrs[i].name()); + match self.expansion_data[0].module.macros.borrow().get(&name) { + Some(ext) => match **ext { + MultiModifier(..) | MultiDecorator(..) => return Some(attrs.remove(i)), + _ => {} + }, + None => {} + } + } + None + } + + fn resolve_invoc(&mut self, invoc: &Invocation) -> Option> { + let (name, span) = match invoc.kind { + InvocationKind::Bang { ref mac, .. } => { + let path = &mac.node.path; + if path.segments.len() > 1 || path.global || + !path.segments[0].parameters.is_empty() { + self.session.span_err(path.span, + "expected macro name without module separators"); + return None; + } + (path.segments[0].identifier.name, path.span) + } + InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span), + }; + + let mut module = self.expansion_data[invoc.mark().as_u32() as usize].module.clone(); + loop { + if let Some(ext) = module.macros.borrow().get(&name) { + return Some(ext.clone()); + } + match module.parent.clone() { + Some(parent) => module = parent, + None => break, + } + } + + let mut err = + self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); + self.suggest_macro_name(&name.as_str(), &mut err); + err.emit(); + None + } +} + +impl<'a> Resolver<'a> { + fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { + if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) { + if suggestion != name { + err.help(&format!("did you mean `{}!`?", suggestion)); + } else { + err.help(&format!("have you added the `#[macro_use]` on the module/import?")); + } + } + } +} + +struct ExpansionVisitor<'b, 'a: 'b> { + resolver: &'b mut Resolver<'a>, + current_module: Rc, +} + +impl<'a, 'b> ExpansionVisitor<'a, 'b> { + fn visit_invoc(&mut self, id: ast::NodeId) { + assert_eq!(id, self.resolver.expansion_data.len() as u32); + self.resolver.expansion_data.push(ExpansionData { + module: self.current_module.clone(), + }); + } + + // does this attribute list contain "macro_use"? + fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { + for attr in attrs { + if attr.check_name("macro_escape") { + let msg = "macro_escape is a deprecated synonym for macro_use"; + let mut err = self.resolver.session.struct_span_warn(attr.span, msg); + if let ast::AttrStyle::Inner = attr.node.style { + err.help("consider an outer attribute, #[macro_use] mod ...").emit(); + } else { + err.emit(); + } + } else if !attr.check_name("macro_use") { + continue; + } + + if !attr.is_word() { + self.resolver.session.span_err(attr.span, + "arguments to macro_use are not allowed here"); + } + return true; + } + + false + } +} + +macro_rules! method { + ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { + fn $visit(&mut self, node: &$ty) { + match node.node { + $invoc(..) => self.visit_invoc(node.id), + _ => visit::$walk(self, node), + } + } + } +} + +impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b> { + method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item); + method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); + method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt); + method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); + method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); + method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); + + fn visit_item(&mut self, item: &ast::Item) { + match item.node { + ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder + ast::ItemKind::Mac(..) => self.visit_invoc(item.id), + ast::ItemKind::Mod(..) => { + let module_data = ModuleData { + parent: Some(self.current_module.clone()), + macros: RefCell::new(FnvHashMap()), + macros_escape: self.contains_macro_use(&item.attrs), + }; + let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data)); + visit::walk_item(self, item); + self.current_module = orig_module; + } + _ => visit::walk_item(self, item), + } + } + + fn visit_block(&mut self, block: &ast::Block) { + let module_data = ModuleData { + parent: Some(self.current_module.clone()), + macros: RefCell::new(FnvHashMap()), + macros_escape: false, + }; + let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data)); + visit::walk_block(self, block); + self.current_module = orig_module; + } +} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d0e11643c64c1..d46e2a9872e8d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,27 +10,25 @@ pub use self::SyntaxExtension::*; -use ast; -use ast::{Name, PatKind}; +use ast::{self, Attribute, Name, PatKind}; use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; -use ext; -use ext::expand; +use ext::expand::{self, Invocation, Expansion}; +use ext::hygiene::Mark; use ext::tt::macro_rules; use parse; use parse::parser; use parse::token; -use parse::token::{InternedString, intern, str_to_ident}; +use parse::token::{InternedString, str_to_ident}; use ptr::P; use std_inject; use util::small_vector::SmallVector; -use util::lev_distance::find_best_match_for_name; use fold::Folder; use feature_gate; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; use tokenstream; @@ -44,7 +42,7 @@ pub enum Annotatable { } impl HasAttrs for Annotatable { - fn attrs(&self) -> &[ast::Attribute] { + fn attrs(&self) -> &[Attribute] { match *self { Annotatable::Item(ref item) => &item.attrs, Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, @@ -52,7 +50,7 @@ impl HasAttrs for Annotatable { } } - fn map_attrs) -> Vec>(self, f: F) -> Self { + fn map_attrs) -> Vec>(self, f: F) -> Self { match self { Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)), Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)), @@ -464,91 +462,15 @@ pub enum SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); -/// The base map of methods for expanding syntax extension -/// AST nodes into full ASTs -fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) - -> SyntaxEnv { - // utility function to simplify creating NormalTT syntax extensions - fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { - NormalTT(Box::new(f), None, false) - } - - let mut syntax_expanders = SyntaxEnv::new(); - syntax_expanders.insert(intern("macro_rules"), MacroRulesTT); - - if ecfg.enable_quotes() { - // Quasi-quoting expanders - syntax_expanders.insert(intern("quote_tokens"), - builtin_normal_expander( - ext::quote::expand_quote_tokens)); - syntax_expanders.insert(intern("quote_expr"), - builtin_normal_expander( - ext::quote::expand_quote_expr)); - syntax_expanders.insert(intern("quote_ty"), - builtin_normal_expander( - ext::quote::expand_quote_ty)); - syntax_expanders.insert(intern("quote_item"), - builtin_normal_expander( - ext::quote::expand_quote_item)); - syntax_expanders.insert(intern("quote_pat"), - builtin_normal_expander( - ext::quote::expand_quote_pat)); - syntax_expanders.insert(intern("quote_arm"), - builtin_normal_expander( - ext::quote::expand_quote_arm)); - syntax_expanders.insert(intern("quote_stmt"), - builtin_normal_expander( - ext::quote::expand_quote_stmt)); - syntax_expanders.insert(intern("quote_matcher"), - builtin_normal_expander( - ext::quote::expand_quote_matcher)); - syntax_expanders.insert(intern("quote_attr"), - builtin_normal_expander( - ext::quote::expand_quote_attr)); - syntax_expanders.insert(intern("quote_arg"), - builtin_normal_expander( - ext::quote::expand_quote_arg)); - syntax_expanders.insert(intern("quote_block"), - builtin_normal_expander( - ext::quote::expand_quote_block)); - syntax_expanders.insert(intern("quote_meta_item"), - builtin_normal_expander( - ext::quote::expand_quote_meta_item)); - syntax_expanders.insert(intern("quote_path"), - builtin_normal_expander( - ext::quote::expand_quote_path)); - } - - syntax_expanders.insert(intern("line"), - builtin_normal_expander( - ext::source_util::expand_line)); - syntax_expanders.insert(intern("column"), - builtin_normal_expander( - ext::source_util::expand_column)); - syntax_expanders.insert(intern("file"), - builtin_normal_expander( - ext::source_util::expand_file)); - syntax_expanders.insert(intern("stringify"), - builtin_normal_expander( - ext::source_util::expand_stringify)); - syntax_expanders.insert(intern("include"), - builtin_normal_expander( - ext::source_util::expand_include)); - syntax_expanders.insert(intern("include_str"), - builtin_normal_expander( - ext::source_util::expand_include_str)); - syntax_expanders.insert(intern("include_bytes"), - builtin_normal_expander( - ext::source_util::expand_include_bytes)); - syntax_expanders.insert(intern("module_path"), - builtin_normal_expander( - ext::source_util::expand_mod)); - syntax_expanders -} - pub trait Resolver { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) - -> Vec; + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); + fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc); + fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + + fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; + fn resolve_invoc(&mut self, invoc: &Invocation) -> Option>; } pub enum LoadedMacro { @@ -558,9 +480,31 @@ pub enum LoadedMacro { pub struct DummyResolver; impl Resolver for DummyResolver { - fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { + fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec { Vec::new() } + + fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} + fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc) {} + fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + + fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } + fn resolve_invoc(&mut self, _invoc: &Invocation) -> Option> { None } +} + +#[derive(Clone)] +pub struct ModuleData { + pub mod_path: Vec, + pub directory: PathBuf, +} + +#[derive(Clone)] +pub struct ExpansionData { + pub mark: Mark, + pub depth: usize, + pub backtrace: ExpnId, + pub module: Rc, + pub in_block: bool, } /// One of these is made during expansion and incrementally updated as we go; @@ -569,16 +513,12 @@ impl Resolver for DummyResolver { pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub cfg: ast::CrateConfig, - pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, pub resolver: &'a mut Resolver, - pub exported_macros: Vec, - - pub syntax_env: SyntaxEnv, pub derive_modes: HashMap>, - pub recursion_count: usize, + pub current_expansion: ExpansionData, } impl<'a> ExtCtxt<'a> { @@ -587,16 +527,20 @@ impl<'a> ExtCtxt<'a> { resolver: &'a mut Resolver) -> ExtCtxt<'a> { ExtCtxt { - syntax_env: initial_syntax_expander_table(&ecfg), parse_sess: parse_sess, cfg: cfg, - backtrace: NO_EXPANSION, ecfg: ecfg, crate_root: None, exported_macros: Vec::new(), resolver: resolver, derive_modes: HashMap::new(), - recursion_count: 0, + current_expansion: ExpansionData { + mark: Mark::root(), + depth: 0, + backtrace: NO_EXPANSION, + module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), + in_block: false, + }, } } @@ -609,23 +553,22 @@ impl<'a> ExtCtxt<'a> { -> parser::Parser<'a> { parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg()) } - pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() } pub fn call_site(&self) -> Span { - self.codemap().with_expn_info(self.backtrace, |ei| match ei { + self.codemap().with_expn_info(self.backtrace(), |ei| match ei { Some(expn_info) => expn_info.call_site, None => self.bug("missing top span") }) } - pub fn backtrace(&self) -> ExpnId { self.backtrace } + pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Span { - let mut expn_id = self.backtrace; + let mut expn_id = self.backtrace(); let mut last_macro = None; loop { if self.codemap().with_expn_info(expn_id, |info| { @@ -646,15 +589,15 @@ impl<'a> ExtCtxt<'a> { } pub fn bt_push(&mut self, ei: ExpnInfo) { - if self.recursion_count > self.ecfg.recursion_limit { + if self.current_expansion.depth > self.ecfg.recursion_limit { self.span_fatal(ei.call_site, &format!("recursion limit reached while expanding the macro `{}`", ei.callee.name())); } let mut call_site = ei.call_site; - call_site.expn_id = self.backtrace; - self.backtrace = self.codemap().record_expansion(ExpnInfo { + call_site.expn_id = self.backtrace(); + self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo { call_site: call_site, callee: ei.callee }); @@ -667,14 +610,11 @@ impl<'a> ExtCtxt<'a> { } if def.use_locally { let ext = macro_rules::compile(self, &def); - self.syntax_env.insert(def.ident.name, ext); + self.resolver.add_macro(self.current_expansion.mark, def.ident, Rc::new(ext)); } } - pub fn insert_custom_derive(&mut self, - name: &str, - ext: Box, - sp: Span) { + pub fn insert_custom_derive(&mut self, name: &str, ext: Box, sp: Span) { if !self.ecfg.enable_rustc_macro() { feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic, "rustc_macro", @@ -685,8 +625,7 @@ impl<'a> ExtCtxt<'a> { } let name = token::intern_and_get_ident(name); if self.derive_modes.insert(name.clone(), ext).is_some() { - self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", - name)); + self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name)); } } @@ -765,20 +704,6 @@ impl<'a> ExtCtxt<'a> { token::intern(st) } - pub fn suggest_macro_name(&mut self, - name: &str, - err: &mut DiagnosticBuilder<'a>) { - let names = &self.syntax_env.names; - if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) { - if suggestion != name { - err.help(&format!("did you mean `{}!`?", suggestion)); - } else { - err.help(&format!("have you added the `#[macro_use]` on the \ - module/import?")); - } - } - } - pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) { if std_inject::no_core(&krate) { self.crate_root = None; @@ -789,16 +714,16 @@ impl<'a> ExtCtxt<'a> { } for (name, extension) in user_exts { - self.syntax_env.insert(name, extension); + let ident = ast::Ident::with_empty_ctxt(name); + self.resolver.add_macro(Mark::root(), ident, Rc::new(extension)); } - self.syntax_env.current_module = Module(0); - let mut paths = ModulePaths { + let mut module = ModuleData { mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)], directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)), }; - paths.directory.pop(); - self.syntax_env.module_data[0].paths = Rc::new(paths); + module.directory.pop(); + self.current_expansion.module = Rc::new(module); } } @@ -809,7 +734,7 @@ pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &st -> Option> { // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { - expr.span.expn_id = cx.backtrace; + expr.span.expn_id = cx.backtrace(); expr }); @@ -884,104 +809,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt, } Some(es) } - -/// In order to have some notion of scoping for macros, -/// we want to implement the notion of a transformation -/// environment. -/// -/// This environment maps Names to SyntaxExtensions. -pub struct SyntaxEnv { - module_data: Vec, - pub current_module: Module, - - /// All bang-style macro/extension names - /// encountered so far; to be used for diagnostics in resolve - pub names: HashSet, -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct Module(u32); - -struct ModuleData { - parent: Module, - paths: Rc, - macros: HashMap>, - macros_escape: bool, - in_block: bool, -} - -#[derive(Clone)] -pub struct ModulePaths { - pub mod_path: Vec, - pub directory: PathBuf, -} - -impl SyntaxEnv { - fn new() -> SyntaxEnv { - let mut env = SyntaxEnv { - current_module: Module(0), - module_data: Vec::new(), - names: HashSet::new(), - }; - let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() }); - env.add_module(false, false, paths); - env - } - - fn data(&self, module: Module) -> &ModuleData { - &self.module_data[module.0 as usize] - } - - pub fn paths(&self) -> Rc { - self.data(self.current_module).paths.clone() - } - - pub fn in_block(&self) -> bool { - self.data(self.current_module).in_block - } - - pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc) - -> Module { - let data = ModuleData { - parent: self.current_module, - paths: paths, - macros: HashMap::new(), - macros_escape: macros_escape, - in_block: in_block, - }; - - self.module_data.push(data); - Module(self.module_data.len() as u32 - 1) - } - - pub fn find(&self, name: Name) -> Option> { - let mut module = self.current_module; - let mut module_data; - loop { - module_data = self.data(module); - if let Some(ext) = module_data.macros.get(&name) { - return Some(ext.clone()); - } - if module == module_data.parent { - return None; - } - module = module_data.parent; - } - } - - pub fn insert(&mut self, name: Name, ext: SyntaxExtension) { - if let NormalTT(..) = ext { - self.names.insert(name); - } - - let mut module = self.current_module; - while self.data(module).macros_escape { - module = self.data(module).parent; - } - self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext)); - } - - pub fn is_crate_root(&mut self) -> bool { - self.current_module == Module(0) - } -} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d8365391153bc..beb1687dfdc72 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -25,6 +25,7 @@ use parse::token::{intern, keywords}; use ptr::P; use tokenstream::TokenTree; use util::small_vector::SmallVector; +use visit::Visitor; use std::mem; use std::path::PathBuf; @@ -32,7 +33,8 @@ use std::rc::Rc; macro_rules! expansions { ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident, - $(.$fold:ident)* $(lift .$fold_elt:ident)*;)*) => { + $(.$fold:ident)* $(lift .$fold_elt:ident)*, + $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { #[derive(Copy, Clone)] pub enum ExpansionKind { OptExpr, $( $kind, )* } pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* } @@ -77,6 +79,17 @@ macro_rules! expansions { }, )*)* } } + + pub fn visit_with(&self, visitor: &mut V) { + match *self { + Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), + Expansion::OptExpr(None) => {} + $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)* + $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() { + visitor.$visit_elt(ast); + }, )*)* + } + } } impl<'a, 'b> Folder for MacroExpander<'a, 'b> { @@ -94,17 +107,17 @@ macro_rules! expansions { } expansions! { - Expr: P [], "expression", .make_expr, .fold_expr; - Pat: P [], "pattern", .make_pat, .fold_pat; - Ty: P [], "type", .make_ty, .fold_ty; + Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr; + Pat: P [], "pattern", .make_pat, .fold_pat, .visit_pat; + Ty: P [], "type", .make_ty, .fold_ty, .visit_ty; Stmts: SmallVector [SmallVector, ast::Stmt], - "statement", .make_stmts, lift .fold_stmt; + "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt; Items: SmallVector> [SmallVector, P], - "item", .make_items, lift .fold_item; + "item", .make_items, lift .fold_item, lift .visit_item; TraitItems: SmallVector [SmallVector, ast::TraitItem], - "trait item", .make_trait_items, lift .fold_trait_item; + "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; ImplItems: SmallVector [SmallVector, ast::ImplItem], - "impl item", .make_impl_items, lift .fold_impl_item; + "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; } impl ExpansionKind { @@ -127,15 +140,12 @@ impl ExpansionKind { } pub struct Invocation { - kind: InvocationKind, + pub kind: InvocationKind, expansion_kind: ExpansionKind, - mark: Mark, - module: Module, - backtrace: ExpnId, - depth: usize, + expansion_data: ExpansionData, } -enum InvocationKind { +pub enum InvocationKind { Bang { attrs: Vec, mac: ast::Mac, @@ -148,6 +158,19 @@ enum InvocationKind { }, } +impl Invocation { + fn span(&self) -> Span { + match self.kind { + InvocationKind::Bang { span, .. } => span, + InvocationKind::Attr { ref attr, .. } => attr.span, + } + } + + pub fn mark(&self) -> Mark { + self.expansion_data.mark + } +} + pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, pub single_step: bool, @@ -170,7 +193,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let items = Expansion::Items(SmallVector::many(krate.module.items)); krate.module.items = self.expand(items).make_items().into(); - krate.exported_macros = self.cx.exported_macros.clone(); + krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); if self.cx.parse_sess.span_diagnostic.err_count() > err_count { self.cx.parse_sess.span_diagnostic.abort_if_errors(); @@ -181,21 +204,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Fully expand all the invocations in `expansion`. fn expand(&mut self, expansion: Expansion) -> Expansion { - self.cx.recursion_count = 0; + let orig_expansion_data = self.cx.current_expansion.clone(); + self.cx.current_expansion.depth = 0; + let (expansion, mut invocations) = self.collect_invocations(expansion); invocations.reverse(); let mut expansions = vec![vec![(0, expansion)]]; while let Some(invoc) = invocations.pop() { - let Invocation { mark, module, depth, backtrace, .. } = invoc; - self.cx.syntax_env.current_module = module; - self.cx.recursion_count = depth; - self.cx.backtrace = backtrace; + let ExpansionData { depth, mark, .. } = invoc.expansion_data; + self.cx.current_expansion = invoc.expansion_data.clone(); - let expansion = self.expand_invoc(invoc); + let expansion = match self.cx.resolver.resolve_invoc(&invoc) { + Some(ext) => self.expand_invoc(invoc, ext), + None => invoc.expansion_kind.dummy(invoc.span()), + }; - self.cx.syntax_env.current_module = module; - self.cx.recursion_count = depth + 1; + self.cx.current_expansion.depth = depth + 1; let (expansion, new_invocations) = self.collect_invocations(expansion); if expansions.len() == depth { @@ -207,6 +232,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } + self.cx.current_expansion = orig_expansion_data; + let mut placeholder_expander = PlaceholderExpander::new(); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { @@ -233,30 +260,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; (expansion.fold_with(&mut collector), collector.invocations) }; - self.cx.cfg = crate_config; + + let mark = self.cx.current_expansion.mark; + self.cx.resolver.visit_expansion(mark, &result.0); result } - fn expand_invoc(&mut self, invoc: Invocation) -> Expansion { + fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { match invoc.kind { - InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc), - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc), + InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), + InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), } } - fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion { + fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { let Invocation { expansion_kind: kind, .. } = invoc; let (attr, item) = match invoc.kind { InvocationKind::Attr { attr, item } => (attr, item), _ => unreachable!(), }; - let extension = match self.cx.syntax_env.find(intern(&attr.name())) { - Some(extension) => extension, - None => unreachable!(), - }; - attr::mark_used(&attr); self.cx.bt_push(ExpnInfo { call_site: attr.span, @@ -267,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }); - match *extension { + match *ext { MultiModifier(ref mac) => { let item = mac.expand(self.cx, attr.span, &attr.node.value, item); kind.expect_from_annotatables(item) @@ -284,8 +308,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } /// Expand a macro invocation. Returns the result of expansion. - fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion { - let Invocation { mark, expansion_kind: kind, .. } = invoc; + fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { + let (mark, kind) = (invoc.mark(), invoc.expansion_kind); let (attrs, mac, ident, span) = match invoc.kind { InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span), _ => unreachable!(), @@ -306,19 +330,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let extname = path.segments[0].identifier.name; - let extension = if let Some(extension) = self.cx.syntax_env.find(extname) { - extension - } else { - let mut err = - self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname)); - self.cx.suggest_macro_name(&extname.as_str(), &mut err); - err.emit(); - return kind.dummy(span); - }; - let ident = ident.unwrap_or(keywords::Invalid.ident()); let marked_tts = mark_tts(&tts, mark); - let opt_expanded = match *extension { + let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { let msg = @@ -442,10 +456,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.invocations.push(Invocation { kind: kind, expansion_kind: expansion_kind, - mark: mark, - module: self.cx.syntax_env.current_module, - backtrace: self.cx.backtrace, - depth: self.cx.recursion_count, + expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() }, }); placeholder(expansion_kind, mark.as_u32()) } @@ -462,50 +473,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } // If `item` is an attr invocation, remove and return the macro attribute. - fn classify_item(&self, mut item: T) -> (T, Option) { + fn classify_item(&mut self, mut item: T) -> (T, Option) { let mut attr = None; item = item.map_attrs(|mut attrs| { - for i in 0..attrs.len() { - if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) { - match *extension { - MultiModifier(..) | MultiDecorator(..) => { - attr = Some(attrs.remove(i)); - break; - } - _ => {} - } - } - } + attr = self.cx.resolver.find_attr_invoc(&mut attrs); attrs }); (item, attr) } - // does this attribute list contain "macro_use" ? - fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { - for attr in attrs { - let mut is_use = attr.check_name("macro_use"); - if attr.check_name("macro_escape") { - let msg = "macro_escape is a deprecated synonym for macro_use"; - let mut err = self.cx.struct_span_warn(attr.span, msg); - is_use = true; - if let ast::AttrStyle::Inner = attr.node.style { - err.help("consider an outer attribute, #[macro_use] mod ...").emit(); - } else { - err.emit(); - } - }; - - if is_use { - if !attr.is_word() { - self.cx.span_err(attr.span, "arguments to macro_use are not allowed here"); - } - return true; - } - } - false - } - fn configure(&mut self, node: T) -> Option { self.cfg.configure(node) } @@ -574,11 +550,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_block(&mut self, block: P) -> P { - let paths = self.cx.syntax_env.paths(); - let module = self.cx.syntax_env.add_module(false, true, paths); - let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module); + let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true); let result = noop_fold_block(block, self); - self.cx.syntax_env.current_module = orig_module; + self.cx.current_expansion.in_block = orig_in_block; result } @@ -613,8 +587,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }) } ast::ItemKind::Mod(ast::Mod { inner, .. }) => { - let mut paths = (*self.cx.syntax_env.paths()).clone(); - paths.mod_path.push(item.ident); + let mut module = (*self.cx.current_expansion.module).clone(); + module.mod_path.push(item.ident); // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). @@ -622,28 +596,26 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; if inline_module { - paths.directory.push(&*{ + module.directory.push(&*{ ::attr::first_attr_value_str_by_name(&item.attrs, "path") .unwrap_or(item.ident.name.as_str()) }); } else { - paths.directory = + module.directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)); - paths.directory.pop(); + module.directory.pop(); } - let macro_use = self.contains_macro_use(&item.attrs); - let in_block = self.cx.syntax_env.in_block(); - let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths)); - let module = mem::replace(&mut self.cx.syntax_env.current_module, module); + let orig_module = + mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); let result = noop_fold_item(item, self); - self.cx.syntax_env.current_module = module; - result - }, + self.cx.current_expansion.module = orig_module; + return result; + } ast::ItemKind::ExternCrate(..) => { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. - let is_crate_root = self.cx.syntax_env.is_crate_root(); + let is_crate_root = self.cx.current_expansion.module.mod_path.len() == 1; for def in self.cx.resolver.load_crate(&*item, is_crate_root) { match def { LoadedMacro::Def(def) => self.cx.insert_macro(def), diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 27e8eab62e114..34126fac4ac78 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -29,7 +29,7 @@ pub struct SyntaxContextData { pub prev_ctxt: SyntaxContext, } -/// A mark represents a unique id associated with a macro expansion. +/// A mark is a unique id associated with a macro expansion. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct Mark(u32); @@ -41,6 +41,11 @@ impl Mark { }) } + /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST. + pub fn root() -> Self { + Mark(0) + } + pub fn as_u32(&self) -> u32 { self.0 } @@ -56,8 +61,8 @@ impl HygieneData { fn new() -> Self { HygieneData { syntax_contexts: vec![SyntaxContextData { - outer_mark: Mark(0), // the null mark - prev_ctxt: SyntaxContext(0), // the empty context + outer_mark: Mark::root(), + prev_ctxt: SyntaxContext::empty(), }], markings: HashMap::new(), next_mark: Mark(1), diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 105b226111738..e75e41d0c2d4b 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -74,8 +74,8 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "module_path!"); - let paths = cx.syntax_env.paths(); - let string = paths.mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); + let mod_path = &cx.current_expansion.module.mod_path; + let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); base::MacEager::expr(cx.expr_str( sp, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index ed80ec9cbc49e..51ef45b97be6f 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, imported_from, rhs); let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr)); - p.directory = cx.syntax_env.paths().directory.clone(); - p.restrictions = match cx.syntax_env.in_block() { + p.directory = cx.current_expansion.module.directory.clone(); + p.restrictions = match cx.current_expansion.in_block { true => Restrictions::NO_NONINLINE_MOD, false => Restrictions::empty(), }; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index fcbce36389082..6162beb80eccc 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,8 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; -use syntax::ext::base::MultiModifier; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -89,7 +88,7 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { } } -fn expand_derive(cx: &mut ExtCtxt, +pub fn expand_derive(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, annotatable: Annotatable) @@ -243,10 +242,6 @@ fn expand_derive(cx: &mut ExtCtxt, macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { - pub fn register_all(env: &mut SyntaxEnv) { - env.insert(intern("derive"), MultiModifier(Box::new(expand_derive))); - } - pub fn is_builtin_trait(name: &str) -> bool { match name { $( $name )|+ => true, diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 2065d92fd6ed7..3a6212e5445ce 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -34,11 +34,6 @@ extern crate syntax_pos; extern crate rustc_macro; extern crate rustc_errors as errors; -use syntax::ext::base::{MacroExpanderFn, NormalTT}; -use syntax::ext::base::{SyntaxEnv, SyntaxExtension}; -use syntax::parse::token::intern; - - mod asm; mod cfg; mod concat; @@ -53,28 +48,67 @@ pub mod rustc_macro_registrar; // for custom_derive pub mod deriving; -pub fn register_builtins(env: &mut SyntaxEnv) { - // utility function to simplify creating NormalTT syntax extensions - fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { - NormalTT(Box::new(f), None, false) +use std::rc::Rc; +use syntax::ast; +use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier}; +use syntax::ext::hygiene::Mark; +use syntax::parse::token::intern; + +pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) { + let mut register = |name, ext| { + resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext)); + }; + + register("macro_rules", MacroRulesTT); + + macro_rules! register { + ($( $name:ident: $f:expr, )*) => { $( + register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false)); + )* } } - env.insert(intern("asm"), builtin_normal_expander(asm::expand_asm)); - env.insert(intern("cfg"), builtin_normal_expander(cfg::expand_cfg)); - env.insert(intern("concat"), - builtin_normal_expander(concat::expand_syntax_ext)); - env.insert(intern("concat_idents"), - builtin_normal_expander(concat_idents::expand_syntax_ext)); - env.insert(intern("env"), builtin_normal_expander(env::expand_env)); - env.insert(intern("option_env"), - builtin_normal_expander(env::expand_option_env)); - env.insert(intern("format_args"), - // format_args uses `unstable` things internally. - NormalTT(Box::new(format::expand_format_args), None, true)); - env.insert(intern("log_syntax"), - builtin_normal_expander(log_syntax::expand_syntax_ext)); - env.insert(intern("trace_macros"), - builtin_normal_expander(trace_macros::expand_trace_macros)); - - deriving::register_all(env); + if enable_quotes { + use syntax::ext::quote::*; + register! { + quote_tokens: expand_quote_tokens, + quote_expr: expand_quote_expr, + quote_ty: expand_quote_ty, + quote_item: expand_quote_item, + quote_pat: expand_quote_pat, + quote_arm: expand_quote_arm, + quote_stmt: expand_quote_stmt, + quote_matcher: expand_quote_matcher, + quote_attr: expand_quote_attr, + quote_arg: expand_quote_arg, + quote_block: expand_quote_block, + quote_meta_item: expand_quote_meta_item, + quote_path: expand_quote_path, + } + } + + use syntax::ext::source_util::*; + register! { + line: expand_line, + column: expand_column, + file: expand_file, + stringify: expand_stringify, + include: expand_include, + include_str: expand_include_str, + include_bytes: expand_include_bytes, + module_path: expand_mod, + + asm: asm::expand_asm, + cfg: cfg::expand_cfg, + concat: concat::expand_syntax_ext, + concat_idents: concat_idents::expand_syntax_ext, + env: env::expand_env, + option_env: env::expand_option_env, + log_syntax: log_syntax::expand_syntax_ext, + trace_macros: trace_macros::expand_trace_macros, + } + + // format_args uses `unstable` things internally. + register("format_args", NormalTT(Box::new(format::expand_format_args), None, true)); + + register("derive", MultiModifier(Box::new(deriving::expand_derive))); } From c86c8d41a26b2037e80c9fd028a59313a78b3a66 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 00:10:27 +0000 Subject: [PATCH 702/768] Perform node id assignment and `macros_at_scope` construction during the `InvocationCollector` and `PlaceholderExpander` folds. --- src/librustc_driver/driver.rs | 2 - src/librustc_resolve/assign_ids.rs | 92 ------------------------------ src/librustc_resolve/lib.rs | 1 - src/librustc_resolve/macros.rs | 4 ++ src/libsyntax/ext/base.rs | 3 + src/libsyntax/ext/expand.rs | 24 ++++++-- src/libsyntax/ext/placeholders.rs | 61 ++++++++++++++++++-- 7 files changed, 83 insertions(+), 104 deletions(-) delete mode 100644 src/librustc_resolve/assign_ids.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bf50c96034dd0..007222b2edf6d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -707,8 +707,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, &sess.features.borrow()) }); - let krate = time(sess.time_passes(), "assigning node ids", || resolver.assign_node_ids(krate)); - if sess.opts.debugging_opts.input_stats { println!("Post-expansion node count: {}", count_nodes(&krate)); } diff --git a/src/librustc_resolve/assign_ids.rs b/src/librustc_resolve/assign_ids.rs deleted file mode 100644 index a9e3c6ffe9ed8..0000000000000 --- a/src/librustc_resolve/assign_ids.rs +++ /dev/null @@ -1,92 +0,0 @@ -// 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. - -use Resolver; -use rustc::session::Session; -use rustc::util::nodemap::FnvHashMap; -use syntax::ast; -use syntax::ext::hygiene::Mark; -use syntax::fold::{self, Folder}; -use syntax::ptr::P; -use syntax::util::move_map::MoveMap; -use syntax::util::small_vector::SmallVector; - -use std::mem; - -impl<'a> Resolver<'a> { - pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate { - NodeIdAssigner { - sess: self.session, - macros_at_scope: &mut self.macros_at_scope, - }.fold_crate(krate) - } -} - -struct NodeIdAssigner<'a> { - sess: &'a Session, - macros_at_scope: &'a mut FnvHashMap>, -} - -impl<'a> Folder for NodeIdAssigner<'a> { - fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId { - assert_eq!(old_id, ast::DUMMY_NODE_ID); - self.sess.next_node_id() - } - - fn fold_block(&mut self, block: P) -> P { - block.map(|mut block| { - block.id = self.new_id(block.id); - - let stmt = block.stmts.pop(); - let mut macros = Vec::new(); - block.stmts = block.stmts.move_flat_map(|stmt| { - if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::Mac(..) = item.node { - macros.push(item.ident.ctxt.data().outer_mark); - return None; - } - } - - let stmt = self.fold_stmt(stmt).pop().unwrap(); - if !macros.is_empty() { - self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new())); - } - Some(stmt) - }); - - stmt.and_then(|mut stmt| { - // Avoid wasting a node id on a trailing expression statement, - // which shares a HIR node with the expression itself. - if let ast::StmtKind::Expr(expr) = stmt.node { - let expr = self.fold_expr(expr); - stmt.id = expr.id; - stmt.node = ast::StmtKind::Expr(expr); - Some(stmt) - } else { - self.fold_stmt(stmt).pop() - } - }).map(|stmt| { - if !macros.is_empty() { - self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new())); - } - block.stmts.push(stmt); - }); - - block - }) - } - - fn fold_item(&mut self, item: P) -> SmallVector> { - match item.node { - ast::ItemKind::Mac(..) => SmallVector::zero(), - _ => fold::noop_fold_item(item, self), - } - } -} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6bf45ab8f6fa0..ad0507c9fb7e1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -84,7 +84,6 @@ mod macros; mod check_unused; mod build_reduced_graph; mod resolve_imports; -mod assign_ids; enum SuggestionType { Macro(String), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 36f501a54d261..67ee4c307d3c3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -41,6 +41,10 @@ impl<'a> base::Resolver for Resolver<'a> { self.macro_loader.load_crate(extern_crate, allows_macros) } + fn next_node_id(&mut self) -> ast::NodeId { + self.session.next_node_id() + } + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { expansion.visit_with(&mut ExpansionVisitor { current_module: self.expansion_data[mark.as_u32() as usize].module.clone(), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d46e2a9872e8d..1e8f8ef9ddd6c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -464,6 +464,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub trait Resolver { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + fn next_node_id(&mut self) -> ast::NodeId; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc); @@ -479,10 +480,12 @@ pub enum LoadedMacro { } pub struct DummyResolver; + impl Resolver for DummyResolver { fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec { Vec::new() } + fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index beb1687dfdc72..eef38ea28e0f4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -195,6 +195,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate.module.items = self.expand(items).make_items().into(); krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); + for def in &mut krate.exported_macros { + def.id = self.cx.resolver.next_node_id() + } + if self.cx.parse_sess.span_diagnostic.err_count() > err_count { self.cx.parse_sess.span_diagnostic.abort_if_errors(); } @@ -234,7 +238,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = orig_expansion_data; - let mut placeholder_expander = PlaceholderExpander::new(); + let mut placeholder_expander = PlaceholderExpander::new(self.cx); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let expansion = expansion.fold_with(&mut placeholder_expander); @@ -530,9 +534,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { None => return SmallVector::zero(), }; - let (mac, style, attrs) = match stmt.node { - StmtKind::Mac(mac) => mac.unwrap(), - _ => return noop_fold_stmt(stmt, self), + let (mac, style, attrs) = if let StmtKind::Mac(mac) = stmt.node { + mac.unwrap() + } else { + // The placeholder expander gives ids to statements, so we avoid folding the id here. + let ast::Stmt { id, node, span } = stmt; + return noop_fold_stmt_kind(node, self).into_iter().map(|node| { + ast::Stmt { id: id, node: node, span: span } + }).collect() }; let mut placeholder = @@ -624,7 +633,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } } - SmallVector::one(item) + noop_fold_item(item, self) }, _ => noop_fold_item(item, self), } @@ -687,6 +696,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { noop_fold_item_kind(self.cfg.configure_item_kind(item), self) } + + fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { + assert_eq!(id, ast::DUMMY_NODE_ID); + self.cx.resolver.next_node_id() + } } pub struct ExpansionConfig<'feat> { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index abadcf867b146..7635705daa052 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -10,13 +10,16 @@ use ast; use codemap::{DUMMY_SP, dummy_spanned}; +use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; use fold::*; use parse::token::keywords; use ptr::P; +use util::move_map::MoveMap; use util::small_vector::SmallVector; use std::collections::HashMap; +use std::mem; pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { fn mac_placeholder() -> ast::Mac { @@ -69,13 +72,15 @@ pub fn macro_scope_placeholder() -> Expansion { placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) } -pub struct PlaceholderExpander { +pub struct PlaceholderExpander<'a, 'b: 'a> { expansions: HashMap, + cx: &'a mut ExtCtxt<'b>, } -impl PlaceholderExpander { - pub fn new() -> Self { +impl<'a, 'b> PlaceholderExpander<'a, 'b> { + pub fn new(cx: &'a mut ExtCtxt<'b>) -> Self { PlaceholderExpander { + cx: cx, expansions: HashMap::new(), } } @@ -89,7 +94,7 @@ impl PlaceholderExpander { } } -impl Folder for PlaceholderExpander { +impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_item(&mut self, item: P) -> SmallVector> { match item.node { // Scope placeholder @@ -155,6 +160,54 @@ impl Folder for PlaceholderExpander { _ => noop_fold_ty(ty, self), } } + + fn fold_block(&mut self, block: P) -> P { + noop_fold_block(block, self).map(|mut block| { + let mut macros = Vec::new(); + let mut remaining_stmts = block.stmts.len(); + + block.stmts = block.stmts.move_flat_map(|mut stmt| { + remaining_stmts -= 1; + + // Scope placeholder + if let ast::StmtKind::Item(ref item) = stmt.node { + if let ast::ItemKind::Mac(..) = item.node { + macros.push(item.ident.ctxt.data().outer_mark); + return None; + } + } + + match stmt.node { + // Avoid wasting a node id on a trailing expression statement, + // which shares a HIR node with the expression itself. + ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, + + _ => { + assert_eq!(stmt.id, ast::DUMMY_NODE_ID); + stmt.id = self.cx.resolver.next_node_id(); + } + } + + if !macros.is_empty() { + let macros = mem::replace(&mut macros, Vec::new()); + self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); + } + + Some(stmt) + }); + + block + }) + } + + fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod { + let mut module = noop_fold_mod(module, self); + module.items = module.items.move_flat_map(|item| match item.node { + ast::ItemKind::Mac(_) => None, // remove scope placeholders from modules + _ => Some(item), + }); + module + } } pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion { From f3c2dca3539e6edc745f9c91898cb97d281865c1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 01:45:23 +0000 Subject: [PATCH 703/768] Remove scope placeholders from the crate root. --- src/libsyntax/ext/expand.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index eef38ea28e0f4..0eb9d4bc0c2f7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -191,8 +191,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { let err_count = self.cx.parse_sess.span_diagnostic.err_count(); - let items = Expansion::Items(SmallVector::many(krate.module.items)); - krate.module.items = self.expand(items).make_items().into(); + let mut krate_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) + .make_items().pop().unwrap().unwrap(); + krate_item.node = ast::ItemKind::Mod(krate.module); + let krate_item = Expansion::Items(SmallVector::one(P(krate_item))); + + krate.module = match self.expand(krate_item).make_items().pop().unwrap().unwrap().node { + ast::ItemKind::Mod(module) => module, + _ => unreachable!(), + }; krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); for def in &mut krate.exported_macros { @@ -596,6 +603,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }) } ast::ItemKind::Mod(ast::Mod { inner, .. }) => { + if item.ident == keywords::Invalid.ident() { + return noop_fold_item(item, self); + } + let mut module = (*self.cx.current_expansion.module).clone(); module.mod_path.push(item.ident); From 78c00398780db6f59ebf43e765fa9368dad436d2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 07:52:09 +0000 Subject: [PATCH 704/768] Expand generated test harnesses and macro registries. --- src/librustc_driver/driver.rs | 2 ++ src/libsyntax/test.rs | 30 +++++++++++----------- src/libsyntax_ext/rustc_macro_registrar.rs | 23 ++++++++--------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 007222b2edf6d..36e9fccdf5fd8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -690,6 +690,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, + &mut resolver, sess.opts.test, krate, sess.diagnostic()) @@ -700,6 +701,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro); let num_crate_types = crate_types.len(); syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess, + &mut resolver, krate, is_rustc_macro_crate, num_crate_types, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index dde8a8d271f62..46c9a4606ccef 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -28,7 +28,7 @@ use errors; use errors::snippet::{SnippetData}; use config; use entry::{self, EntryPointType}; -use ext::base::{ExtCtxt, DummyResolver}; +use ext::base::{ExtCtxt, Resolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use fold::Folder; @@ -70,6 +70,7 @@ struct TestCtxt<'a> { // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness pub fn modify_for_testing(sess: &ParseSess, + resolver: &mut Resolver, should_test: bool, krate: ast::Crate, span_diagnostic: &errors::Handler) -> ast::Crate { @@ -82,7 +83,7 @@ pub fn modify_for_testing(sess: &ParseSess, "reexport_test_harness_main"); if should_test { - generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic) + generate_test_harness(sess, resolver, reexport_test_harness_main, krate, span_diagnostic) } else { krate } @@ -248,27 +249,28 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }).chain(tested_submods.into_iter().map(|(r, sym)| { let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]); cx.ext_cx.item_use_simple_(DUMMY_SP, ast::Visibility::Public, r, path) - })); + })).collect(); let reexport_mod = ast::Mod { inner: DUMMY_SP, - items: items.collect(), + items: items, }; let sym = token::gensym_ident("__test_reexports"); - let it = P(ast::Item { + let it = cx.ext_cx.expander().fold_item(P(ast::Item { ident: sym.clone(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, node: ast::ItemKind::Mod(reexport_mod), vis: ast::Visibility::Public, span: DUMMY_SP, - }); + })).pop().unwrap(); (it, sym) } fn generate_test_harness(sess: &ParseSess, + resolver: &mut Resolver, reexport_test_harness_main: Option, krate: ast::Crate, sd: &errors::Handler) -> ast::Crate { @@ -276,13 +278,10 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); - let mut resolver = DummyResolver; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, vec![], - ExpansionConfig::default("test".to_string()), - &mut resolver), + ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, @@ -511,16 +510,17 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { items: vec![import, mainfn, tests], }; let item_ = ast::ItemKind::Mod(testmod); - let mod_ident = token::gensym_ident("__test"); - let item = P(ast::Item { + + let mut expander = cx.ext_cx.expander(); + let item = expander.fold_item(P(ast::Item { id: ast::DUMMY_NODE_ID, ident: mod_ident, attrs: vec![], node: item_, vis: ast::Visibility::Public, span: DUMMY_SP, - }); + })).pop().unwrap(); let reexport = cx.reexport_test_harness_main.as_ref().map(|s| { // building `use = __test::main` let reexport_ident = token::str_to_ident(&s); @@ -529,14 +529,14 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { nospan(ast::ViewPathSimple(reexport_ident, path_node(vec![mod_ident, token::str_to_ident("main")]))); - P(ast::Item { + expander.fold_item(P(ast::Item { id: ast::DUMMY_NODE_ID, ident: keywords::Invalid.ident(), attrs: vec![], node: ast::ItemKind::Use(P(use_path)), vis: ast::Visibility::Inherited, span: DUMMY_SP - }) + })).pop().unwrap() }); debug!("Synthetic test module:\n{}\n", pprust::item_to_string(&item)); diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs index 78fed9d33dd82..c07e79179398e 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -13,12 +13,13 @@ use std::mem; use errors; use syntax::ast::{self, Ident, NodeId}; use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; -use syntax::ext::base::{ExtCtxt, DummyResolver}; +use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::parse::ParseSess; use syntax::parse::token::{self, InternedString}; use syntax::feature_gate::Features; +use syntax::fold::Folder; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; use syntax::visit::{self, Visitor}; @@ -39,16 +40,14 @@ struct CollectCustomDerives<'a> { } pub fn modify(sess: &ParseSess, + resolver: &mut ::syntax::ext::base::Resolver, mut krate: ast::Crate, is_rustc_macro_crate: bool, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { - let mut loader = DummyResolver; - let mut cx = ExtCtxt::new(sess, - Vec::new(), - ExpansionConfig::default("rustc_macro".to_string()), - &mut loader); + let ecfg = ExpansionConfig::default("rustc_macro".to_string()); + let mut cx = ExtCtxt::new(sess, Vec::new(), ecfg, resolver); let mut collect = CollectCustomDerives { derives: Vec::new(), @@ -268,13 +267,11 @@ fn mk_registrar(cx: &mut ExtCtxt, i.vis = ast::Visibility::Public; i }); - let module = cx.item_mod(span, - span, - ast::Ident::with_empty_ctxt(token::gensym("registrar")), - Vec::new(), - vec![krate, func]); - module.map(|mut i| { + let ident = ast::Ident::with_empty_ctxt(token::gensym("registrar")); + let module = cx.item_mod(span, span, ident, Vec::new(), vec![krate, func]).map(|mut i| { i.vis = ast::Visibility::Public; i - }) + }); + + cx.expander().fold_item(module).pop().unwrap() } From b54e1e399741579612f13e2df98a25ea9447989d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 05:42:45 +0000 Subject: [PATCH 705/768] Differentiate between monotonic and non-monotonic expansion and only assign node ids during monotonic expansion. --- src/libsyntax/ext/base.rs | 8 +++++++- src/libsyntax/ext/expand.rs | 24 ++++++++++++++-------- src/libsyntax/ext/placeholders.rs | 10 ++++++--- src/libsyntax/test.rs | 4 ++-- src/libsyntax_ext/rustc_macro_registrar.rs | 2 +- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1e8f8ef9ddd6c..fb4816d3847ed 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -549,7 +549,13 @@ impl<'a> ExtCtxt<'a> { /// Returns a `Folder` for deeply expanding all macros in an AST node. pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { - expand::MacroExpander::new(self, false, false) + expand::MacroExpander::new(self, false) + } + + /// Returns a `Folder` that deeply expands all macros and assigns all node ids in an AST node. + /// Once node ids are assigned, the node may not be expanded, removed, or otherwise modified. + pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { + expand::MacroExpander::new(self, true) } pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0eb9d4bc0c2f7..62e299684b760 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -175,16 +175,16 @@ pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, pub single_step: bool, pub keep_macs: bool, + monotonic: bool, // c.f. `cx.monotonic_expander()` } impl<'a, 'b> MacroExpander<'a, 'b> { - pub fn new(cx: &'a mut ExtCtxt<'b>, - single_step: bool, - keep_macs: bool) -> MacroExpander<'a, 'b> { + pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { MacroExpander { cx: cx, - single_step: single_step, - keep_macs: keep_macs + monotonic: monotonic, + single_step: false, + keep_macs: false, } } @@ -245,7 +245,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = orig_expansion_data; - let mut placeholder_expander = PlaceholderExpander::new(self.cx); + let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let expansion = expansion.fold_with(&mut placeholder_expander); @@ -268,6 +268,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }, cx: self.cx, invocations: Vec::new(), + monotonic: self.monotonic, }; (expansion.fold_with(&mut collector), collector.invocations) }; @@ -450,6 +451,7 @@ struct InvocationCollector<'a, 'b: 'a> { cx: &'a mut ExtCtxt<'b>, cfg: StripUnconfigured<'a>, invocations: Vec, + monotonic: bool, } macro_rules! fully_configure { @@ -709,8 +711,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { - assert_eq!(id, ast::DUMMY_NODE_ID); - self.cx.resolver.next_node_id() + if self.monotonic { + assert_eq!(id, ast::DUMMY_NODE_ID); + self.cx.resolver.next_node_id() + } else { + id + } } } @@ -763,7 +769,7 @@ pub fn expand_crate(cx: &mut ExtCtxt, user_exts: Vec, c: Crate) -> Crate { cx.initialize(user_exts, &c); - cx.expander().expand_crate(c) + cx.monotonic_expander().expand_crate(c) } // Expands crate using supplied MacroExpander - allows for diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 7635705daa052..47f366a88768e 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -75,13 +75,15 @@ pub fn macro_scope_placeholder() -> Expansion { pub struct PlaceholderExpander<'a, 'b: 'a> { expansions: HashMap, cx: &'a mut ExtCtxt<'b>, + monotonic: bool, } impl<'a, 'b> PlaceholderExpander<'a, 'b> { - pub fn new(cx: &'a mut ExtCtxt<'b>) -> Self { + pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { PlaceholderExpander { cx: cx, expansions: HashMap::new(), + monotonic: monotonic, } } @@ -182,13 +184,15 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { // which shares a HIR node with the expression itself. ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, - _ => { + _ if self.monotonic => { assert_eq!(stmt.id, ast::DUMMY_NODE_ID); stmt.id = self.cx.resolver.next_node_id(); } + + _ => {} } - if !macros.is_empty() { + if self.monotonic && !macros.is_empty() { let macros = mem::replace(&mut macros, Vec::new()); self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 46c9a4606ccef..6327e8f71bcd5 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -257,7 +257,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }; let sym = token::gensym_ident("__test_reexports"); - let it = cx.ext_cx.expander().fold_item(P(ast::Item { + let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item { ident: sym.clone(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, @@ -512,7 +512,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { let item_ = ast::ItemKind::Mod(testmod); let mod_ident = token::gensym_ident("__test"); - let mut expander = cx.ext_cx.expander(); + let mut expander = cx.ext_cx.monotonic_expander(); let item = expander.fold_item(P(ast::Item { id: ast::DUMMY_NODE_ID, ident: mod_ident, diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs index c07e79179398e..ce3e53cdf97f4 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -273,5 +273,5 @@ fn mk_registrar(cx: &mut ExtCtxt, i }); - cx.expander().fold_item(module).pop().unwrap() + cx.monotonic_expander().fold_item(module).pop().unwrap() } From 265620225d2fa122c27bb6221bf5afe1797e9e6e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Sep 2016 07:59:42 -0700 Subject: [PATCH 706/768] rustc: Don't pass --whole-archive for compiler-builtins This flag is intended for rlibs included once, not rlibs that are repeatedly included. --- src/libcompiler_builtins/build.rs | 10 ++++--- src/librustc_trans/back/link.rs | 44 ++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index fb8e45c1fe133..09c400b52bc83 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -50,10 +50,12 @@ impl Sources { } fn extend(&mut self, sources: &[&'static str]) { - // NOTE Some intrinsics have both a generic implementation (e.g. `floatdidf.c`) and an arch - // optimized implementation (`x86_64/floatdidf.c`). In those cases, we keep the arch - // optimized implementation and discard the generic implementation. If we don't and keep - // both implementations, the linker will yell at us about duplicate symbols! + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! for &src in sources { let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); if src.contains("/") { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3433b866691cc..288249a7d9934 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -943,8 +943,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) + add_static_crate(cmd, sess, tmpdir, crate_type, cnum); } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) @@ -956,9 +955,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` // is used) if let Some(cnum) = compiler_builtins { - let src = sess.cstore.used_crate_source(cnum); - add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)); + add_static_crate(cmd, sess, tmpdir, crate_type, cnum); } // Converts a library file-stem into a cc -l argument @@ -1006,8 +1003,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, tmpdir: &Path, crate_type: config::CrateType, - cratepath: &Path, - is_a_no_builtins_crate: bool) { + cnum: ast::CrateNum) { + let src = sess.cstore.used_crate_source(cnum); + let cratepath = &src.rlib.unwrap().0; if !sess.lto() && crate_type != config::CrateTypeDylib { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return @@ -1031,7 +1029,13 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } let canonical = f.replace("-", "_"); let canonical_name = name.replace("-", "_"); - if sess.lto() && !is_a_no_builtins_crate && + + // If we're performing LTO and this is a rust-generated object + // file, then we don't need the object file as it's part of the + // LTO module. Note that `#![no_builtins]` is excluded from LTO, + // though, so we let that object file slide. + if sess.lto() && + !sess.cstore.is_no_builtins(cnum) && canonical.starts_with(&canonical_name) && canonical.ends_with(".o") { let num = &f[name.len()..f.len() - 2]; @@ -1043,13 +1047,23 @@ fn add_upstream_rust_crates(cmd: &mut Linker, any_objects = true; } - if any_objects { - archive.build(); - if crate_type == config::CrateTypeDylib { - cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } else { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } + if !any_objects { + return + } + archive.build(); + + // If we're creating a dylib, then we need to include the + // whole of each object in our archive into that artifact. This is + // because a `dylib` can be reused as an intermediate artifact. + // + // Note, though, that we don't want to include the whole of a + // compiler-builtins crate (e.g. compiler-rt) because it'll get + // repeatedly linked anyway. + if crate_type == config::CrateTypeDylib && + !sess.cstore.is_compiler_builtins(cnum) { + cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } else { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); } }); } From 5a881e920ec39c80310ff832867f2ef51168a1de Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Sep 2016 18:09:49 -0400 Subject: [PATCH 707/768] Make sure that projection bounds in ty::TraitObject are sorted in a way that is stable across compilation sessions and crate boundaries. --- src/librustc/ty/context.rs | 2 +- src/librustc/ty/mod.rs | 4 ---- src/librustc/ty/sty.rs | 21 ++++++++++++--------- src/librustc/ty/trait_def.rs | 10 ++++++++-- src/librustc_metadata/decoder.rs | 4 +++- src/librustc_typeck/collect.rs | 5 ++++- 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 20601493d68f3..6d7a2d6cba1c7 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1303,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> { - obj.projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); + obj.projection_bounds.sort_by_key(|b| b.sort_key(self)); self.mk_ty(TyTrait(box obj)) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f634c8e37d7bd..14eb2fb7914c3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1018,10 +1018,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { pub fn item_name(&self) -> Name { self.0.projection_ty.item_name // safe to skip the binder to access a name } - - pub fn sort_key(&self) -> (DefId, Name) { - self.0.projection_ty.sort_key() - } } pub trait ToPolyTraitRef<'tcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a755dd056cd84..5fdc7abc0af5b 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -23,7 +23,7 @@ use std::mem; use std::ops; use syntax::abi; use syntax::ast::{self, Name}; -use syntax::parse::token::keywords; +use syntax::parse::token::{keywords, InternedString}; use serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -440,12 +440,6 @@ pub struct ProjectionTy<'tcx> { pub item_name: Name, } -impl<'tcx> ProjectionTy<'tcx> { - pub fn sort_key(&self) -> (DefId, Name) { - (self.trait_ref.def_id, self.item_name) - } -} - #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct BareFnTy<'tcx> { pub unsafety: hir::Unsafety, @@ -738,8 +732,17 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { self.0.item_name // safe to skip the binder to access a name } - pub fn sort_key(&self) -> (DefId, Name) { - (self.0.trait_ref.def_id, self.0.item_name) + pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) { + // We want something here that is stable across crate boundaries. + // The DefId isn't but the `deterministic_hash` of the corresponding + // DefPath is. + let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id); + let def_path_hash = trait_def.def_path_hash; + + // An `ast::Name` is also not stable (it's just an index into an + // interning table), so map to the corresponding `InternedString`. + let item_name = self.0.item_name.as_str(); + (def_path_hash, item_name) } pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 61285e8f8b0a5..268b2fcaa4adb 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -70,7 +70,11 @@ pub struct TraitDef<'tcx> { pub specialization_graph: RefCell, /// Various flags - pub flags: Cell + pub flags: Cell, + + /// The ICH of this trait's DefPath, cached here so it doesn't have to be + /// recomputed all the time. + pub def_path_hash: u64, } impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { @@ -78,7 +82,8 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { paren_sugar: bool, generics: &'tcx ty::Generics<'tcx>, trait_ref: ty::TraitRef<'tcx>, - associated_type_names: Vec) + associated_type_names: Vec, + def_path_hash: u64) -> TraitDef<'tcx> { TraitDef { paren_sugar: paren_sugar, @@ -90,6 +95,7 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { blanket_impls: RefCell::new(vec![]), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), + def_path_hash: def_path_hash, } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d2840fbe4fe46..824e892072f57 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -385,12 +385,14 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); + let def_path = def_path(cdata, item_id); ty::TraitDef::new(unsafety, paren_sugar, generics, item_trait_ref(item_doc, tcx, cdata), - associated_type_names) + associated_type_names, + def_path.deterministic_hash(tcx)) } pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7d111cdc4156f..04aca8c0947ca 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1290,12 +1290,15 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }).collect(); + let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); + let trait_ref = ty::TraitRef::new(def_id, substs); let trait_def = ty::TraitDef::new(unsafety, paren_sugar, ty_generics, trait_ref, - associated_type_names); + associated_type_names, + def_path_hash); tcx.intern_trait_def(trait_def) } From 5c923f0159105bf9491a86cd5bd7eb20807387b6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Sep 2016 18:24:45 -0400 Subject: [PATCH 708/768] Remove redundant sorting of projection bounds in tyencode. --- src/librustc_metadata/tyencode.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 8030abf6330e7..dbefd3eacc24a 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -104,14 +104,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx enc_region(w, cx, obj.region_bound); - // Encode projection_bounds in a stable order - let mut projection_bounds: Vec<_> = obj.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - - for tp in projection_bounds.iter().map(|&(_, tp)| tp) { + for tp in &obj.projection_bounds { write!(w, "P"); enc_existential_projection(w, cx, &tp.0); } From 94d75013bcf6fc8e79cd7c0c76c37e68c458db6f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 08:40:14 -0400 Subject: [PATCH 709/768] Remove redundant sorting of projections in TypeIdHasher. --- src/librustc/ty/util.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6b3ebaa895fa3..c6020838b5320 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -458,15 +458,11 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { data.region_bound.visit_with(self); self.hash(data.builtin_bounds); - // Only projection bounds are left, sort and hash them. - let mut projection_bounds: Vec<_> = data.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - for (name, bound) in projection_bounds { + // Only projection bounds are left, hash them. + self.hash(data.projection_bounds.len()); + for bound in &data.projection_bounds { self.def_id(bound.0.trait_ref.def_id); - self.hash(name); + self.hash(bound.0.item_name); bound.visit_with(self); } From 75a0dd0fca4e3e3b5eade66fb3dddc2b9868dc52 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 08:45:34 -0400 Subject: [PATCH 710/768] Make TypeIdHasher use DefPath::deterministic_hash() for stability. --- src/librustc/ty/util.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c6020838b5320..a8287ecc046cf 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -411,15 +411,11 @@ impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> { } fn def_id(&mut self, did: DefId) { - // Hash the crate identification information. - let name = self.tcx.crate_name(did.krate); - let disambiguator = self.tcx.crate_disambiguator(did.krate); - self.hash((name, disambiguator)); - - // Hash the item path within that crate. - // FIXME(#35379) This should use a deterministic - // DefPath hashing mechanism, not the DefIndex. - self.hash(did.index); + // Hash the DefPath corresponding to the DefId, which is independent + // of compiler internal state. + let tcx = self.tcx; + let def_path = tcx.def_path(did); + def_path.deterministic_hash_to(tcx, &mut self.state); } } From 869d14447af84bfb506e19abf2ca97810845c675 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 15:02:17 -0400 Subject: [PATCH 711/768] TypeIdHasher: Let projections be hashed implicitly by the visitor. --- src/librustc/ty/util.rs | 11 ----------- src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs | 5 +++++ src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs | 5 +++++ src/test/run-pass/typeid-intrinsic.rs | 9 +++++++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index a8287ecc046cf..344f0e57d6423 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -453,17 +453,6 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { // Hash region and builtin bounds. data.region_bound.visit_with(self); self.hash(data.builtin_bounds); - - // Only projection bounds are left, hash them. - self.hash(data.projection_bounds.len()); - for bound in &data.projection_bounds { - self.def_id(bound.0.trait_ref.def_id); - self.hash(bound.0.item_name); - bound.visit_with(self); - } - - // Bypass super_visit_with, we've visited everything. - return false; } TyTuple(tys) => { self.hash(tys.len()); diff --git a/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs b/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs index 42c0da6286bdc..10e315f269f97 100644 --- a/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs +++ b/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs @@ -22,6 +22,8 @@ pub type F = Option; pub type G = usize; pub type H = &'static str; pub type I = Box; +pub type I32Iterator = Iterator; +pub type U32Iterator = Iterator; pub fn id_A() -> TypeId { TypeId::of::() } pub fn id_B() -> TypeId { TypeId::of::() } @@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::() } pub fn id_I() -> TypeId { TypeId::of::() } pub fn foo() -> TypeId { TypeId::of::() } + +pub fn id_i32_iterator() -> TypeId { TypeId::of::() } +pub fn id_u32_iterator() -> TypeId { TypeId::of::() } diff --git a/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs b/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs index 42c0da6286bdc..10e315f269f97 100644 --- a/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs +++ b/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs @@ -22,6 +22,8 @@ pub type F = Option; pub type G = usize; pub type H = &'static str; pub type I = Box; +pub type I32Iterator = Iterator; +pub type U32Iterator = Iterator; pub fn id_A() -> TypeId { TypeId::of::() } pub fn id_B() -> TypeId { TypeId::of::() } @@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::() } pub fn id_I() -> TypeId { TypeId::of::() } pub fn foo() -> TypeId { TypeId::of::() } + +pub fn id_i32_iterator() -> TypeId { TypeId::of::() } +pub fn id_u32_iterator() -> TypeId { TypeId::of::() } diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index e99a5f69af40f..36650368d57be 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -78,4 +78,13 @@ pub fn main() { b.hash(&mut s2); assert_eq!(s1.finish(), s2.finish()); + + // Check projections + + assert_eq!(TypeId::of::(), other1::id_i32_iterator()); + assert_eq!(TypeId::of::(), other1::id_u32_iterator()); + assert_eq!(other1::id_i32_iterator(), other2::id_i32_iterator()); + assert_eq!(other1::id_u32_iterator(), other2::id_u32_iterator()); + assert!(other1::id_i32_iterator() != other1::id_u32_iterator()); + assert!(TypeId::of::() != TypeId::of::()); } From 848cfe20a01b3d43d4c9838bd7d9b0da32dace42 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Sep 2016 12:27:26 -0700 Subject: [PATCH 712/768] Link test to compiler builtins and make unstable This commit fixes a test which now needs to explicitly link to the `compiler_builtins` crate as well as makes the `compiler_builtins` crate unstable. --- src/libcompiler_builtins/lib.rs | 5 ++++- src/libstd/lib.rs | 1 + src/test/run-make/no-duplicate-libs/bar.rs | 3 ++- src/test/run-make/no-duplicate-libs/foo.rs | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index ad1d1edbeba29..fbcf5204d2537 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -11,6 +11,9 @@ #![cfg_attr(not(stage0), feature(compiler_builtins))] #![no_std] #![cfg_attr(not(stage0), compiler_builtins)] - +#![unstable(feature = "compiler_builtins_lib", + reason = "internal implementation detail of rustc right now", + issue = "0")] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] +#![feature(staged_api)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d227fb1404f47..115a24fc83c22 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -224,6 +224,7 @@ #![feature(char_internals)] #![feature(collections)] #![feature(collections_bound)] +#![feature(compiler_builtins_lib)] #![feature(const_fn)] #![feature(core_float)] #![feature(core_intrinsics)] diff --git a/src/test/run-make/no-duplicate-libs/bar.rs b/src/test/run-make/no-duplicate-libs/bar.rs index 8a15afb328a92..b82fdeb8f3696 100644 --- a/src/test/run-make/no-duplicate-libs/bar.rs +++ b/src/test/run-make/no-duplicate-libs/bar.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, libc)] +#![feature(lang_items, libc, compiler_builtins_lib)] #![crate_type = "dylib"] #![no_std] extern crate libc; +extern crate compiler_builtins; #[no_mangle] pub extern fn bar() {} diff --git a/src/test/run-make/no-duplicate-libs/foo.rs b/src/test/run-make/no-duplicate-libs/foo.rs index ab8d2eca9363f..cbdee356838de 100644 --- a/src/test/run-make/no-duplicate-libs/foo.rs +++ b/src/test/run-make/no-duplicate-libs/foo.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, libc)] +#![feature(lang_items, libc, compiler_builtins_lib)] #![no_std] #![crate_type = "dylib"] extern crate libc; +extern crate compiler_builtins; #[no_mangle] pub extern fn foo() {} From 377c3e1123dd63689ccfddb5d37699f31846caf5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 15:46:21 -0400 Subject: [PATCH 713/768] Fix rebasing fallout. --- src/librustc_metadata/decoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 824e892072f57..624bffb7e0369 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -385,7 +385,7 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); - let def_path = def_path(cdata, item_id); + let def_path = def_path(cdata, item_id).unwrap(); ty::TraitDef::new(unsafety, paren_sugar, From 7ec9b81326121ae07feb0a19f76b3f16b98d0c43 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 16:01:39 -0400 Subject: [PATCH 714/768] TypeIdHasher: Remove more redundant explicit visit calls. --- src/librustc/ty/util.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 344f0e57d6423..d34fdaa7d71cd 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -441,17 +441,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { self.hash(f.sig.variadic()); } TyTrait(ref data) => { - // Trait objects have a list of projection bounds - // that are not guaranteed to be sorted in an order - // that gets preserved across crates, so we need - // to sort them again by the name, in string form. - - // Hash the whole principal trait ref. self.def_id(data.principal.def_id()); - data.principal.visit_with(self); - - // Hash region and builtin bounds. - data.region_bound.visit_with(self); self.hash(data.builtin_bounds); } TyTuple(tys) => { From b49a26ec6fe2faf06360139b4c6ed59684b083b4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Sep 2016 16:04:27 -0400 Subject: [PATCH 715/768] invoke drop glue with a ptr to (data, meta) This is done by creating a little space on the stack. Hokey, but it's the simplest fix I can see. --- src/librustc_trans/glue.rs | 9 ++++++++- src/librustc_trans/intrinsic.rs | 1 + src/librustc_trans/mir/block.rs | 24 +++++++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6b48c6ae26dac..3073b1dbfaeeb 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -296,6 +296,7 @@ fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, sized_args = [v0]; &sized_args } else { + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments unsized_args = [ Load(bcx, get_dataptr(bcx, v0)), Load(bcx, get_meta(bcx, v0)) @@ -440,7 +441,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, } } -fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>) +fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + v0: ValueRef, + g: DropGlueKind<'tcx>) -> Block<'blk, 'tcx> { let t = g.ty(); @@ -463,6 +466,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK let llval = get_dataptr(bcx, v0); let llbox = Load(bcx, llval); let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None); + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments let info = get_meta(bcx, v0); let info = Load(bcx, info); let (llsize, llalign) = @@ -488,6 +492,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is // okay with always calling the Drop impl, if any. + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments assert!(!skip_dtor); let data_ptr = get_dataptr(bcx, v0); let vtable_ptr = Load(bcx, get_meta(bcx, v0)); @@ -543,6 +548,7 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let value = if type_is_sized(cx.tcx(), t) { adt::MaybeSizedValue::sized(av) } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let data = Load(cx, get_dataptr(cx, av)); let info = Load(cx, get_meta(cx, av)); adt::MaybeSizedValue::unsized_(data, info) @@ -586,6 +592,7 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let val = if type_is_sized(cx.tcx(), field_ty) { llfld_a } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); Store(cx, llfld_a, get_dataptr(cx, scratch)); Store(cx, value.meta, get_meta(cx, scratch)); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 2049696ee4f71..fbade107ecfda 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -186,6 +186,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ptr = if is_sized { llargs[0] } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let scratch = alloc_ty(bcx, tp_ty, "drop"); call_lifetime_start(bcx, scratch); Store(bcx, llargs[0], get_dataptr(bcx, scratch)); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index fbd04d7b38029..baeafbe3e346f 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -242,10 +242,28 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let lvalue = self.trans_lvalue(&bcx, location); let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); let drop_ty = glue::get_drop_glue_type(bcx.tcx(), ty); - let llvalue = if drop_ty != ty { - bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + let is_sized = common::type_is_sized(bcx.tcx(), ty); + let llvalue = if is_sized { + if drop_ty != ty { + bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + } else { + lvalue.llval + } } else { - lvalue.llval + // FIXME(#36457) Currently drop glue takes sized + // values as a `*(data, meta)`, but elsewhere in + // MIR we pass `(data, meta)` as two separate + // arguments. It would be better to fix drop glue, + // but I am shooting for a quick fix to #35546 + // here that can be cleanly backported to beta, so + // I want to avoid touching all of trans. + bcx.with_block(|bcx| { + let scratch = base::alloc_ty(bcx, ty, "drop"); + base::call_lifetime_start(bcx, scratch); + build::Store(bcx, lvalue.llval, base::get_dataptr(bcx, scratch)); + build::Store(bcx, lvalue.llextra, base::get_meta(bcx, scratch)); + scratch + }) }; if let Some(unwind) = unwind { bcx.invoke(drop_fn, From 4b6c4c08df7f4685daf0fa2cfe127b06216176d6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 716/768] Remove some ancient code providing special support for newtypes --- src/librustc/middle/mem_categorization.rs | 4 --- src/librustc_metadata/encoder.rs | 28 --------------------- src/librustc_resolve/build_reduced_graph.rs | 4 +-- src/librustc_trans/adt.rs | 2 +- src/librustdoc/clean/inline.rs | 11 ++++---- src/librustdoc/doctree.rs | 21 ++++++---------- src/librustdoc/html/render.rs | 2 +- 7 files changed, 16 insertions(+), 56 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 39d5487e8beb1..5594ac413e238 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -223,10 +223,6 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { Ok(deref_ptr(UnsafePtr(mt.mutbl))) } - ty::TyAdt(..) => { // newtype - Ok(deref_interior(InteriorField(PositionalField(0)))) - } - ty::TyArray(..) | ty::TySlice(_) => { // no deref of indexed content without supplying InteriorOffsetKind if let Some(context) = context { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 603b7a483b90c..e228bf7430261 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -252,27 +252,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -/// Iterates through "auxiliary node IDs", which are node IDs that describe -/// top-level items that are sub-items of the given item. Specifically: -/// -/// * For newtype structs, iterates through the node ID of the constructor. -fn each_auxiliary_node_id(item: &hir::Item, callback: F) -> bool where - F: FnOnce(NodeId) -> bool, -{ - let mut continue_ = true; - match item.node { - hir::ItemStruct(ref struct_def, _) => { - // If this is a newtype struct, return the constructor. - if struct_def.is_tuple() { - continue_ = callback(struct_def.id()); - } - } - _ => {} - } - - continue_ -} - fn encode_reexports(ecx: &EncodeContext, rbml_w: &mut Encoder, id: NodeId) { @@ -313,13 +292,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { for item_id in &md.item_ids { self.rbml_w.wr_tagged_u64(tag_mod_child, def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); - - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { - self.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); } self.encode_visibility(vis); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index ad750ccc01299..83f03e7cfc5ac 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -261,8 +261,8 @@ impl<'b> Resolver<'b> { let def = Def::Struct(self.definitions.local_def_id(item.id)); self.define(parent, name, TypeNS, (def, sp, vis)); - // If this is a newtype or unit-like struct, define a name - // in the value namespace as well + // If this is a tuple or unit struct, define a name + // in the value namespace as well. if !struct_def.is_struct() { let def = Def::Struct(self.definitions.local_def_id(struct_def.id())); self.define(parent, name, ValueNS, (def, sp, vis)); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index e8498363e45a3..67e5ec2616d29 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -231,7 +231,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } if cases.len() == 1 && hint == attr::ReprAny { - // Equivalent to a struct/tuple/newtype. + // Equivalent to a struct or tuple. return Univariant(mk_struct(cx, &cases[0].tys, false, t)); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f1b907e70d74e..709e36989244f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,7 +19,7 @@ use rustc::middle::cstore; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, VariantKind}; use rustc::util::nodemap::FnvHashSet; use rustc_const_eval::lookup_const_by_id; @@ -207,11 +207,10 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { - struct_type: match &variant.fields[..] { - &[] => doctree::Unit, - &[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype, - &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, - _ => doctree::Plain, + struct_type: match variant.kind { + VariantKind::Struct => doctree::Plain, + VariantKind::Tuple => doctree::Tuple, + VariantKind::Unit => doctree::Unit, }, generics: (t.generics, &predicates).clean(cx), fields: variant.fields.clean(cx), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index cc62fcfa0aa8b..c2404f4294e96 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -82,14 +82,12 @@ impl Module { #[derive(Debug, Clone, RustcEncodable, RustcDecodable, Copy)] pub enum StructType { - /// A normal struct + /// A braced struct Plain, /// A tuple struct Tuple, - /// A newtype struct (tuple struct with one element) - Newtype, /// A unit struct - Unit + Unit, } pub enum TypeBound { @@ -262,15 +260,10 @@ pub struct Import { pub whence: Span, } -pub fn struct_type_from_def(sd: &hir::VariantData) -> StructType { - if !sd.is_struct() { - // We are in a tuple-struct - match sd.fields().len() { - 0 => Unit, - 1 => Newtype, - _ => Tuple - } - } else { - Plain +pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType { + match *vdata { + hir::VariantData::Struct(..) => Plain, + hir::VariantData::Tuple(..) => Tuple, + hir::VariantData::Unit(..) => Unit, } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6da7423edb89f..df6b3239cd863 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2537,7 +2537,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } write!(w, "}}")?; } - doctree::Tuple | doctree::Newtype => { + doctree::Tuple => { write!(w, "(")?; for (i, field) in fields.iter().enumerate() { if i > 0 { From 03161e9b12621364d44b7fb85694ddf9901ce50f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 717/768] Remove some more dead code from mem categorization --- src/librustc/middle/mem_categorization.rs | 98 +++++------------------ 1 file changed, 20 insertions(+), 78 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5594ac413e238..c419f96e82095 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -67,7 +67,6 @@ pub use self::ElementKind::*; pub use self::MutabilityCategory::*; pub use self::AliasableReason::*; pub use self::Note::*; -pub use self::deref_kind::*; use self::Aliasability::*; @@ -195,47 +194,6 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; -// We pun on *T to mean both actual deref of a ptr as well -// as accessing of components: -#[derive(Copy, Clone)] -pub enum deref_kind<'tcx> { - deref_ptr(PointerKind<'tcx>), - deref_interior(InteriorKind), -} - -type DerefKindContext = Option; - -// Categorizes a derefable type. Note that we include vectors and strings as -// derefable (we model an index as the combination of a deref and then a -// pointer adjustment). -fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { - match t.sty { - ty::TyBox(_) => { - Ok(deref_ptr(Unique)) - } - - ty::TyRef(r, mt) => { - let kind = ty::BorrowKind::from_mutbl(mt.mutbl); - Ok(deref_ptr(BorrowedPtr(kind, r))) - } - - ty::TyRawPtr(ref mt) => { - Ok(deref_ptr(UnsafePtr(mt.mutbl))) - } - - ty::TyArray(..) | ty::TySlice(_) => { - // no deref of indexed content without supplying InteriorOffsetKind - if let Some(context) = context { - Ok(deref_interior(InteriorElement(context, ElementKind::VecElement))) - } else { - Err(()) - } - } - - _ => Err(()), - } -} - pub trait ast_node { fn id(&self) -> ast::NodeId; fn span(&self) -> Span; @@ -472,7 +430,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { autoderefs, cmt); for deref in 1..autoderefs + 1 { - cmt = self.cat_deref(expr, cmt, deref, None)?; + cmt = self.cat_deref(expr, cmt, deref)?; } return Ok(cmt); } @@ -484,7 +442,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { let base_cmt = self.cat_expr(&e_base)?; - self.cat_deref(expr, base_cmt, 0, None) + self.cat_deref(expr, base_cmt, 0) } hir::ExprField(ref base, f_name) => { @@ -503,7 +461,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprIndex(ref base, _) => { let method_call = ty::MethodCall::expr(expr.id()); - let context = InteriorOffsetKind::Index; match self.infcx.node_method_ty(method_call) { Some(method_ty) => { // If this is an index implemented by a method call, then it @@ -525,10 +482,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // is an rvalue. That is what we will be // dereferencing. let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty); - self.cat_deref_common(expr, base_cmt, 1, elem_ty, Some(context), true) + Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)) } None => { - self.cat_index(expr, self.cat_expr(&base)?, context) + self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index) } } } @@ -903,8 +860,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { fn cat_deref(&self, node: &N, base_cmt: cmt<'tcx>, - deref_cnt: usize, - deref_context: DerefKindContext) + deref_cnt: usize) -> McResult> { let method_call = ty::MethodCall { expr_id: node.id(), @@ -926,12 +882,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let base_cmt_ty = base_cmt.ty; match base_cmt_ty.builtin_deref(true, ty::NoPreference) { Some(mt) => { - let ret = self.cat_deref_common(node, base_cmt, deref_cnt, - mt.ty, - deref_context, - /* implicit: */ false); + let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false); debug!("cat_deref ret {:?}", ret); - ret + Ok(ret) } None => { debug!("Explicit deref of non-derefable type: {:?}", @@ -946,40 +899,29 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { base_cmt: cmt<'tcx>, deref_cnt: usize, deref_ty: Ty<'tcx>, - deref_context: DerefKindContext, implicit: bool) - -> McResult> + -> cmt<'tcx> { - let (m, cat) = match deref_kind(base_cmt.ty, deref_context)? { - deref_ptr(ptr) => { - let ptr = if implicit { - match ptr { - BorrowedPtr(bk, r) => Implicit(bk, r), - _ => span_bug!(node.span(), - "Implicit deref of non-borrowed pointer") - } - } else { - ptr - }; - // for unique ptrs, we inherit mutability from the - // owning reference. - (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), - Categorization::Deref(base_cmt, deref_cnt, ptr)) - } - deref_interior(interior) => { - (base_cmt.mutbl.inherit(), Categorization::Interior(base_cmt, interior)) + let ptr = match base_cmt.ty.sty { + ty::TyBox(..) => Unique, + ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), + ty::TyRef(r, mt) => { + let bk = ty::BorrowKind::from_mutbl(mt.mutbl); + if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } } + ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty) }; let ret = Rc::new(cmt_ { id: node.id(), span: node.span(), - cat: cat, - mutbl: m, + // For unique ptrs, we inherit mutability from the owning reference. + mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), + cat: Categorization::Deref(base_cmt, deref_cnt, ptr), ty: deref_ty, note: NoteNone }); debug!("cat_deref_common ret {:?}", ret); - Ok(ret) + ret } pub fn cat_index(&self, @@ -1202,7 +1144,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, 0, None)?; + let subcmt = self.cat_deref(pat, cmt, 0)?; self.cat_pattern_(subcmt, &subpat, op)?; } From b57f1099b577d4d388cc5236fb6990275c028b5b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 718/768] Remove parsing of obsolete pre-1.0 syntaxes --- src/libsyntax/parse/obsolete.rs | 15 ++------- src/libsyntax/parse/parser.rs | 33 +------------------- src/test/parse-fail/obsolete-closure-kind.rs | 18 ----------- 3 files changed, 4 insertions(+), 62 deletions(-) delete mode 100644 src/test/parse-fail/obsolete-closure-kind.rs diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a1d7ddcdf4bdf..a46a788ca0808 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -19,8 +19,7 @@ use parse::parser; /// The specific types of unsupported syntax #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum ObsoleteSyntax { - ClosureKind, - ExternCrateString, + // Nothing here at the moment } pub trait ParserObsoleteMethods { @@ -36,18 +35,10 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. + #[allow(unused_variables)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { - ObsoleteSyntax::ClosureKind => ( - "`:`, `&mut:`, or `&:`", - "rely on inference instead", - true, - ), - ObsoleteSyntax::ExternCrateString => ( - "\"crate-name\"", - "use an identifier not in quotes instead", - false, // warning for now - ), + // Nothing here at the moment }; self.report(sp, kind, kind_str, desc, error); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded59..d0936fd981b50 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -47,7 +47,7 @@ use parse; use parse::classify; use parse::common::SeqSep; use parse::lexer::{Reader, TokenAndSpan}; -use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax}; +use parse::obsolete::ObsoleteSyntax; use parse::token::{self, intern, MatchNt, SubstNt, SpecialVarNt, InternedString}; use parse::token::{keywords, SpecialMacroVar}; use parse::{new_sub_parser_from_file, ParseSess}; @@ -1165,36 +1165,6 @@ impl<'a> Parser<'a> { }))) } - /// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`). - pub fn parse_obsolete_closure_kind(&mut self) -> PResult<'a, ()> { - let lo = self.span.lo; - if - self.check(&token::BinOp(token::And)) && - self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && - self.look_ahead(2, |t| *t == token::Colon) - { - self.bump(); - self.bump(); - self.bump(); - } else if - self.token == token::BinOp(token::And) && - self.look_ahead(1, |t| *t == token::Colon) - { - self.bump(); - self.bump(); - } else if - self.eat(&token::Colon) - { - /* nothing */ - } else { - return Ok(()); - } - - let span = mk_sp(lo, self.span.hi); - self.obsolete(span, ObsoleteSyntax::ClosureKind); - Ok(()) - } - pub fn parse_unsafety(&mut self) -> PResult<'a, Unsafety> { if self.eat_keyword(keywords::Unsafe) { return Ok(Unsafety::Unsafe); @@ -4728,7 +4698,6 @@ impl<'a> Parser<'a> { Vec::new() } else { self.expect(&token::BinOp(token::Or))?; - self.parse_obsolete_closure_kind()?; let args = self.parse_seq_to_before_end( &token::BinOp(token::Or), SeqSep::trailing_allowed(token::Comma), diff --git a/src/test/parse-fail/obsolete-closure-kind.rs b/src/test/parse-fail/obsolete-closure-kind.rs deleted file mode 100644 index 89134e806a75c..0000000000000 --- a/src/test/parse-fail/obsolete-closure-kind.rs +++ /dev/null @@ -1,18 +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. - -// Test that we generate obsolete syntax errors around usages of closure kinds: `|:|`, `|&:|` and -// `|&mut:|`. - -fn main() { - let a = |:| {}; //~ ERROR obsolete syntax: `:`, `&mut:`, or `&:` - let a = |&:| {}; //~ ERROR obsolete syntax: `:`, `&mut:`, or `&:` - let a = |&mut:| {}; //~ ERROR obsolete syntax: `:`, `&mut:`, or `&:` -} From 693676da4f65a14fbae2c44cd4e2a94ba0ccf6d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Sep 2016 18:33:35 -0400 Subject: [PATCH 719/768] add missing test --- src/test/run-pass/issue-35546.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/run-pass/issue-35546.rs diff --git a/src/test/run-pass/issue-35546.rs b/src/test/run-pass/issue-35546.rs new file mode 100644 index 0000000000000..e8d14f1d42146 --- /dev/null +++ b/src/test/run-pass/issue-35546.rs @@ -0,0 +1,28 @@ +// 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. + +// Regression test for #35546. Check that we are able to codegen +// this. Before we had problems because of the drop glue signature +// around dropping a trait object (specifically, when dropping the +// `value` field of `Node`). + +struct Node { + next: Option>>, + value: T, +} + +fn clear(head: &mut Option>>) { + match head.take() { + Some(node) => *head = node.next, + None => (), + } +} + +fn main() {} From 606cdede0deaa6678fe7db3cc12b1a1e063012ee Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Tue, 13 Sep 2016 17:21:54 -0700 Subject: [PATCH 720/768] Add checked operation methods to Duration --- src/libstd/time/duration.rs | 162 ++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 79bbe5e7daa45..12e580fe80184 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -97,6 +97,130 @@ impl Duration { #[stable(feature = "duration", since = "1.3.0")] #[inline] pub fn subsec_nanos(&self) -> u32 { self.nanos } + + /// Checked duration addition. Computes `self + other`, returning `None` + /// if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_add(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_add(rhs.secs) { + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + if let Some(new_secs) = secs.checked_add(1) { + secs = new_secs; + } else { + return None; + } + } + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs: secs, + nanos: nanos, + }) + } else { + None + } + } + + /// Checked duration subtraction. Computes `self + other`, returning `None` + /// if the result would be negative or if underflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_sub(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { + let nanos = if self.nanos >= rhs.nanos { + self.nanos - rhs.nanos + } else { + if let Some(sub_secs) = secs.checked_sub(1) { + secs = sub_secs; + self.nanos + NANOS_PER_SEC - rhs.nanos + } else { + return None; + } + }; + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } + + /// Checked integer multiplication. Computes `self * other`, returning + /// `None` if underflow or overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); + /// assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_mul(self, rhs: u32) -> Option { + // Multiply nanoseconds as u64, because it cannot overflow that way. + let total_nanos = self.nanos as u64 * rhs as u64; + let extra_secs = total_nanos / (NANOS_PER_SEC as u64); + let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; + if let Some(secs) = self.secs + .checked_mul(rhs as u64) + .and_then(|s| s.checked_add(extra_secs)) { + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs: secs, + nanos: nanos, + }) + } else { + None + } + } + + /// Checked duration division. Computes `self / other`, returning `None` + /// if `other == 0` or the operation results in underflow or overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + /// assert_eq!(Duration::new(2, 0).checked_div(0), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_div(self, rhs: u32) -> Option { + if rhs != 0 { + let secs = self.secs / (rhs as u64); + let carry = self.secs - secs * (rhs as u64); + let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); + let nanos = self.nanos / rhs + (extra_nanos as u32); + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } } #[stable(feature = "duration", since = "1.3.0")] @@ -234,6 +358,15 @@ mod tests { Duration::new(1, 1)); } + #[test] + fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + } + #[test] fn sub() { assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), @@ -244,6 +377,18 @@ mod tests { Duration::new(0, 999_999_999)); } + #[test] + fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); + } + #[test] #[should_panic] fn sub_bad1() { Duration::new(0, 0) - Duration::new(0, 1); @@ -263,6 +408,16 @@ mod tests { Duration::new(2000, 4000)); } + #[test] + fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + } + #[test] fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); @@ -270,4 +425,11 @@ mod tests { assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990)); } + + #[test] + fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); + } } From 07b41b5555f2582ce741569ce44116451105742c Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Tue, 13 Sep 2016 17:32:24 -0700 Subject: [PATCH 721/768] Fix Duration::checked_mul documentation --- src/libstd/time/duration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 12e580fe80184..3024a44a208ab 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -164,7 +164,7 @@ impl Duration { } } - /// Checked integer multiplication. Computes `self * other`, returning + /// Checked duration multiplication. Computes `self * other`, returning /// `None` if underflow or overflow occurred. /// /// # Examples From b1bcd185b01e1aee3a6c2e976e915b244626e129 Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Tue, 13 Sep 2016 17:58:45 -0700 Subject: [PATCH 722/768] Implement add, sub, mul and div methods using checked methods for Duration --- src/libstd/time/duration.rs | 39 ++++--------------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 3024a44a208ab..a3493f0593c8c 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -228,15 +228,7 @@ impl Add for Duration { type Output = Duration; fn add(self, rhs: Duration) -> Duration { - let mut secs = self.secs.checked_add(rhs.secs) - .expect("overflow when adding durations"); - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs = secs.checked_add(1).expect("overflow when adding durations"); - } - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_add(rhs).expect("overflow when adding durations") } } @@ -252,17 +244,7 @@ impl Sub for Duration { type Output = Duration; fn sub(self, rhs: Duration) -> Duration { - let mut secs = self.secs.checked_sub(rhs.secs) - .expect("overflow when subtracting durations"); - let nanos = if self.nanos >= rhs.nanos { - self.nanos - rhs.nanos - } else { - secs = secs.checked_sub(1) - .expect("overflow when subtracting durations"); - self.nanos + NANOS_PER_SEC - rhs.nanos - }; - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_sub(rhs).expect("overflow when subtracting durations") } } @@ -278,15 +260,7 @@ impl Mul for Duration { type Output = Duration; fn mul(self, rhs: u32) -> Duration { - // Multiply nanoseconds as u64, because it cannot overflow that way. - let total_nanos = self.nanos as u64 * rhs as u64; - let extra_secs = total_nanos / (NANOS_PER_SEC as u64); - let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; - let secs = self.secs.checked_mul(rhs as u64) - .and_then(|s| s.checked_add(extra_secs)) - .expect("overflow when multiplying duration"); - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") } } @@ -302,12 +276,7 @@ impl Div for Duration { type Output = Duration; fn div(self, rhs: u32) -> Duration { - let secs = self.secs / (rhs as u64); - let carry = self.secs - secs * (rhs as u64); - let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); - let nanos = self.nanos / rhs + (extra_nanos as u32); - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") } } From fae439b92f68a67444814243d4951943a43b0273 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 13 Sep 2016 22:07:38 -0400 Subject: [PATCH 723/768] Add doc examples for std::net::IpAddr construction. --- src/libstd/net/ip.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index c6a7a77e68a6b..05ef559422f33 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -22,6 +22,24 @@ use sys::net::netc as c; use sys_common::{AsInner, FromInner}; /// An IP address, either an IPv4 or IPv6 address. +/// +/// # Examples +/// +/// Constructing an IPv4 address: +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr}; +/// +/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// ``` +/// +/// Constructing an IPv6 address: +/// +/// ``` +/// use std::net::{IpAddr, Ipv6Addr}; +/// +/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] pub enum IpAddr { From 1b3a588f55c84d4fc36f4889f4c7ef7357ad471a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 22:09:22 -0400 Subject: [PATCH 724/768] trans: Let the collector find drop-glue for all vtables, not just VTableImpl. --- src/librustc_trans/collector.rs | 13 ++++++----- .../instantiation-through-vtable.rs | 2 -- .../codegen-units/item-collection/unsizing.rs | 2 -- .../partitioning/vtable-through-const.rs | 2 -- src/test/run-pass/issue36260.rs | 22 +++++++++++++++++++ 5 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/issue36260.rs diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5a8ab62a2aa2d..a58de71ca41ed 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } } - mir::Rvalue::Box(_) => { + mir::Rvalue::Box(..) => { let exchange_malloc_fn_def_id = self.scx .tcx() @@ -1072,15 +1072,16 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, }); output.extend(items); - - // Also add the destructor - let dg_type = glue::get_drop_glue_type(scx.tcx(), - trait_ref.self_ty()); - output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); } _ => { /* */ } } } + + // Also add the destructor + let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty); + if glue::type_needs_drop(scx.tcx(), dg_type) { + output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); + } } } diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index 06e547f0dd037..b772525122001 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -40,5 +40,3 @@ fn main() { //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 5c67ab7a82646..45ba441bc8ba6 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -78,5 +78,3 @@ fn main() //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index b40bb7f60973a..ee5e97cd9c212 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -89,5 +89,3 @@ fn main() { //~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const[Internal] mod1::ID_CHAR('x'); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/run-pass/issue36260.rs b/src/test/run-pass/issue36260.rs new file mode 100644 index 0000000000000..08dbbb5c9fe13 --- /dev/null +++ b/src/test/run-pass/issue36260.rs @@ -0,0 +1,22 @@ +// Copyright 2012-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. + +// Make sure this compiles without getting a linker error because of missing +// drop-glue because the collector missed adding drop-glue for the closure: + +fn create_fn() -> Box { + let text = String::new(); + + Box::new(move || { let _ = &text; }) +} + +fn main() { + let _ = create_fn(); +} From 4715985b07184c3027456bdea74e9fde639b9bcc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Sep 2016 15:57:16 +1000 Subject: [PATCH 725/768] Remove unused Token::to_binop function. --- src/libsyntax/parse/token.rs | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index ff01d37581544..09bc5607946de 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -14,7 +14,7 @@ pub use self::DelimToken::*; pub use self::Lit::*; pub use self::Token::*; -use ast::{self, BinOpKind}; +use ast::{self}; use ptr::P; use util::interner::Interner; use tokenstream; @@ -258,31 +258,6 @@ impl Token { self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() } - /// Maps a token to its corresponding binary operator. - pub fn to_binop(&self) -> Option { - match *self { - BinOp(Star) => Some(BinOpKind::Mul), - BinOp(Slash) => Some(BinOpKind::Div), - BinOp(Percent) => Some(BinOpKind::Rem), - BinOp(Plus) => Some(BinOpKind::Add), - BinOp(Minus) => Some(BinOpKind::Sub), - BinOp(Shl) => Some(BinOpKind::Shl), - BinOp(Shr) => Some(BinOpKind::Shr), - BinOp(And) => Some(BinOpKind::BitAnd), - BinOp(Caret) => Some(BinOpKind::BitXor), - BinOp(Or) => Some(BinOpKind::BitOr), - Lt => Some(BinOpKind::Lt), - Le => Some(BinOpKind::Le), - Ge => Some(BinOpKind::Ge), - Gt => Some(BinOpKind::Gt), - EqEq => Some(BinOpKind::Eq), - Ne => Some(BinOpKind::Ne), - AndAnd => Some(BinOpKind::And), - OrOr => Some(BinOpKind::Or), - _ => None, - } - } - /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { match *self { From 6353e30bb2d7968332217c04ac25e0800500fb33 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Sep 2016 18:31:26 -0400 Subject: [PATCH 726/768] clear obligations-added flag with nested fulfillcx This flag is a debugging measure designed to detect cases where we start a snapshot, create type variables, register obligations involving those type variables in the fulfillment cx, and then have to unroll the snapshot, leaving "dangling type variables" behind. HOWEVER, in some cases the flag is wrong. In particular, we sometimes create a "mini-fulfilment-cx" in which we enroll obligations. As long as this fulfillment cx is fully drained before we return, this is not a problem, as there won't be any escaping obligations in the main cx. So we add a fn to save/restore the flag. --- src/librustc/infer/mod.rs | 27 +++++++++++++++ src/librustc/traits/specialize/mod.rs | 46 ++++++++++++++------------ src/test/compile-fail/issue-36053-2.rs | 21 ++++++++++++ src/test/run-pass/issue-36053.rs | 32 ++++++++++++++++++ 4 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 src/test/compile-fail/issue-36053-2.rs create mode 100644 src/test/run-pass/issue-36053.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 59431f3f02dce..39fc50666a8ce 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -830,6 +830,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } + // Clear the "obligations in snapshot" flag, invoke the closure, + // then restore the flag to its original value. This flag is a + // debugging measure designed to detect cases where we start a + // snapshot, create type variables, register obligations involving + // those type variables in the fulfillment cx, and then have to + // unroll the snapshot, leaving "dangling type variables" behind. + // In such cases, the flag will be set by the fulfillment cx, and + // an assertion will fail when rolling the snapshot back. Very + // useful, much better than grovelling through megabytes of + // RUST_LOG output. + // + // HOWEVER, in some cases the flag is wrong. In particular, we + // sometimes create a "mini-fulfilment-cx" in which we enroll + // obligations. As long as this fulfillment cx is fully drained + // before we return, this is not a problem, as there won't be any + // escaping obligations in the main cx. In those cases, you can + // use this function. + pub fn save_and_restore_obligations_in_snapshot_flag(&self, func: F) -> R + where F: FnOnce(&Self) -> R + { + let flag = self.obligations_in_snapshot.get(); + self.obligations_in_snapshot.set(false); + let result = func(self); + self.obligations_in_snapshot.set(flag); + result + } + fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index f3ba4d16eb0b2..2f63526bf6c27 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -203,32 +203,34 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - let mut fulfill_cx = FulfillmentContext::new(); - for oblig in obligations.into_iter() { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - match fulfill_cx.select_all_or_error(infcx) { - Err(errors) => { - // no dice! - debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ - {:?}", - source_trait_ref, - target_trait_ref, - errors, - infcx.parameter_environment.caller_bounds); - Err(()) + infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| { + let mut fulfill_cx = FulfillmentContext::new(); + for oblig in obligations.into_iter() { + fulfill_cx.register_predicate_obligation(&infcx, oblig); } + match fulfill_cx.select_all_or_error(infcx) { + Err(errors) => { + // no dice! + debug!("fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + source_trait_ref, + target_trait_ref, + errors, + infcx.parameter_environment.caller_bounds); + Err(()) + } - Ok(()) => { - debug!("fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, - target_trait_ref); + Ok(()) => { + debug!("fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, + target_trait_ref); - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + } } - } + }) } pub struct SpecializesCache { diff --git a/src/test/compile-fail/issue-36053-2.rs b/src/test/compile-fail/issue-36053-2.rs new file mode 100644 index 0000000000000..7da529487aa86 --- /dev/null +++ b/src/test/compile-fail/issue-36053-2.rs @@ -0,0 +1,21 @@ +// 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. + +// Regression test for #36053. ICE was caused due to obligations +// being added to a special, dedicated fulfillment cx during +// a probe. + +use std::iter::once; +fn main() { + once::<&str>("str").fuse().filter(|a: &str| true).count(); + //~^ ERROR no method named `count` + //~| ERROR E0281 + //~| ERROR E0281 +} diff --git a/src/test/run-pass/issue-36053.rs b/src/test/run-pass/issue-36053.rs new file mode 100644 index 0000000000000..2411996cf054b --- /dev/null +++ b/src/test/run-pass/issue-36053.rs @@ -0,0 +1,32 @@ +// 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. + +// Regression test for #36053. ICE was caused due to obligations being +// added to a special, dedicated fulfillment cx during a +// probe. Problem seems to be related to the particular definition of +// `FusedIterator` in std but I was not able to isolate that into an +// external crate. + +#![feature(fused)] +use std::iter::FusedIterator; + +struct Thing<'a>(&'a str); +impl<'a> Iterator for Thing<'a> { + type Item = &'a str; + fn next(&mut self) -> Option<&'a str> { + None + } +} + +impl<'a> FusedIterator for Thing<'a> {} + +fn main() { + Thing("test").fuse().filter(|_| true).count(); +} From 35584629f4f8ad1eb32c4363fb9b5437e1052e5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Sep 2016 17:52:26 +0200 Subject: [PATCH 727/768] Update E0049 to new error format --- src/librustc_typeck/check/compare_method.rs | 35 +++++++++++++++++++-- src/librustc_typeck/check/mod.rs | 4 ++- src/test/compile-fail/E0049.rs | 3 +- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1604f34d57552..faad3f9b000cc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -38,7 +38,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span: Span, impl_m_body_id: ast::NodeId, trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + impl_trait_ref: &ty::TraitRef<'tcx>, + trait_item_span: Option) { debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); @@ -97,14 +98,42 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let num_impl_m_type_params = impl_m.generics.types.len(); let num_trait_m_type_params = trait_m.generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { - span_err!(tcx.sess, impl_m_span, E0049, + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if impl_m_sig.generics.is_parameterized() { + impl_m_sig.generics.span + } else { + impl_m_span + } + } + _ => bug!("{:?} is not a method", impl_m) + }; + + struct_span_err!(tcx.sess, span, E0049, "method `{}` has {} type parameter{} \ but its trait declaration has {} type parameter{}", trait_m.name, num_impl_m_type_params, if num_impl_m_type_params == 1 {""} else {"s"}, num_trait_m_type_params, - if num_trait_m_type_params == 1 {""} else {"s"}); + if num_trait_m_type_params == 1 {""} else {"s"}) + .span_label(trait_item_span.unwrap(), + &format!("expected {}", + &if num_trait_m_type_params != 1 { + format!("{} type parameters", + num_trait_m_type_params) + } else { + format!("{} type parameter", + num_trait_m_type_params) + })) + .span_label(span, &format!("found {}", + &if num_impl_m_type_params != 1 { + format!("{} type parameters", num_impl_m_type_params) + } else { + format!("1 type parameter") + })) + .emit(); return; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 005cd2e46b89f..455bde9421d7f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1015,13 +1015,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => span_bug!(impl_item.span, "non-method impl-item for method") }; + let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { compare_impl_method(ccx, &impl_method, impl_item.span, body.id, &trait_method, - &impl_trait_ref); + &impl_trait_ref, + trait_span); } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ diff --git a/src/test/compile-fail/E0049.rs b/src/test/compile-fail/E0049.rs index 5867e11e9acc6..33ebd3f7aca5e 100644 --- a/src/test/compile-fail/E0049.rs +++ b/src/test/compile-fail/E0049.rs @@ -9,13 +9,14 @@ // except according to those terms. trait Foo { - fn foo(x: T) -> Self; + fn foo(x: T) -> Self; //~ NOTE expected 1 type parameter } struct Bar; impl Foo for Bar { fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 + //~| NOTE found 0 type parameters } fn main() { From a4ee9c6e96025fa2b5eb254e4ccdd4c6910f5f60 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Tue, 13 Sep 2016 20:51:39 +0200 Subject: [PATCH 728/768] core: Use primitive indexing in slice's Index/IndexMut [T]'s Index implementation is normally not used for indexing, instead the compiler supplied indexing is used. Use the compiler supplied version in Index/IndexMut. This removes an inconsistency: Compiler supplied bound check failures look like this: thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' If you convince Rust to use the Index impl for slices, bounds check failure looks like this instead: thread 'main' panicked at 'assertion failed: index < self.len()' The latter is used if you for example use Index generically:: use std::ops::Index; fn foo(x: &T) where T: Index { &x[4]; } foo(&[1, 2, 3][..]) --- src/libcore/slice.rs | 8 ++++---- src/test/run-fail/bounds-check-no-overflow.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index b22bdb43414fd..9755623365961 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -520,8 +520,8 @@ impl ops::Index for [T] { type Output = T; fn index(&self, index: usize) -> &T { - assert!(index < self.len()); - unsafe { self.get_unchecked(index) } + // NB built-in indexing + &(*self)[index] } } @@ -530,8 +530,8 @@ impl ops::Index for [T] { impl ops::IndexMut for [T] { #[inline] fn index_mut(&mut self, index: usize) -> &mut T { - assert!(index < self.len()); - unsafe { self.get_unchecked_mut(index) } + // NB built-in indexing + &mut (*self)[index] } } diff --git a/src/test/run-fail/bounds-check-no-overflow.rs b/src/test/run-fail/bounds-check-no-overflow.rs index 4d502cb2106b1..3d1cbb446e848 100644 --- a/src/test/run-fail/bounds-check-no-overflow.rs +++ b/src/test/run-fail/bounds-check-no-overflow.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assertion failed: index < self.len() +// error-pattern:index out of bounds use std::usize; use std::mem::size_of; From a6da082e102966284857dc6849a0043e31b367e2 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 14 Sep 2016 22:41:17 +0200 Subject: [PATCH 729/768] doc: make that sound better --- src/libstd/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 63bf051c9bcd0..76eb92bd55989 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -83,7 +83,7 @@ pub struct VarsOs { inner: os_imp::Env } /// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation, modifications to environment +/// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// /// # Panics @@ -112,7 +112,7 @@ pub fn vars() -> Vars { /// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation, modifications to environment +/// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// /// # Examples From f2eb4f11d0c1e5667678def88235309bd083e7fe Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Wed, 14 Sep 2016 15:41:19 -0700 Subject: [PATCH 730/768] Fix doc-tests for Duration --- src/libstd/time/duration.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index a3493f0593c8c..6931c8d631527 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -106,8 +106,10 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); /// ``` #[unstable(feature = "duration_checked_ops", issue = "35774")] #[inline] @@ -140,6 +142,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); /// ``` @@ -172,8 +176,10 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); - /// assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); /// ``` #[unstable(feature = "duration_checked_ops", issue = "35774")] #[inline] @@ -203,6 +209,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); /// assert_eq!(Duration::new(2, 0).checked_div(0), None); From b6321bd13362d69dc0bc4a1ca8416d58b0ff63d2 Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Wed, 14 Sep 2016 17:13:06 -0700 Subject: [PATCH 731/768] Add feature crate attribute for duration_checked_ops to docs --- src/libstd/time/duration.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 6931c8d631527..246c57ab23871 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -106,6 +106,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); @@ -142,6 +144,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); @@ -176,6 +180,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); @@ -209,6 +215,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); From 5cab9525ae12a18ec0583ee1ddba3a9eb31a5cfd Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 14 Sep 2016 22:49:36 -0400 Subject: [PATCH 732/768] Don't ignore a doc code-block we can compile. --- src/doc/book/traits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index d07fb6b7c45bf..b0d954adf6771 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -291,7 +291,7 @@ let result = f.write(buf); We need to `use` the `Write` trait first: -```rust,ignore +```rust,no_run use std::io::Write; let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); From b232f6d9fe9ce822aa38cb164e4dce3e4faf5cc4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 14 Sep 2016 22:36:42 +0000 Subject: [PATCH 733/768] Avoid loading and parsing unconfigured non-inline modules. --- src/libsyntax/config.rs | 2 +- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 3f5b294cc0443..abbbbe1e3d1cc 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -126,7 +126,7 @@ impl<'a> StripUnconfigured<'a> { } // Determine if a node with the given attributes should be included in this configuation. - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { // When not compiling with --test we should not compile the #[test] functions if !self.should_test && is_test_or_bench(attr) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded59..fd2ae3b49083e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5291,20 +5291,29 @@ impl<'a> Parser<'a> { /// Parse a `mod { ... }` or `mod ;` item fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { - let outer_attrs = ::config::StripUnconfigured { - config: &self.cfg, - sess: self.sess, - should_test: false, // irrelevant - features: None, // don't perform gated feature checking - }.process_cfg_attrs(outer_attrs.to_owned()); + let (in_cfg, outer_attrs) = { + let mut strip_unconfigured = ::config::StripUnconfigured { + config: &self.cfg, + sess: self.sess, + should_test: false, // irrelevant + features: None, // don't perform gated feature checking + }; + let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned()); + (strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) + }; let id_span = self.span; let id = self.parse_ident()?; if self.check(&token::Semi) { self.bump(); - // This mod is in an external file. Let's go get it! - let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?; - Ok((id, m, Some(attrs))) + if in_cfg { + // This mod is in an external file. Let's go get it! + let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?; + Ok((id, m, Some(attrs))) + } else { + let placeholder = ast::Mod { inner: syntax_pos::DUMMY_SP, items: Vec::new() }; + Ok((id, ItemKind::Mod(placeholder), None)) + } } else { let directory = self.directory.clone(); self.push_directory(id, &outer_attrs); From 6f0ee455023fe24cade7a8ebb0af31c2ac98548e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 14 Sep 2016 22:40:56 +0000 Subject: [PATCH 734/768] Add regression test. --- src/test/run-pass/conditional-compile.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 5891d9f1aa019..c8e9cbdae1e84 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -148,3 +148,6 @@ mod test_methods { fn the(&self); } } + +#[cfg(any())] +mod nonexistent_file; // Check that unconfigured non-inline modules are not loaded or parsed. From af1a3ffbebef27f3dc267e66c15325596d1a2cff Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 15 Sep 2016 09:59:55 +0200 Subject: [PATCH 735/768] Remove data structure specialization for .zip() iterator Go back on half the specialization, the part that changed the Zip struct's fields themselves depending on the types of the iterators. This means that the Zip iterator will always carry two usize fields, which are unused. If a whole for loop using a .zip() iterator is inlined, these are simply removed and have no effect. The same improvement for Zip of for example slice iterators remain, and they still optimize well. However, like when the specialization of zip was merged, the compiler is still very sensistive to the exact context. For example this code only autovectorizes if the function is used, not if the code in zip_sum_i32 is inserted inline it was called: ``` fn zip_sum_i32(xs: &[i32], ys: &[i32]) -> i32 { let mut s = 0; for (&x, &y) in xs.iter().zip(ys) { s += x * y; } s } fn zipdot_i32_default_zip(b: &mut test::Bencher) { let xs = vec![1; 1024]; let ys = vec![1; 1024]; b.iter(|| { zip_sum_i32(&xs, &ys) }) } ``` Include a test that checks that Zip is covariant w.r.t. T and U. --- src/libcore/iter/mod.rs | 52 +++++-------------- .../run-pass/variance-iterators-in-libcore.rs | 17 ++++++ 2 files changed, 31 insertions(+), 38 deletions(-) create mode 100644 src/test/run-pass/variance-iterators-in-libcore.rs diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index b1d3ab1d1febc..dd57fd1b5190f 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -643,7 +643,9 @@ impl FusedIterator for Chain pub struct Zip { a: A, b: B, - spec: <(A, B) as ZipImplData>::Data, + // index and len are only used by the specialized version of zip + index: usize, + len: usize, } #[stable(feature = "rust1", since = "1.0.0")] @@ -685,17 +687,6 @@ trait ZipImpl { B: DoubleEndedIterator + ExactSizeIterator; } -// Zip specialization data members -#[doc(hidden)] -trait ZipImplData { - type Data: 'static + Clone + Default + fmt::Debug; -} - -#[doc(hidden)] -impl ZipImplData for T { - default type Data = (); -} - // General Zip impl #[doc(hidden)] impl ZipImpl for Zip @@ -706,7 +697,8 @@ impl ZipImpl for Zip Zip { a: a, b: b, - spec: Default::default(), // unused + index: 0, // unused + len: 0, // unused } } @@ -759,20 +751,6 @@ impl ZipImpl for Zip } } -#[doc(hidden)] -#[derive(Default, Debug, Clone)] -struct ZipImplFields { - index: usize, - len: usize, -} - -#[doc(hidden)] -impl ZipImplData for (A, B) - where A: TrustedRandomAccess, B: TrustedRandomAccess -{ - type Data = ZipImplFields; -} - #[doc(hidden)] impl ZipImpl for Zip where A: TrustedRandomAccess, B: TrustedRandomAccess @@ -782,18 +760,16 @@ impl ZipImpl for Zip Zip { a: a, b: b, - spec: ZipImplFields { - index: 0, - len: len, - } + index: 0, + len: len, } } #[inline] fn next(&mut self) -> Option<(A::Item, B::Item)> { - if self.spec.index < self.spec.len { - let i = self.spec.index; - self.spec.index += 1; + if self.index < self.len { + let i = self.index; + self.index += 1; unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } @@ -804,7 +780,7 @@ impl ZipImpl for Zip #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.spec.len - self.spec.index; + let len = self.len - self.index; (len, Some(len)) } @@ -813,9 +789,9 @@ impl ZipImpl for Zip where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator { - if self.spec.index < self.spec.len { - self.spec.len -= 1; - let i = self.spec.len; + if self.index < self.len { + self.len -= 1; + let i = self.len; unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } diff --git a/src/test/run-pass/variance-iterators-in-libcore.rs b/src/test/run-pass/variance-iterators-in-libcore.rs new file mode 100644 index 0000000000000..b9677d5ba8598 --- /dev/null +++ b/src/test/run-pass/variance-iterators-in-libcore.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. + +#![allow(warnings)] + +use std::iter::Zip; + +fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter } + +fn main() { } From c10176ef66b00af7cdfdcf85e2351381f8b38d07 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 11:40:16 -0400 Subject: [PATCH 736/768] trans: Only translate #[inline] functions if they are used somewhere. --- src/librustc_trans/base.rs | 6 ++- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/partitioning.rs | 71 +----------------------------- src/librustc_trans/trans_item.rs | 33 +++++++------- 4 files changed, 25 insertions(+), 87 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a6581ae605b56..fcfe53d0c8512 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1591,7 +1591,11 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.map.local_def_id(id); let generics = tcx.lookup_generics(def_id); - generics.parent_types == 0 && generics.types.is_empty() + let attributes = tcx.get_attrs(def_id); + (generics.parent_types == 0 && generics.types.is_empty()) && + // Functions marked with #[inline] are only ever translated + // with "internal" linkage and are never exported. + !attr::requests_inline(&attributes[..]) } _ => false diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5a8ab62a2aa2d..f193c0482f709 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -401,7 +401,7 @@ fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callees: &[TransItem<'tcx>], inlining_map: &mut InliningMap<'tcx>) { let is_inlining_candidate = |trans_item: &TransItem<'tcx>| { - trans_item.is_from_extern_crate() || trans_item.requests_inline(tcx) + trans_item.needs_local_copy(tcx) }; let inlining_candidates = callees.into_iter() diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index a161bd199b1f6..798e883c9557c 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -261,12 +261,6 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { let tcx = scx.tcx(); - if let PartitioningStrategy::FixedUnitCount(1) = strategy { - // If there is only a single codegen-unit, we can use a very simple - // scheme and don't have to bother with doing much analysis. - return vec![single_codegen_unit(tcx, trans_items, reachable)]; - } - // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. @@ -320,7 +314,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let mut codegen_units = FnvHashMap(); for trans_item in trans_items { - let is_root = !trans_item.is_instantiated_only_on_demand(); + let is_root = !trans_item.is_instantiated_only_on_demand(tcx); if is_root { let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); @@ -454,7 +448,6 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit // reliably in that case. new_codegen_unit.items.insert(trans_item, llvm::InternalLinkage); } else { - assert!(trans_item.is_instantiated_only_on_demand()); // We can't be sure if this will also be instantiated // somewhere else, so we add an instance here with // InternalLinkage so we don't get any conflicts. @@ -550,68 +543,6 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return token::intern_and_get_ident(&mod_path[..]); } -fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trans_items: I, - reachable: &NodeSet) - -> CodegenUnit<'tcx> - where I: Iterator> -{ - let mut items = FnvHashMap(); - - for trans_item in trans_items { - let linkage = trans_item.explicit_linkage(tcx).unwrap_or_else(|| { - match trans_item { - TransItem::Static(node_id) => { - if reachable.contains(&node_id) { - llvm::ExternalLinkage - } else { - llvm::PrivateLinkage - } - } - TransItem::DropGlue(_) => { - llvm::InternalLinkage - } - TransItem::Fn(instance) => { - if trans_item.is_generic_fn() { - // FIXME(mw): Assigning internal linkage to all - // monomorphizations is potentially a waste of space - // since monomorphizations could be shared between - // crates. The main reason for making them internal is - // a limitation in MingW's binutils that cannot deal - // with COFF object that have more than 2^15 sections, - // which is something that can happen for large programs - // when every function gets put into its own COMDAT - // section. - llvm::InternalLinkage - } else if trans_item.is_from_extern_crate() { - // FIXME(mw): It would be nice if we could mark these as - // `AvailableExternallyLinkage`, since they should have - // been instantiated in the extern crate. But this - // sometimes leads to crashes on Windows because LLVM - // does not handle exception handling table instantiation - // reliably in that case. - llvm::InternalLinkage - } else if reachable.contains(&tcx.map - .as_local_node_id(instance.def) - .unwrap()) { - llvm::ExternalLinkage - } else { - // Functions that are not visible outside this crate can - // be marked as internal. - llvm::InternalLinkage - } - } - } - }); - - items.insert(trans_item, linkage); - } - - CodegenUnit::new( - numbered_codegen_unit_name(&tcx.crate_name[..], 0), - items) -} - fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { token::intern_and_get_ident(&format!("{}{}{}", crate_name, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 44e613c4c2b04..bde393b77e167 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -241,19 +241,6 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - match *self { - TransItem::Fn(ref instance) => { - instance.substs.types().next().is_some() || { - let attributes = tcx.get_attrs(instance.def); - attr::requests_inline(&attributes[..]) - } - } - TransItem::DropGlue(..) => true, - TransItem::Static(..) => false, - } - } - pub fn is_from_extern_crate(&self) -> bool { match *self { TransItem::Fn(ref instance) => !instance.def.is_local(), @@ -262,10 +249,14 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn is_instantiated_only_on_demand(&self) -> bool { + /// True if the translation item should only be translated to LLVM IR if + /// it is referenced somewhere (like inline functions, for example). + pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt) -> bool { match *self { TransItem::Fn(ref instance) => { - !instance.def.is_local() || instance.substs.types().next().is_some() + !instance.def.is_local() || + instance.substs.types().next().is_some() || + attr::requests_inline(&tcx.get_attrs(instance.def)[..]) } TransItem::DropGlue(..) => true, TransItem::Static(..) => false, @@ -282,6 +273,18 @@ impl<'a, 'tcx> TransItem<'tcx> { } } + /// Returns true if there has to be a local copy of this TransItem in every + /// codegen unit that references it (as with inlined functions, for example) + pub fn needs_local_copy(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + // Currently everything that is instantiated only on demand is done so + // with "internal" linkage, so we need a copy to be present in every + // codegen unit. + // This is coincidental: We could also instantiate something only if it + // is referenced (e.g. a regular, private function) but place it in its + // own codegen unit with "external" linkage. + self.is_instantiated_only_on_demand(tcx) + } + pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { let def_id = match *self { TransItem::Fn(ref instance) => instance.def, From eba2270a9cc1c0785cf42fa87fe154f425a2eea0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 25 Aug 2016 18:43:40 +0200 Subject: [PATCH 737/768] Add `pub fn ptr_eq(this: &Self, other: &Self) -> bool` to `Rc` and `Arc`. Servo and Kuchiki have had helper functions doing this for some time. --- src/liballoc/arc.rs | 37 +++++++++++++++++++++++++++++++++++++ src/liballoc/rc.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 3d579641b9658..5f9ccd1820ca6 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -331,6 +331,33 @@ impl Arc { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } + + #[inline] + #[unstable(feature = "ptr_eq", + reason = "newly added", + issue = "36497")] + /// Return whether two `Arc` references point to the same value + /// (not just values that compare equal). + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_eq)] + /// + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let same_five = five.clone(); + /// let other_five = Arc::new(5); + /// + /// assert!(Arc::ptr_eq(&five, &same_five)); + /// assert!(!Arc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + let this_ptr: *const ArcInner = *this.ptr; + let other_ptr: *const ArcInner = *other.ptr; + this_ptr == other_ptr + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1200,6 +1227,16 @@ mod tests { let foo: Weak = Weak::new(); assert!(foo.upgrade().is_none()); } + + #[test] + fn test_ptr_eq() { + let five = Arc::new(5); + let same_five = five.clone(); + let other_five = Arc::new(5); + + assert!(Arc::ptr_eq(&five, &same_five)); + assert!(!Arc::ptr_eq(&five, &other_five)); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index dadddbc2cb3e5..32e5587ff4128 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -376,6 +376,33 @@ impl Rc { None } } + + #[inline] + #[unstable(feature = "ptr_eq", + reason = "newly added", + issue = "36497")] + /// Return whether two `Rc` references point to the same value + /// (not just values that compare equal). + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_eq)] + /// + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let same_five = five.clone(); + /// let other_five = Rc::new(5); + /// + /// assert!(Rc::ptr_eq(&five, &same_five)); + /// assert!(!Rc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + let this_ptr: *const RcBox = *this.ptr; + let other_ptr: *const RcBox = *other.ptr; + this_ptr == other_ptr + } } impl Rc { @@ -1174,6 +1201,16 @@ mod tests { let foo: Weak = Weak::new(); assert!(foo.upgrade().is_none()); } + + #[test] + fn test_ptr_eq() { + let five = Rc::new(5); + let same_five = five.clone(); + let other_five = Rc::new(5); + + assert!(Rc::ptr_eq(&five, &same_five)); + assert!(!Rc::ptr_eq(&five, &other_five)); + } } #[stable(feature = "rust1", since = "1.0.0")] From 5ce9feeb8cb48a89feffe579cfc1a9281b4dfbb0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 15 Sep 2016 11:19:19 +0200 Subject: [PATCH 738/768] Add std::ptr::eq, for referential equality of &T references. Fixes https://github.com/rust-lang/rfcs/issues/1155 --- src/libcore/ptr.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 8c8925251e5cf..69682652a6a51 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -479,6 +479,40 @@ impl PartialEq for *mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for *mut T {} +/// Compare raw pointers for equality. +/// +/// This is the same as using the `==` operator, but less generic: +/// the arguments have to be `*const T` raw pointers, +/// not anything that implements `PartialEq`. +/// +/// This can be used to compare `&T` references (which coerce to `*const T` implicitly) +/// by their address rather than comparing the values they point to +/// (which is what the `PartialEq for &T` implementation does). +/// +/// # Examples +/// +/// ``` +/// #![feature(ptr_eq)] +/// use std::ptr; +/// +/// let five = 5; +/// let other_five = 5; +/// let five_ref = &five; +/// let same_five_ref = &five; +/// let other_five_ref = &other_five; +/// +/// assert!(five_ref == same_five_ref); +/// assert!(five_ref == other_five_ref); +/// +/// assert!(ptr::eq(five_ref, same_five_ref)); +/// assert!(!ptr::eq(five_ref, other_five_ref)); +/// ``` +#[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")] +#[inline] +pub fn eq(a: *const T, b: *const T) -> bool { + a == b +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for *const T { #[inline] From 928c3981b63e63307a020e99ae67474a75652588 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 14:46:35 -0400 Subject: [PATCH 739/768] Adapt run-make/sep-comp-inlining test case to new behaviour --- src/test/run-make/sepcomp-inlining/Makefile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile index bc299de0c2d3f..ef43b0d97e417 100644 --- a/src/test/run-make/sepcomp-inlining/Makefile +++ b/src/test/run-make/sepcomp-inlining/Makefile @@ -1,13 +1,14 @@ -include ../tools.mk -# Test that #[inline(always)] functions still get inlined across compilation -# unit boundaries. Compilation should produce three IR files, with each one -# containing a definition of the inlined function. Also, the non-#[inline] -# function should be defined in only one compilation unit. +# Test that #[inline] functions still get inlined across compilation unit +# boundaries. Compilation should produce three IR files, but only the two +# compilation units that have a usage of the #[inline] function should +# contain a definition. Also, the non-#[inline] function should be defined +# in only one compilation unit. all: $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "1" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ available_externally\ i32\ .*inlined)" -eq "2" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ i32\ .*normal)" -eq "2" ] From b735c1bc7891a5a0176e544aa50c47b4d67f52b4 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sun, 11 Sep 2016 15:09:05 -0700 Subject: [PATCH 740/768] Tweak std::marker docs Fixes #29361. --- src/libcore/marker.rs | 423 ++++++++++++++++++++++++++---------------- 1 file changed, 268 insertions(+), 155 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c22c9f0d1c717..5a1a034a36358 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Primitive traits and marker types representing basic 'kinds' of types. +//! Primitive traits and types representing basic properties of types. //! //! Rust types can be classified in various useful ways according to -//! intrinsic properties of the type. These classifications, often called -//! 'kinds', are represented as traits. +//! their intrinsic properties. These classifications are represented +//! as traits. #![stable(feature = "rust1", since = "1.0.0")] @@ -22,7 +22,21 @@ use hash::Hasher; /// Types that can be transferred across thread boundaries. /// -/// This trait is automatically derived when the compiler determines it's appropriate. +/// This trait is automatically implemented when the compiler determines it's +/// appropriate. +/// +/// An example of a non-`Send` type is the reference-counting pointer +/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same +/// reference-counted value, they might try to update the reference count at the +/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic +/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring +/// some overhead) and thus is `Send`. +/// +/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [arc]: ../../std/sync/struct.Arc.html +/// [ub]: ../../reference.html#behavior-considered-undefined #[stable(feature = "rust1", since = "1.0.0")] #[lang = "send"] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] @@ -38,10 +52,10 @@ impl !Send for *const T { } #[stable(feature = "rust1", since = "1.0.0")] impl !Send for *mut T { } -/// Types with a constant size known at compile-time. +/// Types with a constant size known at compile time. /// -/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax -/// `?Sized` can be used to remove this bound if it is not appropriate. +/// All type parameters have an implicit bound of `Sized`. The special syntax +/// `?Sized` can be used to remove this bound if it's not appropriate. /// /// ``` /// # #![allow(dead_code)] @@ -51,6 +65,26 @@ impl !Send for *mut T { } /// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32] /// struct BarUse(Bar<[i32]>); // OK /// ``` +/// +/// The one exception is the implicit `Self` type of a trait, which does not +/// get an implicit `Sized` bound. This is because a `Sized` bound prevents +/// the trait from being used to form a [trait object]: +/// +/// ``` +/// # #![allow(unused_variables)] +/// trait Foo { } +/// trait Bar: Sized { } +/// +/// struct Impl; +/// impl Foo for Impl { } +/// impl Bar for Impl { } +/// +/// let x: &Foo = &Impl; // OK +/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot +/// // be made into an object +/// ``` +/// +/// [trait object]: ../../book/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] @@ -59,14 +93,27 @@ pub trait Sized { // Empty. } -/// Types that can be "unsized" to a dynamically sized type. +/// Types that can be "unsized" to a dynamically-sized type. +/// +/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and +/// `Unsize`. +/// +/// All implementations of `Unsize` are provided automatically by the compiler. +/// +/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow +/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized +/// types. See the [DST coercion RFC][RFC982] for more details. +/// +/// [coerceunsized]: ../ops/trait.CoerceUnsized.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md #[unstable(feature = "unsize", issue = "27732")] #[lang="unsize"] pub trait Unsize { // Empty. } -/// Types that can be copied by simply copying bits (i.e. `memcpy`). +/// Types whose values can be duplicated simply by copying bits. /// /// By default, variable bindings have 'move semantics.' In other /// words: @@ -87,7 +134,8 @@ pub trait Unsize { /// However, if a type implements `Copy`, it instead has 'copy semantics': /// /// ``` -/// // we can just derive a `Copy` implementation +/// // We can derive a `Copy` implementation. `Clone` is also required, as it's +/// // a supertrait of `Copy`. /// #[derive(Debug, Copy, Clone)] /// struct Foo; /// @@ -100,13 +148,59 @@ pub trait Unsize { /// println!("{:?}", x); // A-OK! /// ``` /// -/// It's important to note that in these two examples, the only difference is if you are allowed to -/// access `x` after the assignment: a move is also a bitwise copy under the hood. +/// It's important to note that in these two examples, the only difference is whether you +/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move +/// can result in bits being copied in memory, although this is sometimes optimized away. +/// +/// ## How can I implement `Copy`? +/// +/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`: +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct MyStruct; +/// ``` +/// +/// You can also implement `Copy` and `Clone` manually: +/// +/// ``` +/// struct MyStruct; +/// +/// impl Copy for MyStruct { } +/// +/// impl Clone for MyStruct { +/// fn clone(&self) -> MyStruct { +/// *self +/// } +/// } +/// ``` +/// +/// There is a small difference between the two: the `derive` strategy will also place a `Copy` +/// bound on type parameters, which isn't always desired. +/// +/// ## What's the difference between `Copy` and `Clone`? +/// +/// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of +/// `Copy` is not overloadable; it is always a simple bit-wise copy. +/// +/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can +/// provide any type-specific behavior necessary to duplicate values safely. For example, +/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string +/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the +/// pointer, leading to a double free down the line. For this reason, `String` is `Clone` +/// but not `Copy`. +/// +/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement +/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self` +/// (see the example above). +/// +/// [clone]: ../clone/trait.Clone.html +/// [string]: ../../std/string/struct.String.html /// /// ## When can my type be `Copy`? /// /// A type can implement `Copy` if all of its components implement `Copy`. For example, this -/// `struct` can be `Copy`: +/// struct can be `Copy`: /// /// ``` /// # #[allow(dead_code)] @@ -116,7 +210,8 @@ pub trait Unsize { /// } /// ``` /// -/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`. +/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`. +/// By contrast, consider /// /// ``` /// # #![allow(dead_code)] @@ -126,57 +221,35 @@ pub trait Unsize { /// } /// ``` /// -/// The `PointList` `struct` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we +/// The struct `PointList` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we /// attempt to derive a `Copy` implementation, we'll get an error: /// /// ```text /// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy` /// ``` /// -/// ## When can my type _not_ be `Copy`? +/// ## When *can't* my type be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference, and copying [`String`] would result in two attempts to free the same buffer. +/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s +/// buffer, leading to a double free. /// /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's /// managing some resource besides its own [`size_of::()`] bytes. /// -/// ## What if I derive `Copy` on a type that can't? -/// -/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error. -/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204) -/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205). -/// -/// ## When should my type be `Copy`? -/// -/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing -/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future, -/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking -/// change: that second example would fail to compile if we made `Foo` non-`Copy`. +/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a +/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get +/// [E0205]. /// -/// ## Derivable +/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204 +/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205 /// -/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type. +/// ## When *should* my type be `Copy`? /// -/// ## How can I implement `Copy`? -/// -/// There are two ways to implement `Copy` on your type: -/// -/// ``` -/// #[derive(Copy, Clone)] -/// struct MyStruct; -/// ``` -/// -/// and -/// -/// ``` -/// struct MyStruct; -/// impl Copy for MyStruct {} -/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } } -/// ``` -/// -/// There is a small difference between the two: the `derive` strategy will also place a `Copy` -/// bound on type parameters, which isn't always desired. +/// Generally speaking, if your type _can_ implement `Copy`, it should. Keep in mind, though, +/// that implementing `Copy` is part of the public API of your type. If the type might become +/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to +/// avoid a breaking API change. /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html @@ -188,64 +261,74 @@ pub trait Copy : Clone { // Empty. } -/// Types that can be safely shared between threads when aliased. +/// Types for which it is safe to share references between threads. +/// +/// This trait is automatically implemented when the compiler determines +/// it's appropriate. /// /// The precise definition is: a type `T` is `Sync` if `&T` is -/// thread-safe. In other words, there is no possibility of data races -/// when passing `&T` references between threads. -/// -/// As one would expect, primitive types like [`u8`] and [`f64`] are all -/// `Sync`, and so are simple aggregate types containing them (like -/// tuples, structs and enums). More instances of basic `Sync` types -/// include "immutable" types like `&T` and those with simple -/// inherited mutability, such as [`Box`], [`Vec`] and most other -/// collection types. (Generic parameters need to be `Sync` for their -/// container to be `Sync`.) -/// -/// A somewhat surprising consequence of the definition is `&mut T` is -/// `Sync` (if `T` is `Sync`) even though it seems that it might -/// provide unsynchronized mutation. The trick is a mutable reference -/// stored in an aliasable reference (that is, `& &mut T`) becomes -/// read-only, as if it were a `& &T`, hence there is no risk of a data -/// race. +/// [`Send`][send]. In other words, if there is no possibility of +/// [undefined behavior][ub] (including data races) when passing +/// `&T` references between threads. +/// +/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64] +/// are all `Sync`, and so are simple aggregate types containing them, +/// like tuples, structs and enums. More examples of basic `Sync` +/// types include "immutable" types like `&T`, and those with simple +/// inherited mutability, such as [`Box`][box], [`Vec`][vec] and +/// most other collection types. (Generic parameters need to be `Sync` +/// for their container to be `Sync`.) +/// +/// A somewhat surprising consequence of the definition is that `&mut T` +/// is `Sync` (if `T` is `Sync`) even though it seems like that might +/// provide unsynchronized mutation. The trick is that a mutable +/// reference behind a shared reference (that is, `& &mut T`) +/// becomes read-only, as if it were a `& &T`. Hence there is no risk +/// of a data race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe way, such as [`Cell`] and [`RefCell`] -/// in [`std::cell`]. These types allow for mutation of their contents -/// even when in an immutable, aliasable slot, e.g. the contents of -/// [`&Cell`][`Cell`] can be [`.set`], and do not ensure data races are -/// impossible, hence they cannot be `Sync`. A higher level example -/// of a non-`Sync` type is the reference counted pointer -/// [`std::rc::Rc`][`Rc`], because any reference [`&Rc`][`Rc`] can clone a new -/// reference, which modifies the reference counts in a non-atomic -/// way. -/// -/// For cases when one does need thread-safe interior mutability, -/// types like the atomics in [`std::sync`][`sync`] and [`Mutex`] / [`RwLock`] in -/// the [`sync`] crate do ensure that any mutation cannot cause data -/// races. Hence these types are `Sync`. -/// -/// Any types with interior mutability must also use the [`std::cell::UnsafeCell`] -/// wrapper around the value(s) which can be mutated when behind a `&` -/// reference; not doing this is undefined behavior (for example, -/// [`transmute`]-ing from `&T` to `&mut T` is invalid). +/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] +/// and [`cell::RefCell`][refcell]. These types allow for mutation of +/// their contents even through an immutable, shared reference. For +/// example the `set` method on `Cell` takes `&self`, so it requires +/// only a shared reference `&Cell`. The method performs no +/// synchronization, thus `Cell` cannot be `Sync`. /// -/// This trait is automatically derived when the compiler determines it's appropriate. +/// Another example of a non-`Sync` type is the reference-counting +/// pointer [`rc::Rc`][rc]. Given any reference `&Rc`, you can clone +/// a new `Rc`, modifying the reference counts in a non-atomic way. /// -/// [`u8`]: ../../std/primitive.u8.html -/// [`f64`]: ../../std/primitive.f64.html -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`Box`]: ../../std/boxed/struct.Box.html -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`std::cell`]: ../../std/cell/index.html -/// [`.set`]: ../../std/cell/struct.Cell.html#method.set -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [`sync`]: ../../std/sync/index.html -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`RwLock`]: ../../std/sync/struct.RwLock.html -/// [`std::cell::UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html -/// [`transmute`]: ../../std/mem/fn.transmute.html +/// For cases when one does need thread-safe interior mutability, +/// Rust provides [atomic data types], as well as explicit locking via +/// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types +/// ensure that any mutation cannot cause data races, hence the types +/// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe +/// analogue of `Rc`. +/// +/// Any types with interior mutability must also use the +/// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which +/// can be mutated through a shared reference. Failing to doing this is +/// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing +/// from `&T` to `&mut T` is invalid. +/// +/// See [the Nomicon](../../nomicon/send-and-sync.html) for more +/// details about `Sync`. +/// +/// [send]: trait.Send.html +/// [u8]: ../../std/primitive.u8.html +/// [f64]: ../../std/primitive.f64.html +/// [box]: ../../std/boxed/struct.Box.html +/// [vec]: ../../std/vec/struct.Vec.html +/// [cell]: ../cell/struct.Cell.html +/// [refcell]: ../cell/struct.RefCell.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [arc]: ../../std/sync/struct.Arc.html +/// [atomic data types]: ../sync/atomic/index.html +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [unsafecell]: ../cell/struct.UnsafeCell.html +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] @@ -314,29 +397,30 @@ macro_rules! impls{ ) } -/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, -/// even though it does not. This allows you to inform the compiler about certain safety properties -/// of your code. +/// Zero-sized type used to mark things that "act like" they own a `T`. /// -/// For a more in-depth explanation of how to use `PhantomData`, please see [the Nomicon]. +/// Adding a `PhantomData` field to your type tells the compiler that your +/// type acts as though it stores a value of type `T`, even though it doesn't +/// really. This information is used when computing certain safety properties. /// -/// [the Nomicon]: ../../nomicon/phantom-data.html +/// For a more in-depth explanation of how to use `PhantomData`, please see +/// [the Nomicon](../../nomicon/phantom-data.html). /// /// # A ghastly note 👻👻👻 /// -/// Though they both have scary names, `PhantomData` and 'phantom types' are related, but not -/// identical. Phantom types are a more general concept that don't require `PhantomData` to -/// implement, but `PhantomData` is the most common way to implement them in a correct manner. +/// Though they both have scary names, `PhantomData` and 'phantom types' are +/// related, but not identical. A phantom type parameter is simply a type +/// parameter which is never used. In Rust, this often causes the compiler to +/// complain, and the solution is to add a "dummy" use by way of `PhantomData`. /// /// # Examples /// -/// ## Unused lifetime parameter +/// ## Unused lifetime parameters /// -/// Perhaps the most common time that `PhantomData` is required is -/// with a struct that has an unused lifetime parameter, typically as -/// part of some unsafe code. For example, here is a struct `Slice` -/// that has two pointers of type `*const T`, presumably pointing into -/// an array somewhere: +/// Perhaps the most common use case for `PhantomData` is a struct that has an +/// unused lifetime parameter, typically as part of some unsafe code. For +/// example, here is a struct `Slice` that has two pointers of type `*const T`, +/// presumably pointing into an array somewhere: /// /// ```ignore /// struct Slice<'a, T> { @@ -350,7 +434,7 @@ macro_rules! impls{ /// intent is not expressed in the code, since there are no uses of /// the lifetime `'a` and hence it is not clear what data it applies /// to. We can correct this by telling the compiler to act *as if* the -/// `Slice` struct contained a borrowed reference `&'a T`: +/// `Slice` struct contained a reference `&'a T`: /// /// ``` /// use std::marker::PhantomData; @@ -359,29 +443,53 @@ macro_rules! impls{ /// struct Slice<'a, T: 'a> { /// start: *const T, /// end: *const T, -/// phantom: PhantomData<&'a T> +/// phantom: PhantomData<&'a T>, /// } /// ``` /// -/// This also in turn requires that we annotate `T:'a`, indicating -/// that `T` is a type that can be borrowed for the lifetime `'a`. +/// This also in turn requires the annotation `T: 'a`, indicating +/// that any references in `T` are valid over the lifetime `'a`. +/// +/// When initializing a `Slice` you simply provide the value +/// `PhantomData` for the field `phantom`: +/// +/// ``` +/// # #![allow(dead_code)] +/// # use std::marker::PhantomData; +/// # struct Slice<'a, T: 'a> { +/// # start: *const T, +/// # end: *const T, +/// # phantom: PhantomData<&'a T>, +/// # } +/// fn borrow_vec<'a, T>(vec: &'a Vec) -> Slice<'a, T> { +/// let ptr = vec.as_ptr(); +/// Slice { +/// start: ptr, +/// end: unsafe { ptr.offset(vec.len() as isize) }, +/// phantom: PhantomData, +/// } +/// } +/// ``` /// /// ## Unused type parameters /// -/// It sometimes happens that there are unused type parameters that +/// It sometimes happens that you have unused type parameters which /// indicate what type of data a struct is "tied" to, even though that /// data is not actually found in the struct itself. Here is an -/// example where this arises when handling external resources over a -/// foreign function interface. `PhantomData` can prevent -/// mismatches by enforcing types in the method implementations: +/// example where this arises with [FFI]. The foreign interface uses +/// handles of type `*mut ()` to refer to Rust values of different +/// types. We track the Rust type using a phantom type parameter on +/// the struct `ExternalResource` which wraps a handle. +/// +/// [FFI]: ../../book/ffi.html /// /// ``` /// # #![allow(dead_code)] -/// # trait ResType { fn foo(&self); } +/// # trait ResType { } /// # struct ParamType; /// # mod foreign_lib { -/// # pub fn new(_: usize) -> *mut () { 42 as *mut () } -/// # pub fn do_stuff(_: *mut (), _: usize) {} +/// # pub fn new(_: usize) -> *mut () { 42 as *mut () } +/// # pub fn do_stuff(_: *mut (), _: usize) {} /// # } /// # fn convert_params(_: ParamType) -> usize { 42 } /// use std::marker::PhantomData; @@ -408,21 +516,20 @@ macro_rules! impls{ /// } /// ``` /// -/// ## Indicating ownership +/// ## Ownership and the drop check /// -/// Adding a field of type `PhantomData` also indicates that your -/// struct owns data of type `T`. This in turn implies that when your -/// struct is dropped, it may in turn drop one or more instances of -/// the type `T`, though that may not be apparent from the other -/// structure of the type itself. This is commonly necessary if the -/// structure is using a raw pointer like `*mut T` whose referent -/// may be dropped when the type is dropped, as a `*mut T` is -/// otherwise not treated as owned. +/// Adding a field of type `PhantomData` indicates that your +/// type owns data of type `T`. This in turn implies that when your +/// type is dropped, it may drop one or more instances of the type +/// `T`. This has bearing on the Rust compiler's [drop check] +/// analysis. /// /// If your struct does not in fact *own* the data of type `T`, it is /// better to use a reference type, like `PhantomData<&'a T>` /// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so /// as not to indicate ownership. +/// +/// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; @@ -438,10 +545,13 @@ mod impls { /// Types that can be reflected over. /// -/// This trait is implemented for all types. Its purpose is to ensure -/// that when you write a generic function that will employ -/// reflection, that must be reflected (no pun intended) in the -/// generic bounds of that function. Here is an example: +/// By "reflection" we mean use of the [`Any`][any] trait, or related +/// machinery such as [`TypeId`][typeid]. +/// +/// `Reflect` is implemented for all types. Its purpose is to ensure +/// that when you write a generic function that will employ reflection, +/// that must be reflected (no pun intended) in the generic bounds of +/// that function. /// /// ``` /// #![feature(reflect_marker)] @@ -455,21 +565,24 @@ mod impls { /// } /// ``` /// -/// Without the declaration `T: Reflect`, `foo` would not type check -/// (note: as a matter of style, it would be preferable to write -/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but -/// we use `Reflect` here to show how it works). The `Reflect` bound -/// thus serves to alert `foo`'s caller to the fact that `foo` may -/// behave differently depending on whether `T = u32` or not. In -/// particular, thanks to the `Reflect` bound, callers know that a -/// function declared like `fn bar(...)` will always act in -/// precisely the same way no matter what type `T` is supplied, -/// because there are no bounds declared on `T`. (The ability for a -/// caller to reason about what a function may do based solely on what -/// generic bounds are declared is often called the ["parametricity -/// property"][1].) -/// -/// [1]: http://en.wikipedia.org/wiki/Parametricity +/// Without the bound `T: Reflect`, `foo` would not typecheck. (As +/// a matter of style, it would be preferable to write `T: Any`, +/// because `T: Any` implies `T: Reflect` and `T: 'static`, but we +/// use `Reflect` here for illustrative purposes.) +/// +/// The `Reflect` bound serves to alert `foo`'s caller to the +/// fact that `foo` may behave differently depending on whether +/// `T` is `u32` or not. The ability for a caller to reason about what +/// a function may do based solely on what generic bounds are declared +/// is often called the "[parametricity property][param]". Despite the +/// use of `Reflect`, Rust lacks true parametricity because a generic +/// function can, at the very least, call [`mem::size_of`][size_of] +/// without employing any trait bounds whatsoever. +/// +/// [any]: ../any/trait.Any.html +/// [typeid]: ../any/struct.TypeId.html +/// [param]: http://en.wikipedia.org/wiki/Parametricity +/// [size_of]: ../mem/fn.size_of.html #[rustc_reflect_like] #[unstable(feature = "reflect_marker", reason = "requires RFC and more experience", From 9f4e9083604f68c6ee55461687802dfecd753836 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 15 Sep 2016 21:34:21 +0200 Subject: [PATCH 741/768] correctly cancel some errors --- src/libsyntax/parse/parser.rs | 16 +++++++++++----- .../compile-fail/associated-types/issue-36499.rs | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/associated-types/issue-36499.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded59..fb8bf0f6181f0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -808,10 +808,12 @@ impl<'a> Parser<'a> { /// Eat and discard tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) { + let handler = self.diagnostic(); + self.parse_seq_to_before_tokens(kets, SeqSep::none(), |p| p.parse_token_tree(), - |mut e| e.cancel()); + |mut e| handler.cancel(&mut e)); } /// Parse a sequence, including the closing delimiter. The function @@ -1040,6 +1042,10 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.abort_if_errors(); } + fn cancel(&self, err: &mut DiagnosticBuilder) { + self.sess.span_diagnostic.cancel(err) + } + pub fn diagnostic(&self) -> &'a errors::Handler { &self.sess.span_diagnostic } @@ -2416,7 +2422,7 @@ impl<'a> Parser<'a> { ex = ExprKind::Lit(P(lit)); } Err(mut err) => { - err.cancel(); + self.cancel(&mut err); let msg = format!("expected expression, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); @@ -3732,7 +3738,7 @@ impl<'a> Parser<'a> { } } Err(mut err) => { - err.cancel(); + self.cancel(&mut err); let msg = format!("expected pattern, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); } @@ -4106,7 +4112,7 @@ impl<'a> Parser<'a> { } Err(mut e) => { self.recover_stmt_(SemiColonMode::Break); - e.cancel(); + self.cancel(&mut e); } _ => () } @@ -4347,7 +4353,7 @@ impl<'a> Parser<'a> { let span_hi = match self.parse_ty() { Ok(..) => self.span.hi, Err(ref mut err) => { - err.cancel(); + self.cancel(err); span_hi } }; diff --git a/src/test/compile-fail/associated-types/issue-36499.rs b/src/test/compile-fail/associated-types/issue-36499.rs new file mode 100644 index 0000000000000..b5b3ecbb580ae --- /dev/null +++ b/src/test/compile-fail/associated-types/issue-36499.rs @@ -0,0 +1,15 @@ +// 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. + +// error-pattern: aborting due to previous error + +fn main() { + 2 + +2; +} From ffaebadc990579c8813b3c21b5cd05c6bfdc595a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 15 Sep 2016 23:40:48 +0300 Subject: [PATCH 742/768] Default RUST_MIN_STACK to 16MiB for now --- src/librustc_driver/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fbd48fc42c92d..a18a754b184b0 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1054,7 +1054,8 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(f: F) { - const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB + // Temporarily have stack size set to 16MB to deal with nom-using crates failing + const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB struct Sink(Arc>>); impl Write for Sink { From 21ba8160f2aed7a2195015c5889c8a991181fe2f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 12 Sep 2016 09:47:54 +0000 Subject: [PATCH 743/768] Move fields `single_step` and `keep_macs` from `MacroExpander` to `ExpansionConfig`. --- src/librustc_driver/driver.rs | 2 +- src/libsyntax/ext/expand.rs | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 36e9fccdf5fd8..f07025910f07e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -674,11 +674,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, } let features = sess.features.borrow(); let cfg = syntax::ext::expand::ExpansionConfig { - crate_name: crate_name.to_string(), features: Some(&features), recursion_limit: sess.recursion_limit.get(), trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, + ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) }; let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 62e299684b760..eab59d3c9309b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -173,19 +173,12 @@ impl Invocation { pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, - pub single_step: bool, - pub keep_macs: bool, monotonic: bool, // c.f. `cx.monotonic_expander()` } impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { - MacroExpander { - cx: cx, - monotonic: monotonic, - single_step: false, - keep_macs: false, - } + MacroExpander { cx: cx, monotonic: monotonic } } fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { @@ -238,7 +231,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expansions.push(Vec::new()); } expansions[depth].push((mark.as_u32(), expansion)); - if !self.single_step { + if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } } @@ -417,7 +410,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.insert_macro(def.clone()); // If keep_macs is true, expands to a MacEager::items instead. - if self.keep_macs { + if self.cx.ecfg.keep_macs { Some(placeholders::reconstructed_macro_rules(&def, &path)) } else { Some(placeholders::macro_scope_placeholder()) @@ -726,6 +719,8 @@ pub struct ExpansionConfig<'feat> { pub recursion_limit: usize, pub trace_mac: bool, pub should_test: bool, // If false, strip `#[test]` nodes + pub single_step: bool, + pub keep_macs: bool, } macro_rules! feature_tests { @@ -749,6 +744,8 @@ impl<'feat> ExpansionConfig<'feat> { recursion_limit: 64, trace_mac: false, should_test: false, + single_step: false, + keep_macs: false, } } From 0ddb66c4c7216f43cccac8fa08b17abc98bd6c0b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 13 Sep 2016 05:21:54 +0000 Subject: [PATCH 744/768] Allow `IdentMacroExpander::expand` to access the ident macro invocation's attributes. --- src/libsyntax/ext/base.rs | 6 ++++-- src/libsyntax/ext/expand.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index fb4816d3847ed..ede17f8b00564 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -177,7 +177,8 @@ pub trait IdentMacroExpander { cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec ) + token_tree: Vec, + attrs: Vec) -> Box; } @@ -193,7 +194,8 @@ impl IdentMacroExpander for F cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec ) + token_tree: Vec, + _attrs: Vec) -> Box { (*self)(cx, sp, ident, token_tree) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index eab59d3c9309b..9ea3ec3cccf78 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -374,7 +374,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }); - kind.make_from(expander.expand(self.cx, span, ident, marked_tts)) + kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs)) } MacroRulesTT => { From 2abdc8805cf803ea53e96ca7ad44de3697fb7183 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 13 Sep 2016 06:25:02 +0000 Subject: [PATCH 745/768] Remove `MacroRulesTT`. --- src/librustc_plugin/registry.rs | 6 +---- src/libsyntax/ext/base.rs | 3 --- src/libsyntax/ext/expand.rs | 42 +---------------------------- src/libsyntax/ext/placeholders.rs | 13 ++++++--- src/libsyntax/ext/tt/macro_rules.rs | 39 ++++++++++++++++++++++++--- src/libsyntax_ext/lib.rs | 5 ++-- 6 files changed, 51 insertions(+), 57 deletions(-) diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 435196d956187..8f0cc2c3d750f 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -17,7 +17,7 @@ use rustc::mir::transform::MirMapPass; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator}; -use syntax::ext::base::{MacroExpanderFn, MacroRulesTT}; +use syntax::ext::base::MacroExpanderFn; use syntax::parse::token; use syntax::ast; use syntax::feature_gate::AttributeType; @@ -111,10 +111,6 @@ impl<'a> Registry<'a> { } MultiDecorator(ext) => MultiDecorator(ext), MultiModifier(ext) => MultiModifier(ext), - MacroRulesTT => { - self.sess.err("plugin tried to register a new MacroRulesTT"); - return; - } })); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ede17f8b00564..9d0d74138cd44 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -457,9 +457,6 @@ pub enum SyntaxExtension { /// the block. /// IdentTT(Box, Option, bool), - - /// Represents `macro_rules!` itself. - MacroRulesTT, } pub type NamedSyntaxExtension = (Name, SyntaxExtension); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9ea3ec3cccf78..4e87d8ee9dda2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -12,7 +12,7 @@ use ast::{Block, Crate, Ident, Mac_, PatKind}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; -use ext::placeholders::{self, placeholder, PlaceholderExpander}; +use ext::placeholders::{placeholder, PlaceholderExpander}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use syntax_pos::{self, Span, ExpnId}; @@ -377,46 +377,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs)) } - MacroRulesTT => { - if ident.name == keywords::Invalid.name() { - self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", extname)); - return kind.dummy(span); - }; - - self.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: None, - // `macro_rules!` doesn't directly allow unstable - // (this is orthogonal to whether the macro it creates allows it) - allow_internal_unstable: false, - } - }); - - let def = ast::MacroDef { - ident: ident, - id: ast::DUMMY_NODE_ID, - span: span, - imported_from: None, - use_locally: true, - body: marked_tts, - export: attr::contains_name(&attrs, "macro_export"), - allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), - attrs: attrs, - }; - - self.cx.insert_macro(def.clone()); - - // If keep_macs is true, expands to a MacEager::items instead. - if self.cx.ecfg.keep_macs { - Some(placeholders::reconstructed_macro_rules(&def, &path)) - } else { - Some(placeholders::macro_scope_placeholder()) - } - } - MultiDecorator(..) | MultiModifier(..) => { self.cx.span_err(path.span, &format!("`{}` can only be used in attributes", extname)); diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 47f366a88768e..0ede6dd98e5b8 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -13,7 +13,7 @@ use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; use fold::*; -use parse::token::keywords; +use parse::token::{intern, keywords}; use ptr::P; use util::move_map::MoveMap; use util::small_vector::SmallVector; @@ -214,7 +214,7 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } } -pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion { +pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion { Expansion::Items(SmallVector::one(P(ast::Item { ident: def.ident, attrs: def.attrs.clone(), @@ -222,7 +222,14 @@ pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expan node: ast::ItemKind::Mac(ast::Mac { span: def.span, node: ast::Mac_ { - path: path.clone(), + path: ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ast::PathSegment { + identifier: ast::Ident::with_empty_ctxt(intern("macro_rules")), + parameters: ast::PathParameters::none(), + }], + }, tts: def.body.clone(), } }), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 51ef45b97be6f..da82c9ffab1cb 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast; +use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; -use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; -use ext::base::{NormalTT, TTMacroExpander}; +use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension}; +use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander}; +use ext::placeholders; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::parse; @@ -242,6 +243,38 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]); } +pub struct MacroRulesExpander; +impl IdentMacroExpander for MacroRulesExpander { + fn expand(&self, + cx: &mut ExtCtxt, + span: Span, + ident: ast::Ident, + tts: Vec, + attrs: Vec) + -> Box { + let def = ast::MacroDef { + ident: ident, + id: ast::DUMMY_NODE_ID, + span: span, + imported_from: None, + use_locally: true, + body: tts, + export: attr::contains_name(&attrs, "macro_export"), + allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), + attrs: attrs, + }; + + cx.insert_macro(def.clone()); + + // If keep_macs is true, expands to a MacEager::items instead. + if cx.ecfg.keep_macs { + MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items()) + } else { + MacEager::items(placeholders::macro_scope_placeholder().make_items()) + } + } +} + // Note that macro-by-example's input is also matched against a token tree: // $( $lhs:tt => $rhs:tt );+ // diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 3a6212e5445ce..e0c028195bab0 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -50,8 +50,9 @@ pub mod deriving; use std::rc::Rc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier}; +use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier}; use syntax::ext::hygiene::Mark; +use syntax::ext::tt::macro_rules::MacroRulesExpander; use syntax::parse::token::intern; pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) { @@ -59,7 +60,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quot resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext)); }; - register("macro_rules", MacroRulesTT); + register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false)); macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( From f9a08cc9821a442380d15096e3d245c32617eea7 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 13 Sep 2016 08:39:11 +0000 Subject: [PATCH 746/768] Remove irrelevant test. --- .../auxiliary/macro_crate_MacroRulesTT.rs | 26 ------------------- .../plugin-MacroRulesTT.rs | 18 ------------- 2 files changed, 44 deletions(-) delete mode 100644 src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs delete mode 100644 src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs deleted file mode 100644 index 9e693fcc56440..0000000000000 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs +++ /dev/null @@ -1,26 +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. - -// force-host - -#![feature(plugin_registrar, rustc_private)] - -extern crate syntax; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::parse::token; -use syntax::ext::base::MacroRulesTT; -use rustc_plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(token::intern("bogus"), MacroRulesTT); -} diff --git a/src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs b/src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs deleted file mode 100644 index e13ddd13f5d99..0000000000000 --- a/src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs +++ /dev/null @@ -1,18 +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. - -// aux-build:macro_crate_MacroRulesTT.rs -// ignore-stage1 -// error-pattern: plugin tried to register a new MacroRulesTT - -#![feature(plugin)] -#![plugin(macro_crate_MacroRulesTT)] - -fn main() { } From 3f7931017463459768e4281f6f4cea1d75e2e1fe Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 16 Sep 2016 01:48:27 +0300 Subject: [PATCH 747/768] Try to support py3 with rustbuild better --- src/bootstrap/bootstrap.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 17a7c9ca66a26..14a985e93ce01 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -269,6 +269,7 @@ def run(self, args, env): sys.exit(ret) def build_triple(self): + default_encoding = sys.getdefaultencoding() config = self.get_toml('build') if config: return config @@ -276,8 +277,8 @@ def build_triple(self): if config: return config try: - ostype = subprocess.check_output(['uname', '-s']).strip() - cputype = subprocess.check_output(['uname', '-m']).strip() + ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding) + cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding) except (subprocess.CalledProcessError, WindowsError): if sys.platform == 'win32': return 'x86_64-pc-windows-msvc' @@ -289,7 +290,8 @@ def build_triple(self): # Darwin's `uname -s` lies and always returns i386. We have to use # sysctl instead. if ostype == 'Darwin' and cputype == 'i686': - sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64']) + args = ['sysctl', 'hw.optional.x86_64'] + sysctl = subprocess.check_output(args).decode(default_encoding) if ': 1' in sysctl: cputype = 'x86_64' From 63ded0518a35ac9bd259bb961225eae7b4fa737c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 15 Sep 2016 10:59:11 +1000 Subject: [PATCH 748/768] Overhaul char_lit(). This commit does the following. - Removes parsing support for '\X12', '\u123456' and '\U12345678' char literals. These are no longer valid Rust and rejected by the lexer. (This strange-sounding situation occurs because the parser rescans char literals to compute their value.) - Rearranges the function so that all the escaped values are handled in a single `match`, and changes the error-handling to use vanilla assert!() and unwrap(). --- src/libsyntax/parse/mod.rs | 71 +++++++++++++++----------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index a1eceb6921c6d..5aa0efdec11a2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -286,52 +286,37 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, pub fn char_lit(lit: &str) -> (char, isize) { use std::char; - let mut chars = lit.chars(); - match (chars.next(), chars.next()) { - (Some(c), None) if c != '\\' => return (c, 1), - (Some('\\'), Some(c)) => match c { - '"' => return ('"', 2), - 'n' => return ('\n', 2), - 'r' => return ('\r', 2), - 't' => return ('\t', 2), - '\\' => return ('\\', 2), - '\'' => return ('\'', 2), - '0' => return ('\0', 2), - _ => {} - }, - _ => panic!("lexer accepted invalid char escape `{}`", lit) - }; - - fn esc(len: usize, lit: &str) -> Option<(char, isize)> { - u32::from_str_radix(&lit[2..len], 16).ok() - .and_then(char::from_u32) - .map(|x| (x, len as isize)) + // Handle non-escaped chars first. + if lit.as_bytes()[0] != b'\\' { + // If the first byte isn't '\\' it might part of a multi-byte char, so + // get the char with chars(). + let c = lit.chars().next().unwrap(); + return (c, 1); } - let unicode_escape = || -> Option<(char, isize)> { - if lit.as_bytes()[2] == b'{' { - let idx = lit.find('}').unwrap_or_else(|| { - panic!("lexer should have rejected a bad character escape {}", lit) - }); - - let subslice = &lit[3..idx]; - u32::from_str_radix(subslice, 16).ok() - .and_then(char::from_u32) - .map(|x| (x, subslice.chars().count() as isize + 4)) - } else { - esc(6, lit) + // Handle escaped chars. + match lit.as_bytes()[1] as char { + '"' => ('"', 2), + 'n' => ('\n', 2), + 'r' => ('\r', 2), + 't' => ('\t', 2), + '\\' => ('\\', 2), + '\'' => ('\'', 2), + '0' => ('\0', 2), + 'x' => { + let v = u32::from_str_radix(&lit[2..4], 16).unwrap(); + let c = char::from_u32(v).unwrap(); + (c, 4) } - }; - - // Unicode escapes - return match lit.as_bytes()[1] as char { - 'x' | 'X' => esc(4, lit), - 'u' => unicode_escape(), - 'U' => esc(10, lit), - _ => None, - }.unwrap_or_else(|| { - panic!("lexer should have rejected a bad character escape {}", lit) - }) + 'u' => { + assert!(lit.as_bytes()[2] == b'{'); + let idx = lit.find('}').unwrap(); + let v = u32::from_str_radix(&lit[3..idx], 16).unwrap(); + let c = char::from_u32(v).unwrap(); + (c, (idx + 1) as isize) + } + _ => panic!("lexer should have rejected a bad character escape {}", lit) + } } /// Parse a string representing a string literal into its final form. Does From bfa6fdc72c5d650e68e09eac6025bd7d577bb11e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 20:39:58 -0400 Subject: [PATCH 749/768] trans: Allow base::internalize_symbols() to internalize #[no_mangle] symbols --- src/librustc_trans/base.rs | 19 ++----------------- src/librustc_trans/partitioning.rs | 15 ++++++++------- src/librustc_trans/trans_item.rs | 6 +++++- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index fcfe53d0c8512..2c3880d21ad1a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1421,21 +1421,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, .iter() .cloned() .filter(|trans_item|{ - let def_id = match *trans_item { - TransItem::DropGlue(..) => { - return false - }, - TransItem::Fn(ref instance) => { - instance.def - } - TransItem::Static(node_id) => { - tcx.map.local_def_id(node_id) - } - }; - - trans_item.explicit_linkage(tcx).is_some() || - attr::contains_extern_indicator(tcx.sess.diagnostic(), - &tcx.get_attrs(def_id)) + trans_item.explicit_linkage(tcx).is_some() }) .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) .collect(); @@ -1900,8 +1886,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a partitioning::partition(scx, items.iter().cloned(), strategy, - &inlining_map, - scx.reachable()) + &inlining_map) }); assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 798e883c9557c..65615e6b6440c 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -133,7 +133,7 @@ use symbol_map::SymbolMap; use syntax::ast::NodeId; use syntax::parse::token::{self, InternedString}; use trans_item::TransItem; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeSet}; +use util::nodemap::{FnvHashMap, FnvHashSet}; pub enum PartitioningStrategy { /// Generate one codegen unit per source-level module. @@ -254,8 +254,7 @@ const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_items: I, strategy: PartitioningStrategy, - inlining_map: &InliningMap<'tcx>, - reachable: &NodeSet) + inlining_map: &InliningMap<'tcx>) -> Vec> where I: Iterator> { @@ -265,8 +264,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. let mut initial_partitioning = place_root_translation_items(scx, - trans_items, - reachable); + trans_items); debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); @@ -304,8 +302,7 @@ struct PreInliningPartitioning<'tcx> { struct PostInliningPartitioning<'tcx>(Vec>); fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, - trans_items: I, - _reachable: &NodeSet) + trans_items: I) -> PreInliningPartitioning<'tcx> where I: Iterator> { @@ -344,6 +341,10 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, // This is a non-generic functions, we always // make it visible externally on the chance that // it might be used in another codegen unit. + // Later on base::internalize_symbols() will + // assign "internal" linkage to those symbols + // that are not referenced from other codegen + // units (and are not publicly visible). llvm::ExternalLinkage } else { // In the current setup, generic functions cannot diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index bde393b77e167..5c7cbbbd88d46 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -251,7 +251,11 @@ impl<'a, 'tcx> TransItem<'tcx> { /// True if the translation item should only be translated to LLVM IR if /// it is referenced somewhere (like inline functions, for example). - pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt) -> bool { + pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + if self.explicit_linkage(tcx).is_some() { + return false; + } + match *self { TransItem::Fn(ref instance) => { !instance.def.is_local() || From 102ee5e70a3da9fa654c1515b492d0f2387e1f97 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 15 Sep 2016 19:47:04 -0600 Subject: [PATCH 750/768] Add example in AsMut trait documentation --- src/libcore/convert.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 5191cd7601064..5f16a4f2435f8 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -92,6 +92,22 @@ pub trait AsRef { /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Examples +/// +/// [`Box`] implements `AsMut`: +/// +/// [`Box`]: ../../std/boxed/struct.Box.html +/// +/// ``` +/// fn add_one>(num: &mut T) { +/// *num.as_mut() += 1; +/// } +/// +/// let mut boxed_num = Box::new(0); +/// add_one(&mut boxed_num); +/// assert_eq!(*boxed_num, 1); +/// ``` +/// /// # Generic Impls /// /// - `AsMut` auto-dereferences if the inner type is a reference or a mutable From cf976fe2cd92a7a4923e6a0934c8f15333b6589d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 22:09:49 -0400 Subject: [PATCH 751/768] Adapt codegen-unit test cases to new behaviour --- src/test/codegen-units/partitioning/local-inlining.rs | 2 +- .../codegen-units/partitioning/local-transitive-inlining.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index 5eb1cbc2199f7..84ca8b1b0f641 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -19,7 +19,7 @@ mod inline { // Important: This function should show up in all codegen units where it is inlined - //~ TRANS_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-inline[External] local_inlining-user1[Available] local_inlining-user2[Available] + //~ TRANS_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-user1[Internal] local_inlining-user2[Internal] #[inline(always)] pub fn inlined_function() { diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 28c4698eabd1f..7e37f9ccaa5a9 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -18,7 +18,7 @@ mod inline { - //~ TRANS_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-inline[External] local_transitive_inlining-direct_user[Available] local_transitive_inlining-indirect_user[Available] + //~ TRANS_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn inlined_function() { @@ -29,7 +29,7 @@ mod inline { mod direct_user { use super::inline; - //~ TRANS_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-direct_user[External] local_transitive_inlining-indirect_user[Available] + //~ TRANS_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn foo() { inline::inlined_function(); From 68e8624d05bc9b291fc3d945aaf5c1cb24bf015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Sep 2016 18:40:31 -0700 Subject: [PATCH 752/768] Specify when type parameter shadows primitive type When a type parameter shadows a primitive type, the error message was non obvious. For example, given the file `file.rs`: ```rust trait Parser { fn parse(text: &str) -> Option; } impl Parser for bool { fn parse(text: &str) -> Option { Some(true) } } fn main() { println!("{}", bool::parse("ok").unwrap_or(false)); } ``` The output was: ```bash % rustc file.rs error[E0308]: mismatched types --> file.rs:7:14 | 7 | Some(true) | ^^^^ expected type parameter, found bool | = note: expected type `bool` = note: found type `bool` error: aborting due to previous error ``` We now show extra information about the type: ```bash % rustc file.rs error[E0308]: mismatched types --> file.rs:7:14 | 7 | Some(true) | ^^^^ expected type parameter, found bool | = note: expected type `bool` (type parameter) = note: found type `bool` (bool) error: aborting due to previous error ``` Fixes #35030 --- src/librustc/infer/error_reporting.rs | 13 +++++++++- src/librustc/ty/error.rs | 2 +- src/librustc_errors/lib.rs | 17 ++++++++++--- src/test/ui/mismatched_types/issue-35030.rs | 25 +++++++++++++++++++ .../ui/mismatched_types/issue-35030.stderr | 11 ++++++++ 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/mismatched_types/issue-35030.rs create mode 100644 src/test/ui/mismatched_types/issue-35030.stderr diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index b8a3bdfcf2573..2792968d427aa 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -547,7 +547,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; if !is_simple_error { - diag.note_expected_found(&"type", &expected, &found); + if expected == found { + if let &TypeError::Sorts(ref values) = terr { + diag.note_expected_found_extra( + &"type", &expected, &found, + &format!(" ({})", values.expected.sort_string(self.tcx)), + &format!(" ({})", values.found.sort_string(self.tcx))); + } else { + diag.note_expected_found(&"type", &expected, &found); + } + } else { + diag.note_expected_found(&"type", &expected, &found); + } } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index d820fddea3907..001f47af68c3b 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -210,7 +210,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { - fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { + pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { match self.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d82d7dbe70f92..d2f3eea85f228 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -273,10 +273,21 @@ impl<'a> DiagnosticBuilder<'a> { expected: &fmt::Display, found: &fmt::Display) -> &mut DiagnosticBuilder<'a> + { + self.note_expected_found_extra(label, expected, found, &"", &"") + } + + pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut DiagnosticBuilder<'a> { // For now, just attach these as notes - self.note(&format!("expected {} `{}`", label, expected)); - self.note(&format!(" found {} `{}`", label, found)); + self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); + self.note(&format!(" found {} `{}`{}", label, found, found_extra)); self } @@ -764,4 +775,4 @@ pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where Some(t) => t, None => diag.bug(&msg()), } -} \ No newline at end of file +} diff --git a/src/test/ui/mismatched_types/issue-35030.rs b/src/test/ui/mismatched_types/issue-35030.rs new file mode 100644 index 0000000000000..006074ead13bd --- /dev/null +++ b/src/test/ui/mismatched_types/issue-35030.rs @@ -0,0 +1,25 @@ +// 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. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +trait Parser { + fn parse(text: &str) -> Option; +} + +impl Parser for bool { + fn parse(text: &str) -> Option { + Some(true) + } +} + +fn main() { + println!("{}", bool::parse("ok").unwrap_or(false)); +} diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr new file mode 100644 index 0000000000000..aa017297a4e15 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-35030.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-35030.rs:19:14 + | +19 | Some(true) + | ^^^^ expected type parameter, found bool + | + = note: expected type `bool` (type parameter) + = note: found type `bool` (bool) + +error: aborting due to previous error + From 8075d546069e9fc850beb846747c43e9ee55e175 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Sep 2016 15:46:40 +1000 Subject: [PATCH 753/768] Optimize the parser's last token handling. The parser currently makes a heap copy of the last token in four cases: identifiers, paths, doc comments, and commas. The identifier and interpolation cases are unused, and for doc comments and commas we only need to record their presence, not their value. This commit consolidates the last token handling and avoids the unnecessary copies by replacing `last_token`, `last_token_eof`, and `last_token_interpolated` with a new field `last_token_kind`. This simplifies the parser slightly and speeds up parsing on some files by 3--4%. --- src/libsyntax/parse/parser.rs | 82 +++++++++++++++++------------------ 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded59..0696576c93e38 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -237,6 +237,15 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) lhs } +#[derive(PartialEq)] +enum LastTokenKind { + DocComment, + Comma, + Interpolated, + Eof, + Other, +} + /* ident is handled by common.rs */ pub struct Parser<'a> { @@ -248,10 +257,8 @@ pub struct Parser<'a> { /// the span of the prior token: pub last_span: Span, pub cfg: CrateConfig, - /// the previous token or None (only stashed sometimes). - pub last_token: Option>, - last_token_interpolated: bool, - last_token_eof: bool, + /// the previous token kind + last_token_kind: LastTokenKind, pub buffer: [TokenAndSpan; 4], pub buffer_start: isize, pub buffer_end: isize, @@ -362,9 +369,7 @@ impl<'a> Parser<'a> { token: tok0.tok, span: span, last_span: span, - last_token: None, - last_token_interpolated: false, - last_token_eof: false, + last_token_kind: LastTokenKind::Other, buffer: [ placeholder.clone(), placeholder.clone(), @@ -500,7 +505,7 @@ impl<'a> Parser<'a> { expr: PResult<'a, P>) -> PResult<'a, (Span, P)> { expr.map(|e| { - if self.last_token_interpolated { + if self.last_token_kind == LastTokenKind::Interpolated { (self.last_span, e) } else { (e.span, e) @@ -520,21 +525,19 @@ impl<'a> Parser<'a> { self.bug("ident interpolation not converted to real token"); } _ => { - let last_token = self.last_token.clone().map(|t| *t); - Err(match last_token { - Some(token::DocComment(_)) => self.span_fatal_help(self.last_span, + Err(if self.last_token_kind == LastTokenKind::DocComment { + self.span_fatal_help(self.last_span, "found a documentation comment that doesn't document anything", "doc comments must come before what they document, maybe a comment was \ - intended with `//`?"), - _ => { + intended with `//`?") + } else { let mut err = self.fatal(&format!("expected identifier, found `{}`", self.this_token_to_string())); if self.token == token::Underscore { err.note("`_` is a wildcard pattern, not an identifier"); } err - } - }) + }) } } } @@ -923,26 +926,22 @@ impl<'a> Parser<'a> { /// Advance the parser by one token pub fn bump(&mut self) { - if self.last_token_eof { + if self.last_token_kind == LastTokenKind::Eof { // Bumping after EOF is a bad sign, usually an infinite loop. self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - if self.token == token::Eof { - self.last_token_eof = true; - } - self.last_span = self.span; - // Stash token for error recovery (sometimes; clone is not necessarily cheap). - self.last_token = if self.token.is_ident() || - self.token.is_path() || - self.token.is_doc_comment() || - self.token == token::Comma { - Some(Box::new(self.token.clone())) - } else { - None + + // Record last token kind for possible error recovery. + self.last_token_kind = match self.token { + token::DocComment(..) => LastTokenKind::DocComment, + token::Comma => LastTokenKind::Comma, + token::Interpolated(..) => LastTokenKind::Interpolated, + token::Eof => LastTokenKind::Eof, + _ => LastTokenKind::Other, }; - self.last_token_interpolated = self.token.is_interpolated(); + let next = if self.buffer_start == self.buffer_end { self.reader.real_token() } else { @@ -979,11 +978,10 @@ impl<'a> Parser<'a> { lo: BytePos, hi: BytePos) { self.last_span = mk_sp(self.span.lo, lo); - // It would be incorrect to just stash current token, but fortunately - // for tokens currently using `bump_with`, last_token will be of no - // use anyway. - self.last_token = None; - self.last_token_interpolated = false; + // It would be incorrect to record the kind of the current token, but + // fortunately for tokens currently using `bump_with`, the + // last_token_kind will be of no use anyway. + self.last_token_kind = LastTokenKind::Other; self.span = mk_sp(lo, hi); self.token = next; self.expected_tokens.clear(); @@ -2974,7 +2972,7 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { - let lhs_span = if self.last_token_interpolated { + let lhs_span = if self.last_token_kind == LastTokenKind::Interpolated { self.last_span } else { lhs.span @@ -4036,13 +4034,13 @@ impl<'a> Parser<'a> { None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { - let last_token = s.last_token.clone().map(|t| *t); - match last_token { - Some(token::DocComment(_)) => s.span_err_help(s.last_span, + if s.last_token_kind == LastTokenKind::DocComment { + s.span_err_help(s.last_span, "found a documentation comment that doesn't document anything", "doc comments must come before what they document, maybe a \ - comment was intended with `//`?"), - _ => s.span_err(s.span, "expected statement after outer attribute"), + comment was intended with `//`?"); + } else { + s.span_err(s.span, "expected statement after outer attribute"); } } }; @@ -4332,9 +4330,7 @@ impl<'a> Parser<'a> { let missing_comma = !lifetimes.is_empty() && !self.token.is_like_gt() && - self.last_token - .as_ref().map_or(true, - |x| &**x != &token::Comma); + self.last_token_kind != LastTokenKind::Comma; if missing_comma { From eb19cd65756cd285c81410e627752a75a41e3f0e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 11 Jun 2016 23:47:28 +0300 Subject: [PATCH 754/768] groundwork refactoring of `gather_moves` --- src/librustc/mir/repr.rs | 7 +- src/librustc/mir/visit.rs | 3 - .../borrowck/mir/dataflow/impls.rs | 47 +- .../borrowck/mir/dataflow/sanity_check.rs | 24 +- .../borrowck/mir/elaborate_drops.rs | 161 ++-- .../borrowck/mir/gather_moves.rs | 875 +++++++----------- src/librustc_borrowck/borrowck/mir/mod.rs | 70 +- src/librustc_trans/mir/analyze.rs | 1 - 8 files changed, 480 insertions(+), 708 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index a2abaa5e12f55..53b6ccdbd530a 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1243,7 +1243,7 @@ impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { type Iter = IntoIter; } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct Location { /// the location is within this block pub block: BasicBlock, @@ -1253,3 +1253,8 @@ pub struct Location { pub statement_index: usize, } +impl fmt::Debug for Location { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}[{}]", self.block, self.statement_index) + } +} diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index c2d0b2c686e77..16e0b376f4b53 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -774,9 +774,6 @@ pub enum LvalueContext<'tcx> { // Being borrowed Borrow { region: &'tcx Region, kind: BorrowKind }, - // Being sliced -- this should be same as being borrowed, probably - Slice { from_start: usize, from_end: usize }, - // Used as base for another lvalue, e.g. `x` in `x.y` Projection, diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index c46daf9c22537..8ac59c60396f6 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -17,7 +17,7 @@ use super::super::MoveDataParamEnv; use super::super::DropFlagState; use super::super::drop_flag_effects_for_function_entry; use super::super::drop_flag_effects_for_location; -use super::super::on_all_children_bits; +use super::super::on_lookup_result_bits; use super::{BitDenotation, BlockSets, DataflowOperator}; @@ -277,10 +277,9 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, - move_path_index, - |mpi| { in_out.add(&mpi); }); + on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, + ctxt.move_data.rev_lookup.find(dest_lval), + |mpi| { in_out.add(&mpi); }); } } @@ -338,11 +337,10 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set - // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, - move_path_index, - |mpi| { in_out.remove(&mpi); }); + // the bits for that dest_lval to 0 (initialized). + on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, + ctxt.move_data.rev_lookup.find(dest_lval), + |mpi| { in_out.remove(&mpi); }); } } @@ -400,10 +398,9 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, - move_path_index, - |mpi| { in_out.add(&mpi); }); + on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, + ctxt.move_data.rev_lookup.find(dest_lval), + |mpi| { in_out.add(&mpi); }); } } @@ -448,11 +445,10 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { // assigning into this `lvalue` kills all // MoveOuts from it, and *also* all MoveOuts // for children and associated fragment sets. - let move_path_index = rev_lookup.find(lvalue); - on_all_children_bits(tcx, + on_lookup_result_bits(tcx, mir, move_data, - move_path_index, + rev_lookup.find(lvalue), |mpi| for moi in &path_map[mpi] { assert!(moi.index() < bits_per_block); sets.kill_set.add(&moi); @@ -489,18 +485,17 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { let move_data = &ctxt.move_data; - let move_path_index = move_data.rev_lookup.find(dest_lval); let bits_per_block = self.bits_per_block(ctxt); let path_map = &move_data.path_map; - on_all_children_bits(self.tcx, - self.mir, - move_data, - move_path_index, - |mpi| for moi in &path_map[mpi] { - assert!(moi.index() < bits_per_block); - in_out.remove(&moi); - }); + on_lookup_result_bits(self.tcx, + self.mir, + move_data, + move_data.rev_lookup.find(dest_lval), + |mpi| for moi in &path_map[mpi] { + assert!(moi.index() < bits_per_block); + in_out.remove(&moi); + }); } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 9a4865755e799..88f6d5fef562d 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -16,7 +16,7 @@ use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; use rustc_data_structures::indexed_vec::Idx; -use super::super::gather_moves::{MovePathIndex}; +use super::super::gather_moves::{MovePathIndex, LookupResult}; use super::super::MoveDataParamEnv; use super::BitDenotation; use super::DataflowResults; @@ -116,20 +116,26 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, repr::BorrowKind::Shared, ref peeking_at_lval) = *rvalue { // Okay, our search is over. - let peek_mpi = move_data.rev_lookup.find(peeking_at_lval); - let bit_state = sets.on_entry.contains(&peek_mpi); - debug!("rustc_peek({:?} = &{:?}) bit_state: {}", - lvalue, peeking_at_lval, bit_state); - if !bit_state { - tcx.sess.span_err(span, &format!("rustc_peek: bit not set")); + match move_data.rev_lookup.find(peeking_at_lval) { + LookupResult::Exact(peek_mpi) => { + let bit_state = sets.on_entry.contains(&peek_mpi); + debug!("rustc_peek({:?} = &{:?}) bit_state: {}", + lvalue, peeking_at_lval, bit_state); + if !bit_state { + tcx.sess.span_err(span, "rustc_peek: bit not set"); + } + } + LookupResult::Parent(..) => { + tcx.sess.span_err(span, "rustc_peek: argument untracked"); + } } return; } else { // Our search should have been over, but the input // does not match expectations of `rustc_peek` for // this sanity_check. - let msg = &format!("rustc_peek: argument expression \ - must be immediate borrow of form `&expr`"); + let msg = "rustc_peek: argument expression \ + must be immediate borrow of form `&expr`"; tcx.sess.span_err(span, msg); } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 71274b7e0218a..96702b209a1f5 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -9,10 +9,11 @@ // except according to those terms. use indexed_set::IdxSetBuf; -use super::gather_moves::{MoveData, MovePathIndex, MovePathContent}; +use super::gather_moves::{MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; use super::{drop_flag_effects_for_location, on_all_children_bits}; +use super::on_lookup_result_bits; use super::{DropFlagState, MoveDataParamEnv}; use super::patch::MirPatch; use rustc::ty::{self, Ty, TyCtxt}; @@ -42,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { } let id = src.item_id(); let param_env = ty::ParameterEnvironment::for_item(tcx, id); - let move_data = MoveData::gather_moves(mir, tcx); + let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let elaborate_patch = { let mir = &*mir; let env = MoveDataParamEnv { @@ -184,31 +185,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn path_needs_drop(&self, path: MovePathIndex) -> bool { - match self.move_data().move_paths[path].content { - MovePathContent::Lvalue(ref lvalue) => { - let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); + let lvalue = &self.move_data().move_paths[path].lvalue; + let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); + debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); - self.tcx.type_needs_drop_given_env(ty, self.param_env()) - } - _ => false - } - } - - /// Returns whether this lvalue is tracked by drop elaboration. This - /// includes all lvalues, except these (1.) behind references or arrays, - /// or (2.) behind ADT's with a Drop impl. - fn lvalue_is_tracked(&self, lv: &Lvalue<'tcx>) -> bool - { - // `lvalue_contents_drop_state_cannot_differ` only compares - // the `lv` to its immediate contents, while this recursively - // follows parent chain formed by `base` of each projection. - if let &Lvalue::Projection(ref data) = lv { - !super::lvalue_contents_drop_state_cannot_differ(self.tcx, self.mir, &data.base) && - self.lvalue_is_tracked(&data.base) - } else { - true - } + self.tcx.type_needs_drop_given_env(ty, self.param_env()) } fn collect_drop_flags(&mut self) @@ -221,19 +202,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { _ => continue }; - if !self.lvalue_is_tracked(location) { - continue - } - let init_data = self.initialization_data_at(Location { block: bb, statement_index: data.statements.len() }); let path = self.move_data().rev_lookup.find(location); - debug!("collect_drop_flags: {:?}, lv {:?} (index {:?})", + debug!("collect_drop_flags: {:?}, lv {:?} ({:?})", bb, location, path); + let path = match path { + LookupResult::Exact(e) => e, + LookupResult::Parent(None) => continue, + LookupResult::Parent(Some(parent)) => { + let (_maybe_live, maybe_dead) = init_data.state(parent); + if maybe_dead { + span_bug!(terminator.source_info.span, + "drop of untracked, uninitialized value {:?}, lv {:?} ({:?})", + bb, location, path); + } + continue + } + }; + on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { if self.path_needs_drop(child) { let (maybe_live, maybe_dead) = init_data.state(child); @@ -257,20 +248,27 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match terminator.kind { TerminatorKind::Drop { ref location, target, unwind } => { let init_data = self.initialization_data_at(loc); - let path = self.move_data().rev_lookup.find(location); - self.elaborate_drop(&DropCtxt { - source_info: terminator.source_info, - is_cleanup: data.is_cleanup, - init_data: &init_data, - lvalue: location, - path: path, - succ: target, - unwind: if data.is_cleanup { - None - } else { - Some(Option::unwrap_or(unwind, resume_block)) + match self.move_data().rev_lookup.find(location) { + LookupResult::Exact(path) => { + self.elaborate_drop(&DropCtxt { + source_info: terminator.source_info, + is_cleanup: data.is_cleanup, + init_data: &init_data, + lvalue: location, + path: path, + succ: target, + unwind: if data.is_cleanup { + None + } else { + Some(Option::unwrap_or(unwind, resume_block)) + } + }, bb); } - }, bb); + LookupResult::Parent(..) => { + span_bug!(terminator.source_info.span, + "drop of untracked value {:?}", bb); + } + } } TerminatorKind::DropAndReplace { ref location, ref value, target, unwind } => @@ -336,35 +334,37 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { is_cleanup: data.is_cleanup, }); - if !self.lvalue_is_tracked(location) { - // drop and replace behind a pointer/array/whatever. The location - // must be initialized. - debug!("elaborate_drop_and_replace({:?}) - untracked", terminator); - self.patch.patch_terminator(bb, TerminatorKind::Drop { - location: location.clone(), - target: target, - unwind: Some(unwind) - }); - } else { - debug!("elaborate_drop_and_replace({:?}) - tracked", terminator); - let init_data = self.initialization_data_at(loc); - let path = self.move_data().rev_lookup.find(location); - - self.elaborate_drop(&DropCtxt { - source_info: terminator.source_info, - is_cleanup: data.is_cleanup, - init_data: &init_data, - lvalue: location, - path: path, - succ: target, - unwind: Some(unwind) - }, bb); - on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - self.set_drop_flag(Location { block: target, statement_index: 0 }, - child, DropFlagState::Present); - self.set_drop_flag(Location { block: unwind, statement_index: 0 }, - child, DropFlagState::Present); - }); + match self.move_data().rev_lookup.find(location) { + LookupResult::Exact(path) => { + debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); + let init_data = self.initialization_data_at(loc); + + self.elaborate_drop(&DropCtxt { + source_info: terminator.source_info, + is_cleanup: data.is_cleanup, + init_data: &init_data, + lvalue: location, + path: path, + succ: target, + unwind: Some(unwind) + }, bb); + on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { + self.set_drop_flag(Location { block: target, statement_index: 0 }, + child, DropFlagState::Present); + self.set_drop_flag(Location { block: unwind, statement_index: 0 }, + child, DropFlagState::Present); + }); + } + LookupResult::Parent(parent) => { + // drop and replace behind a pointer/array/whatever. The location + // must be initialized. + debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent); + self.patch.patch_terminator(bb, TerminatorKind::Drop { + location: location.clone(), + target: target, + unwind: Some(unwind) + }); + } } } @@ -446,10 +446,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { substs: &'tcx Substs<'tcx>) -> Vec<(Lvalue<'tcx>, Option)> { - let move_paths = &self.move_data().move_paths; variant.fields.iter().enumerate().map(|(i, f)| { let subpath = - super::move_path_children_matching(move_paths, variant_path, |p| { + super::move_path_children_matching(self.move_data(), variant_path, |p| { match p { &Projection { elem: ProjectionElem::Field(idx, _), .. @@ -580,7 +579,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let fields = tys.iter().enumerate().map(|(i, &ty)| { (c.lvalue.clone().field(Field::new(i), ty), super::move_path_children_matching( - &self.move_data().move_paths, c.path, |proj| match proj { + self.move_data(), c.path, |proj| match proj { &Projection { elem: ProjectionElem::Field(f, _), .. } => f.index() == i, @@ -598,7 +597,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("open_drop_for_box({:?}, {:?})", c, ty); let interior_path = super::move_path_children_matching( - &self.move_data().move_paths, c.path, |proj| match proj { + self.move_data(), c.path, |proj| match proj { &Projection { elem: ProjectionElem::Deref, .. } => true, _ => false }).unwrap(); @@ -625,10 +624,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { variant_index: usize) -> BasicBlock { - let move_paths = &self.move_data().move_paths; - let subpath = super::move_path_children_matching( - move_paths, c.path, |proj| match proj { + self.move_data(), c.path, |proj| match proj { &Projection { elem: ProjectionElem::Downcast(_, idx), .. } => idx == variant_index, @@ -942,7 +939,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: tgt, statement_index: 0 }; let path = self.move_data().rev_lookup.find(lv); - on_all_children_bits( + on_lookup_result_bits( self.tcx, self.mir, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); @@ -1011,7 +1008,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: bb, statement_index: data.statements.len() }; let path = self.move_data().rev_lookup.find(lv); - on_all_children_bits( + on_lookup_result_bits( self.tcx, self.mir, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 01bf8ed0e4b57..2713a3c371db9 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -9,16 +9,18 @@ // except according to those terms. -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc::util::common::ErrorReported; +use rustc_data_structures::indexed_vec::{IndexVec}; + +use syntax::codemap::DUMMY_SP; -use std::cell::{Cell}; use std::collections::hash_map::Entry; use std::fmt; -use std::iter; -use std::ops::Index; +use std::mem; +use std::ops::{Index, IndexMut}; use super::abs_domain::{AbstractElem, Lift}; @@ -28,17 +30,15 @@ use super::abs_domain::{AbstractElem, Lift}; // ensure that other code does not accidentally access `index.0` // (which is likely to yield a subtle off-by-one error). mod indexes { + use std::fmt; use core::nonzero::NonZero; use rustc_data_structures::indexed_vec::Idx; macro_rules! new_index { - ($Index:ident) => { - #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] + ($Index:ident, $debug_name:expr) => { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct $Index(NonZero); - impl $Index { - } - impl Idx for $Index { fn new(idx: usize) -> Self { unsafe { $Index(NonZero::new(idx + 1)) } @@ -47,14 +47,20 @@ mod indexes { *self.0 - 1 } } + + impl fmt::Debug for $Index { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}{}", $debug_name, self.index()) + } + } } } /// Index into MovePathData.move_paths - new_index!(MovePathIndex); + new_index!(MovePathIndex, "mp"); /// Index into MoveData.moves. - new_index!(MoveOutIndex); + new_index!(MoveOutIndex, "mo"); } pub use self::indexes::MovePathIndex; @@ -62,7 +68,7 @@ pub use self::indexes::MoveOutIndex; impl self::indexes::MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { - move_data.moves[self.index()].path + move_data.moves[*self].path } } @@ -83,40 +89,7 @@ pub struct MovePath<'tcx> { pub next_sibling: Option, pub first_child: Option, pub parent: Option, - pub content: MovePathContent<'tcx>, -} - -/// MovePaths usually represent a single l-value. The exceptions are -/// forms that arise due to erroneous input code: static data holds -/// l-values that we cannot actually move out of. Therefore we map -/// statics to a special marker value (`MovePathContent::Static`) -/// representing an invalid origin. -#[derive(Clone, Debug)] -pub enum MovePathContent<'tcx> { - Lvalue(Lvalue<'tcx>), - Static, -} - -/// During construction of the MovePath's, we use PreMovePath to -/// represent accumulated state while we are gathering up all the -/// children of each path. -#[derive(Clone)] -struct PreMovePath<'tcx> { - pub next_sibling: Option, - pub first_child: Cell>, - pub parent: Option, - pub content: MovePathContent<'tcx>, -} - -impl<'tcx> PreMovePath<'tcx> { - fn into_move_path(self) -> MovePath<'tcx> { - MovePath { - next_sibling: self.next_sibling, - parent: self.parent, - content: self.content, - first_child: self.first_child.get(), - } - } + pub lvalue: Lvalue<'tcx>, } impl<'tcx> fmt::Debug for MovePath<'tcx> { @@ -131,52 +104,50 @@ impl<'tcx> fmt::Debug for MovePath<'tcx> { if let Some(next_sibling) = self.next_sibling { write!(w, " next_sibling: {:?}", next_sibling)?; } - write!(w, " content: {:?} }}", self.content) + write!(w, " lvalue: {:?} }}", self.lvalue) } } #[derive(Debug)] pub struct MoveData<'tcx> { - pub move_paths: MovePathData<'tcx>, - pub moves: Vec, - pub loc_map: LocMap, - pub path_map: PathMap, + pub move_paths: IndexVec>, + pub moves: IndexVec, + /// Each Location `l` is mapped to the MoveOut's that are effects + /// of executing the code at `l`. (There can be multiple MoveOut's + /// for a given `l` because each MoveOut is associated with one + /// particular path being moved.) + pub loc_map: LocationMap>, + pub path_map: IndexVec>, pub rev_lookup: MovePathLookup<'tcx>, } #[derive(Debug)] -pub struct LocMap { +pub struct LocationMap { /// Location-indexed (BasicBlock for outer index, index within BB - /// for inner index) map to list of MoveOutIndex's. - /// - /// Each Location `l` is mapped to the MoveOut's that are effects - /// of executing the code at `l`. (There can be multiple MoveOut's - /// for a given `l` because each MoveOut is associated with one - /// particular path being moved.) - map: Vec>>, + /// for inner index) map. + map: IndexVec>, } -impl Index for LocMap { - type Output = [MoveOutIndex]; +impl Index for LocationMap { + type Output = T; fn index(&self, index: Location) -> &Self::Output { - assert!(index.block.index() < self.map.len()); - assert!(index.statement_index < self.map[index.block.index()].len()); - &self.map[index.block.index()][index.statement_index] + &self.map[index.block][index.statement_index] } } -#[derive(Debug)] -pub struct PathMap { - /// Path-indexed map to list of MoveOutIndex's. - /// - /// Each Path `p` is mapped to the MoveOut's that move out of `p`. - map: Vec>, +impl IndexMut for LocationMap { + fn index_mut(&mut self, index: Location) -> &mut Self::Output { + &mut self.map[index.block][index.statement_index] + } } -impl Index for PathMap { - type Output = [MoveOutIndex]; - fn index(&self, index: MovePathIndex) -> &Self::Output { - &self.map[index.index()] +impl LocationMap where T: Default + Clone { + fn new(mir: &Mir) -> Self { + LocationMap { + map: mir.basic_blocks().iter().map(|block| { + vec![T::default(); block.statements.len()+1] + }).collect() + } } } @@ -196,583 +167,373 @@ pub struct MoveOut { impl fmt::Debug for MoveOut { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "p{}@{:?}", self.path.index(), self.source) - } -} - -#[derive(Debug)] -pub struct MovePathData<'tcx> { - move_paths: Vec>, -} - -impl<'tcx> MovePathData<'tcx> { - pub fn len(&self) -> usize { self.move_paths.len() } -} - -impl<'tcx> Index for MovePathData<'tcx> { - type Output = MovePath<'tcx>; - fn index(&self, i: MovePathIndex) -> &MovePath<'tcx> { - &self.move_paths[i.index()] + write!(fmt, "{:?}@{:?}", self.path, self.source) } } -struct MovePathDataBuilder<'tcx> { - pre_move_paths: Vec>, - rev_lookup: MovePathLookup<'tcx>, -} - /// Tables mapping from an l-value to its MovePathIndex. #[derive(Debug)] pub struct MovePathLookup<'tcx> { - vars: IndexVec>, - temps: IndexVec>, - args: IndexVec>, + vars: IndexVec, + temps: IndexVec, + args: IndexVec, /// The move path representing the return value is constructed /// lazily when we first encounter it in the input MIR. return_ptr: Option, - /// A single move path (representing any static data referenced) - /// is constructed lazily when we first encounter statics in the - /// input MIR. - statics: Option, - /// projections are made from a base-lvalue and a projection /// elem. The base-lvalue will have a unique MovePathIndex; we use /// the latter as the index into the outer vector (narrowing /// subsequent search so that it is solely relative to that /// base-lvalue). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: Vec, MovePathIndex>>, - - /// Tracks the next index to allocate during construction of the - /// MovePathData. Unused after MovePathData is fully constructed. - next_index: MovePathIndex, + projections: FnvHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> } -trait FillTo { - type T; - fn fill_to_with(&mut self, idx: usize, x: Self::T); - fn fill_to(&mut self, idx: usize) where Self::T: Default { - self.fill_to_with(idx, Default::default()) - } +struct MoveDataBuilder<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &'a ParameterEnvironment<'tcx>, + data: MoveData<'tcx>, } -impl FillTo for Vec { - type T = T; - fn fill_to_with(&mut self, idx: usize, x: T) { - if idx >= self.len() { - let delta = idx + 1 - self.len(); - assert_eq!(idx + 1, self.len() + delta); - self.extend(iter::repeat(x).take(delta)) + +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn new(mir: &'a Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &'a ParameterEnvironment<'tcx>) + -> Self { + let mut move_paths = IndexVec::new(); + let mut path_map = IndexVec::new(); + + MoveDataBuilder { + mir: mir, + tcx: tcx, + param_env: param_env, + data: MoveData { + moves: IndexVec::new(), + loc_map: LocationMap::new(mir), + rev_lookup: MovePathLookup { + vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| { + Self::new_move_path(&mut move_paths, &mut path_map, None, v) + }).collect(), + temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| { + Self::new_move_path(&mut move_paths, &mut path_map, None, t) + }).collect(), + args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| { + Self::new_move_path(&mut move_paths, &mut path_map, None, a) + }).collect(), + return_ptr: None, + projections: FnvHashMap(), + }, + move_paths: move_paths, + path_map: path_map, + } } - debug_assert!(idx < self.len()); } -} -#[derive(Clone, Debug)] -enum LookupKind { Generate, Reuse } -#[derive(Clone, Debug)] -struct Lookup(LookupKind, T); - -impl Lookup { - fn index(&self) -> usize { (self.1).index() } -} - -impl<'tcx> MovePathLookup<'tcx> { - fn new(mir: &Mir) -> Self { - MovePathLookup { - vars: IndexVec::from_elem(None, &mir.var_decls), - temps: IndexVec::from_elem(None, &mir.temp_decls), - args: IndexVec::from_elem(None, &mir.arg_decls), - statics: None, - return_ptr: None, - projections: vec![], - next_index: MovePathIndex::new(0), + fn new_move_path(move_paths: &mut IndexVec>, + path_map: &mut IndexVec>, + parent: Option, + lvalue: Lvalue<'tcx>) + -> MovePathIndex + { + let move_path = move_paths.push(MovePath { + next_sibling: None, + first_child: None, + parent: parent, + lvalue: lvalue + }); + + if let Some(parent) = parent { + let next_sibling = + mem::replace(&mut move_paths[parent].first_child, Some(move_path)); + move_paths[move_path].next_sibling = next_sibling; } - } - fn next_index(next: &mut MovePathIndex) -> MovePathIndex { - let i = *next; - *next = MovePathIndex::new(i.index() + 1); - i + let path_map_ent = path_map.push(vec![]); + assert_eq!(path_map_ent, move_path); + move_path } - fn lookup_or_generate(vec: &mut IndexVec>, - idx: I, - next_index: &mut MovePathIndex) - -> Lookup { - let entry = &mut vec[idx]; - match *entry { - None => { - let i = Self::next_index(next_index); - *entry = Some(i); - Lookup(LookupKind::Generate, i) - } - Some(entry_idx) => { - Lookup(LookupKind::Reuse, entry_idx) + /// This creates a MovePath for a given lvalue, returning an `ErrorReported` + /// if that lvalue can't be moved from. + /// + /// NOTE: lvalues behind references *do not* get a move path, which is + /// problematic for borrowck. + /// + /// Maybe we should have seperate "borrowck" and "moveck" modes. + fn move_path_for(&mut self, lval: &Lvalue<'tcx>) + -> Result + { + debug!("lookup({:?})", lval); + match *lval { + Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]), + Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), + Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), + // error: can't move out of a static + Lvalue::Static(..) => Err(ErrorReported), + Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { + Some(ptr) => Ok(ptr), + ref mut ptr @ None => { + let path = Self::new_move_path( + &mut self.data.move_paths, + &mut self.data.path_map, + None, + lval.clone()); + *ptr = Some(path); + Ok(path) + } + }, + Lvalue::Projection(ref proj) => { + self.move_path_for_projection(lval, proj) } } } - fn lookup_var(&mut self, var_idx: Var) -> Lookup { - Self::lookup_or_generate(&mut self.vars, - var_idx, - &mut self.next_index) - } - - fn lookup_temp(&mut self, temp_idx: Temp) -> Lookup { - Self::lookup_or_generate(&mut self.temps, - temp_idx, - &mut self.next_index) - } - - fn lookup_arg(&mut self, arg_idx: Arg) -> Lookup { - Self::lookup_or_generate(&mut self.args, - arg_idx, - &mut self.next_index) + fn create_move_path(&mut self, lval: &Lvalue<'tcx>) { + // This is an assignment, not a move, so this not being a valid + // move path is OK. + let _ = self.move_path_for(lval); } - fn lookup_static(&mut self) -> Lookup { - match self.statics { - Some(mpi) => { - Lookup(LookupKind::Reuse, mpi) - } - ref mut ret @ None => { - let mpi = Self::next_index(&mut self.next_index); - *ret = Some(mpi); - Lookup(LookupKind::Generate, mpi) + fn move_path_for_projection(&mut self, + lval: &Lvalue<'tcx>, + proj: &LvalueProjection<'tcx>) + -> Result + { + let base = try!(self.move_path_for(&proj.base)); + let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + match lv_ty.sty { + // error: can't move out of borrowed content + ty::TyRef(..) | ty::TyRawPtr(..) => return Err(ErrorReported), + // error: can't move out of struct with destructor + ty::TyStruct(adt, _) | ty::TyEnum(adt, _) if adt.has_dtor() => + return Err(ErrorReported), + + ty::TyArray(..) | ty::TySlice(..) => match proj.elem { + // error: can't move out of an array + ProjectionElem::Index(..) => return Err(ErrorReported), + _ => {} + }, + _ => {} + }; + match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) { + Entry::Occupied(ent) => Ok(*ent.get()), + Entry::Vacant(ent) => { + let path = Self::new_move_path( + &mut self.data.move_paths, + &mut self.data.path_map, + Some(base), + lval.clone() + ); + ent.insert(path); + Ok(path) } } } - fn lookup_return_pointer(&mut self) -> Lookup { - match self.return_ptr { - Some(mpi) => { - Lookup(LookupKind::Reuse, mpi) + fn finalize(self) -> MoveData<'tcx> { + debug!("{}", { + debug!("moves for {:?}:", self.mir.span); + for (j, mo) in self.data.moves.iter_enumerated() { + debug!(" {:?} = {:?}", j, mo); } - ref mut ret @ None => { - let mpi = Self::next_index(&mut self.next_index); - *ret = Some(mpi); - Lookup(LookupKind::Generate, mpi) + debug!("move paths for {:?}:", self.mir.span); + for (j, path) in self.data.move_paths.iter_enumerated() { + debug!(" {:?} = {:?}", j, path); } - } + "done dumping moves" + }); + self.data } +} - fn lookup_proj(&mut self, - proj: &LvalueProjection<'tcx>, - base: MovePathIndex) -> Lookup { - let MovePathLookup { ref mut projections, - ref mut next_index, .. } = *self; - projections.fill_to(base.index()); - match projections[base.index()].entry(proj.elem.lift()) { - Entry::Occupied(ent) => { - Lookup(LookupKind::Reuse, *ent.get()) - } - Entry::Vacant(ent) => { - let mpi = Self::next_index(next_index); - ent.insert(mpi); - Lookup(LookupKind::Generate, mpi) - } - } - } +#[derive(Copy, Clone, Debug)] +pub enum LookupResult { + Exact(MovePathIndex), + Parent(Option) } impl<'tcx> MovePathLookup<'tcx> { // Unlike the builder `fn move_path_for` below, this lookup // alternative will *not* create a MovePath on the fly for an - // unknown l-value; it will simply panic. - pub fn find(&self, lval: &Lvalue<'tcx>) -> MovePathIndex { + // unknown l-value, but will rather return the nearest available + // parent. + pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult { match *lval { - Lvalue::Var(var) => self.vars[var].unwrap(), - Lvalue::Temp(temp) => self.temps[temp].unwrap(), - Lvalue::Arg(arg) => self.args[arg].unwrap(), - Lvalue::Static(ref _def_id) => self.statics.unwrap(), - Lvalue::ReturnPointer => self.return_ptr.unwrap(), + Lvalue::Var(var) => LookupResult::Exact(self.vars[var]), + Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]), + Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]), + Lvalue::Static(..) => LookupResult::Parent(None), + Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()), Lvalue::Projection(ref proj) => { - let base_index = self.find(&proj.base); - self.projections[base_index.index()][&proj.elem.lift()] + match self.find(&proj.base) { + LookupResult::Exact(base_path) => { + match self.projections.get(&(base_path, proj.elem.lift())) { + Some(&subpath) => LookupResult::Exact(subpath), + None => LookupResult::Parent(Some(base_path)) + } + } + inexact => inexact + } } } } } -impl<'tcx> MovePathDataBuilder<'tcx> { - fn lookup(&mut self, lval: &Lvalue<'tcx>) -> Lookup { - let proj = match *lval { - Lvalue::Var(var_idx) => - return self.rev_lookup.lookup_var(var_idx), - Lvalue::Temp(temp_idx) => - return self.rev_lookup.lookup_temp(temp_idx), - Lvalue::Arg(arg_idx) => - return self.rev_lookup.lookup_arg(arg_idx), - Lvalue::Static(_def_id) => - return self.rev_lookup.lookup_static(), - Lvalue::ReturnPointer => - return self.rev_lookup.lookup_return_pointer(), - Lvalue::Projection(ref proj) => { - proj - } - }; - - let base_index = self.move_path_for(&proj.base); - self.rev_lookup.lookup_proj(proj, base_index) - } - - fn create_move_path(&mut self, lval: &Lvalue<'tcx>) { - // Create MovePath for `lval`, discarding returned index. - self.move_path_for(lval); +impl<'a, 'tcx> MoveData<'tcx> { + pub fn gather_moves(mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>) + -> Self { + gather_moves(mir, tcx, param_env) } +} - fn move_path_for(&mut self, lval: &Lvalue<'tcx>) -> MovePathIndex { - debug!("move_path_for({:?})", lval); - - let lookup: Lookup = self.lookup(lval); - - // `lookup` is either the previously assigned index or a - // newly-allocated one. - debug_assert!(lookup.index() <= self.pre_move_paths.len()); - - if let Lookup(LookupKind::Generate, mpi) = lookup { - let parent; - let sibling; - // tracks whether content is Some non-static; statics map to None. - let content: Option<&Lvalue<'tcx>>; - - match *lval { - Lvalue::Static(_) => { - content = None; - sibling = None; - parent = None; - } - - Lvalue::Var(_) | Lvalue::Temp(_) | Lvalue::Arg(_) | - Lvalue::ReturnPointer => { - content = Some(lval); - sibling = None; - parent = None; - } - Lvalue::Projection(ref proj) => { - content = Some(lval); - - // Here, install new MovePath as new first_child. - - // Note: `parent` previously allocated (Projection - // case of match above established this). - let idx = self.move_path_for(&proj.base); - parent = Some(idx); - - let parent_move_path = &mut self.pre_move_paths[idx.index()]; - - // At last: Swap in the new first_child. - sibling = parent_move_path.first_child.get(); - parent_move_path.first_child.set(Some(mpi)); - } - }; - - let content = match content { - Some(lval) => MovePathContent::Lvalue(lval.clone()), - None => MovePathContent::Static, - }; - - let move_path = PreMovePath { - next_sibling: sibling, - parent: parent, - content: content, - first_child: Cell::new(None), - }; +fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>) + -> MoveData<'tcx> { + let mut builder = MoveDataBuilder::new(mir, tcx, param_env); - self.pre_move_paths.push(move_path); + for (bb, block) in mir.basic_blocks().iter_enumerated() { + for (i, stmt) in block.statements.iter().enumerate() { + let source = Location { block: bb, statement_index: i }; + builder.gather_statement(source, stmt); } - return lookup.1; + let terminator_loc = Location { + block: bb, + statement_index: block.statements.len() + }; + builder.gather_terminator(terminator_loc, block.terminator()); } -} -impl<'a, 'tcx> MoveData<'tcx> { - pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - gather_moves(mir, tcx) - } + builder.finalize() } -#[derive(Debug)] -enum StmtKind { - Use, Repeat, Cast, BinaryOp, UnaryOp, Box, - Aggregate, Drop, CallFn, CallArg, Return, If, -} - -fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveData<'tcx> { - use self::StmtKind as SK; - - let bb_count = mir.basic_blocks().len(); - let mut moves = vec![]; - let mut loc_map: Vec<_> = iter::repeat(Vec::new()).take(bb_count).collect(); - let mut path_map = Vec::new(); - - // this is mutable only because we will move it to and fro' the - // BlockContexts constructed on each iteration. (Moving is more - // straight-forward than mutable borrows in this instance.) - let mut builder = MovePathDataBuilder { - pre_move_paths: Vec::new(), - rev_lookup: MovePathLookup::new(mir), - }; - - // Before we analyze the program text, we create the MovePath's - // for all of the vars, args, and temps. (This enforces a basic - // property that even if the MIR body doesn't contain any - // references to a var/arg/temp, it will still be a valid - // operation to lookup the MovePath associated with it.) - assert!(mir.var_decls.len() <= ::std::u32::MAX as usize); - assert!(mir.arg_decls.len() <= ::std::u32::MAX as usize); - assert!(mir.temp_decls.len() <= ::std::u32::MAX as usize); - for var in mir.var_decls.indices() { - let path_idx = builder.move_path_for(&Lvalue::Var(var)); - path_map.fill_to(path_idx.index()); - } - for arg in mir.arg_decls.indices() { - let path_idx = builder.move_path_for(&Lvalue::Arg(arg)); - path_map.fill_to(path_idx.index()); - } - for temp in mir.temp_decls.indices() { - let path_idx = builder.move_path_for(&Lvalue::Temp(temp)); - path_map.fill_to(path_idx.index()); +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { + debug!("gather_statement({:?}, {:?})", loc, stmt); + match stmt.kind { + StatementKind::Assign(ref lval, ref rval) => { + self.create_move_path(lval); + self.gather_rvalue(loc, rval); + } + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) => {} + StatementKind::SetDiscriminant{ .. } => { + span_bug!(stmt.source_info.span, + "SetDiscriminant should not exist during borrowck"); + } + } } - for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { - let loc_map_bb = &mut loc_map[bb.index()]; - - debug_assert!(loc_map_bb.len() == 0); - let len = bb_data.statements.len(); - loc_map_bb.fill_to(len); - debug_assert!(loc_map_bb.len() == len + 1); - - let mut bb_ctxt = BlockContext { - _tcx: tcx, - moves: &mut moves, - builder: builder, - path_map: &mut path_map, - loc_map_bb: loc_map_bb, - }; - - for (i, stmt) in bb_data.statements.iter().enumerate() { - let source = Location { block: bb, statement_index: i }; - match stmt.kind { - StatementKind::Assign(ref lval, ref rval) => { - bb_ctxt.builder.create_move_path(lval); - - // Ensure that the path_map contains entries even - // if the lvalue is assigned and never read. - let assigned_path = bb_ctxt.builder.move_path_for(lval); - bb_ctxt.path_map.fill_to(assigned_path.index()); - - match *rval { - Rvalue::Use(ref operand) => { - bb_ctxt.on_operand(SK::Use, operand, source) - } - Rvalue::Repeat(ref operand, ref _const) => - bb_ctxt.on_operand(SK::Repeat, operand, source), - Rvalue::Cast(ref _kind, ref operand, ref _ty) => - bb_ctxt.on_operand(SK::Cast, operand, source), - Rvalue::BinaryOp(ref _binop, ref operand1, ref operand2) | - Rvalue::CheckedBinaryOp(ref _binop, ref operand1, ref operand2) => { - bb_ctxt.on_operand(SK::BinaryOp, operand1, source); - bb_ctxt.on_operand(SK::BinaryOp, operand2, source); - } - Rvalue::UnaryOp(ref _unop, ref operand) => { - bb_ctxt.on_operand(SK::UnaryOp, operand, source); - } - Rvalue::Box(ref _ty) => { - // this is creating uninitialized - // memory that needs to be initialized. - let deref_lval = Lvalue::Projection(Box::new(Projection { - base: lval.clone(), - elem: ProjectionElem::Deref, - })); - bb_ctxt.on_move_out_lval(SK::Box, &deref_lval, source); - } - Rvalue::Aggregate(ref _kind, ref operands) => { - for operand in operands { - bb_ctxt.on_operand(SK::Aggregate, operand, source); - } - } - Rvalue::Ref(..) | - Rvalue::Len(..) | - Rvalue::InlineAsm { .. } => {} - } - } - StatementKind::StorageLive(_) | - StatementKind::StorageDead(_) => {} - StatementKind::SetDiscriminant{ .. } => { - span_bug!(stmt.source_info.span, - "SetDiscriminant should not exist during borrowck"); + fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) { + match *rvalue { + Rvalue::Use(ref operand) | + Rvalue::Repeat(ref operand, _) | + Rvalue::Cast(_, ref operand, _) | + Rvalue::UnaryOp(_, ref operand) => { + self.gather_operand(loc, operand) + } + Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) | + Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => { + self.gather_operand(loc, lhs); + self.gather_operand(loc, rhs); + } + Rvalue::Aggregate(ref _kind, ref operands) => { + for operand in operands { + self.gather_operand(loc, operand); } } + Rvalue::Ref(..) | + Rvalue::Len(..) | + Rvalue::InlineAsm { .. } => {} + Rvalue::Box(..) => { + // This returns an rvalue with uninitialized contents. We can't + // move out of it here because it is an rvalue - assignments always + // completely initialize their lvalue. + // + // However, this does not matter - MIR building is careful to + // only emit a shallow free for the partially-initialized + // temporary. + // + // In any case, if we want to fix this, we have to register a + // special move and change the `statement_effect` functions. + } } + } - debug!("gather_moves({:?})", bb_data.terminator()); - match bb_data.terminator().kind { + fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { + debug!("gather_terminator({:?}, {:?})", loc, term); + match term.kind { TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | TerminatorKind::Unreachable => { } TerminatorKind::Return => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - debug!("gather_moves Return on_move_out_lval return {:?}", source); - bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); - } - - TerminatorKind::If { ref cond, targets: _ } => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_operand(SK::If, cond, source); - } - - TerminatorKind::Assert { - ref cond, expected: _, - ref msg, target: _, cleanup: _ - } => { - // The `cond` is always of (copyable) type `bool`, - // so there will never be anything to move. - let _ = cond; - match *msg { - AssertMessage:: BoundsCheck { ref len, ref index } => { - // Same for the usize length and index in bounds-checking. - let _ = (len, index); - } - AssertMessage::Math(_) => {} - } + self.gather_move(loc, &Lvalue::ReturnPointer); } - TerminatorKind::SwitchInt { switch_ty: _, values: _, targets: _, ref discr } | - TerminatorKind::Switch { adt_def: _, targets: _, ref discr } => { - // The `discr` is not consumed; that is instead - // encoded on specific match arms (and for - // SwitchInt`, it is always a copyable integer - // type anyway). - let _ = discr; + TerminatorKind::If { .. } | + TerminatorKind::Assert { .. } | + TerminatorKind::SwitchInt { .. } | + TerminatorKind::Switch { .. } => { + // branching terminators - these don't move anything } TerminatorKind::Drop { ref location, target: _, unwind: _ } => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_move_out_lval(SK::Drop, location, source); + self.gather_move(loc, location); } TerminatorKind::DropAndReplace { ref location, ref value, .. } => { - let assigned_path = bb_ctxt.builder.move_path_for(location); - bb_ctxt.path_map.fill_to(assigned_path.index()); - - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_operand(SK::Use, value, source); + self.create_move_path(location); + self.gather_operand(loc, value); } TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_operand(SK::CallFn, func, source); + self.gather_operand(loc, func); for arg in args { - debug!("gather_moves Call on_operand {:?} {:?}", arg, source); - bb_ctxt.on_operand(SK::CallArg, arg, source); + self.gather_operand(loc, arg); } if let Some((ref destination, _bb)) = *destination { - debug!("gather_moves Call create_move_path {:?} {:?}", destination, source); - - // Ensure that the path_map contains entries even - // if the lvalue is assigned and never read. - let assigned_path = bb_ctxt.builder.move_path_for(destination); - bb_ctxt.path_map.fill_to(assigned_path.index()); - - bb_ctxt.builder.create_move_path(destination); + self.create_move_path(destination); } } } - - builder = bb_ctxt.builder; } - // At this point, we may have created some MovePaths that do not - // have corresponding entries in the path map. - // - // (For example, creating the path `a.b.c` may, as a side-effect, - // create a path for the parent path `a.b`.) - // - // All such paths were not referenced ... - // - // well you know, lets actually try just asserting that the path map *is* complete. - assert_eq!(path_map.len(), builder.pre_move_paths.len()); - - let pre_move_paths = builder.pre_move_paths; - let move_paths: Vec<_> = pre_move_paths.into_iter() - .map(|p| p.into_move_path()) - .collect(); - - debug!("{}", { - let mut seen: Vec<_> = move_paths.iter().map(|_| false).collect(); - for (j, &MoveOut { ref path, ref source }) in moves.iter().enumerate() { - debug!("MovePathData moves[{}]: MoveOut {{ path: {:?} = {:?}, source: {:?} }}", - j, path, move_paths[path.index()], source); - seen[path.index()] = true; - } - for (j, path) in move_paths.iter().enumerate() { - if !seen[j] { - debug!("MovePathData move_paths[{}]: {:?}", j, path); + fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) { + match *operand { + Operand::Constant(..) => {} // not-a-move + Operand::Consume(ref lval) => { // a move + self.gather_move(loc, lval); } } - "done dumping MovePathData" - }); - - MoveData { - move_paths: MovePathData { move_paths: move_paths, }, - moves: moves, - loc_map: LocMap { map: loc_map }, - path_map: PathMap { map: path_map }, - rev_lookup: builder.rev_lookup, } -} -struct BlockContext<'b, 'tcx: 'b> { - _tcx: TyCtxt<'b, 'tcx, 'tcx>, - moves: &'b mut Vec, - builder: MovePathDataBuilder<'tcx>, - path_map: &'b mut Vec>, - loc_map_bb: &'b mut Vec>, -} + fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) { + debug!("gather_move({:?}, {:?})", loc, lval); -impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> { - fn on_move_out_lval(&mut self, - stmt_kind: StmtKind, - lval: &Lvalue<'tcx>, - source: Location) { - let i = source.statement_index; - let index = MoveOutIndex::new(self.moves.len()); - - let path = self.builder.move_path_for(lval); - self.moves.push(MoveOut { path: path, source: source.clone() }); - self.path_map.fill_to(path.index()); - - debug!("ctxt: {:?} add consume of lval: {:?} \ - at index: {:?} \ - to path_map for path: {:?} and \ - to loc_map for loc: {:?}", - stmt_kind, lval, index, path, source); - - debug_assert!(path.index() < self.path_map.len()); - // this is actually a questionable assert; at the very - // least, incorrect input code can probably cause it to - // fire. - assert!(self.path_map[path.index()].iter().find(|idx| **idx == index).is_none()); - self.path_map[path.index()].push(index); - - debug_assert!(i < self.loc_map_bb.len()); - debug_assert!(self.loc_map_bb[i].iter().find(|idx| **idx == index).is_none()); - self.loc_map_bb[i].push(index); - } - - fn on_operand(&mut self, stmt_kind: StmtKind, operand: &Operand<'tcx>, source: Location) { - match *operand { - Operand::Constant(..) => {} // not-a-move - Operand::Consume(ref lval) => { // a move - self.on_move_out_lval(stmt_kind, lval, source); - } + let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx); + if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) { + debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty); + return } + + let path = self.move_path_for(lval).unwrap_or_else(|_| { + // Moving out of a bad path. Eventually, this should be a MIR + // borrowck error instead of a bug. + span_bug!(self.mir.span, + "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", + lval, lv_ty, loc); + }); + let move_out = self.data.moves.push(MoveOut { path: path, source: loc }); + + debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", + loc, lval, move_out, path); + + self.data.path_map[path].push(move_out); + self.data.loc_map[loc].push(move_out); } } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index e035e268b1c4c..7c2410a2c145f 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -34,8 +34,7 @@ use self::dataflow::{DataflowOperator}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use self::dataflow::{DefinitelyInitializedLvals}; -use self::gather_moves::{MoveData, MovePathIndex}; -use self::gather_moves::{MovePathContent, MovePathData}; +use self::gather_moves::{MoveData, MovePathIndex, LookupResult}; fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option> { for attr in attrs { @@ -78,8 +77,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( let tcx = bcx.tcx; - let move_data = MoveData::gather_moves(mir, tcx); let param_env = ty::ParameterEnvironment::for_item(tcx, id); + let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let flow_inits = do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir)); @@ -211,23 +210,23 @@ impl DropFlagState { } } -fn move_path_children_matching<'tcx, F>(move_paths: &MovePathData<'tcx>, +fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option where F: FnMut(&repr::LvalueProjection<'tcx>) -> bool { - let mut next_child = move_paths[path].first_child; + let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { - match move_paths[child_index].content { - MovePathContent::Lvalue(repr::Lvalue::Projection(ref proj)) => { + match move_data.move_paths[child_index].lvalue { + repr::Lvalue::Projection(ref proj) => { if cond(proj) { return Some(child_index) } } _ => {} } - next_child = move_paths[child_index].next_sibling; + next_child = move_data.move_paths[child_index].next_sibling; } None @@ -272,6 +271,24 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx } } +fn on_lookup_result_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + lookup_result: LookupResult, + each_child: F) + where F: FnMut(MovePathIndex) +{ + match lookup_result { + LookupResult::Parent(..) => { + // access to untracked value - do not touch children + } + LookupResult::Exact(e) => { + on_all_children_bits(tcx, mir, move_data, e, each_child) + } + } +} + fn on_all_children_bits<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, @@ -286,12 +303,8 @@ fn on_all_children_bits<'a, 'tcx, F>( move_data: &MoveData<'tcx>, path: MovePathIndex) -> bool { - match move_data.move_paths[path].content { - MovePathContent::Lvalue(ref lvalue) => { - lvalue_contents_drop_state_cannot_differ(tcx, mir, lvalue) - } - _ => true - } + lvalue_contents_drop_state_cannot_differ( + tcx, mir, &move_data.move_paths[path].lvalue) } fn on_all_children_bits<'a, 'tcx, F>( @@ -327,10 +340,10 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( let move_data = &ctxt.move_data; for (arg, _) in mir.arg_decls.iter_enumerated() { let lvalue = repr::Lvalue::Arg(arg); - let move_path_index = move_data.rev_lookup.find(&lvalue); - on_all_children_bits(tcx, mir, move_data, - move_path_index, - |moi| callback(moi, DropFlagState::Present)); + let lookup_result = move_data.rev_lookup.find(&lvalue); + on_lookup_result_bits(tcx, mir, move_data, + lookup_result, + |moi| callback(moi, DropFlagState::Present)); } } @@ -352,11 +365,10 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( debug!("moving out of path {:?}", move_data.move_paths[path]); // don't move out of non-Copy things - if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content { - let ty = lvalue.ty(mir, tcx).to_ty(tcx); - if !ty.moves_by_default(tcx, param_env, DUMMY_SP) { - continue; - } + let lvalue = &move_data.move_paths[path].lvalue; + let ty = lvalue.ty(mir, tcx).to_ty(tcx); + if !ty.moves_by_default(tcx, param_env, DUMMY_SP) { + continue; } on_all_children_bits(tcx, mir, move_data, @@ -372,9 +384,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( } repr::StatementKind::Assign(ref lvalue, _) => { debug!("drop_flag_effects: assignment {:?}", stmt); - on_all_children_bits(tcx, mir, move_data, - move_data.rev_lookup.find(lvalue), - |moi| callback(moi, DropFlagState::Present)) + on_lookup_result_bits(tcx, mir, move_data, + move_data.rev_lookup.find(lvalue), + |moi| callback(moi, DropFlagState::Present)) } repr::StatementKind::StorageLive(_) | repr::StatementKind::StorageDead(_) => {} @@ -383,9 +395,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( debug!("drop_flag_effects: replace {:?}", block.terminator()); match block.terminator().kind { repr::TerminatorKind::DropAndReplace { ref location, .. } => { - on_all_children_bits(tcx, mir, move_data, - move_data.rev_lookup.find(location), - |moi| callback(moi, DropFlagState::Present)) + on_lookup_result_bits(tcx, mir, move_data, + move_data.rev_lookup.find(location), + |moi| callback(moi, DropFlagState::Present)) } _ => { // other terminators do not contain move-ins diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index cfd1ec0996861..e13da2531024f 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -180,7 +180,6 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { LvalueContext::Store | LvalueContext::Inspect | LvalueContext::Borrow { .. } | - LvalueContext::Slice { .. } | LvalueContext::Projection => { self.mark_as_lvalue(index); } From 7b25e886028195a4f90c0baa5cc9101ebeceb5a3 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 24 Jul 2016 13:56:27 +0300 Subject: [PATCH 755/768] forbid moves out of slices The wording of RFC #495 enables moves out of slices. Unfortuantely, non-zeroing moves out of slices introduce a very annoying complication: as slices can vary in their length, indexes from the start and end may or may not overlap depending on the slice's exact length, which prevents assigning a particular drop flag for each individual element. For example, in the code ```Rust fn foo(a: Box<[Box<[T]>]>, c: bool) -> T { match (a, c) { (box [box [t, ..], ..], true) => t, (box [.., box [.., t]], false) => t, _ => panic!() } } ``` If the condition is false, we have to drop the first element of `a`, unless `a` has size 1 in which case we drop all the elements of it but the last. If someone comes with a nice way of handling it, we can always re-allow moves out of slices. This is a [breaking-change], but it is behind the `slice_patterns` feature gate and was not allowed until recently. --- .../borrowck/gather_loans/gather_moves.rs | 1 + .../borrowck/gather_loans/move_error.rs | 26 ++++++++++--------- src/test/compile-fail/move-out-of-slice-1.rs | 21 +++++++++++++++ 3 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/move-out-of-slice-1.rs diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 3e335dacc8ed9..9bdc6887f6d03 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -185,6 +185,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, check_and_get_illegal_move_origin(bccx, b) } } + ty::TySlice(..) => Some(cmt.clone()), _ => { check_and_get_illegal_move_origin(bccx, b) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 3fa7c252b842c..9fbf1492f5d28 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -16,7 +16,6 @@ use rustc::ty; use syntax::ast; use syntax_pos; use errors::DiagnosticBuilder; -use rustc::hir; pub struct MoveErrorCollector<'tcx> { errors: Vec> @@ -131,17 +130,20 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, err } - Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => { - let expr = bccx.tcx.map.expect_expr(move_from.id); - if let hir::ExprIndex(..) = expr.node { - let mut err = struct_span_err!(bccx, move_from.span, E0508, - "cannot move out of type `{}`, \ - a non-copy fixed-size array", - b.ty); - err.span_label(move_from.span, &format!("cannot move out of here")); - err - } else { - span_bug!(move_from.span, "this path should not cause illegal move"); + Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => { + match (&b.ty.sty, ik) { + (&ty::TySlice(..), _) | + (_, Kind::Index) => { + let mut err = struct_span_err!(bccx, move_from.span, E0508, + "cannot move out of type `{}`, \ + a non-copy array", + b.ty); + err.span_label(move_from.span, &format!("cannot move out of here")); + err + } + (_, Kind::Pattern) => { + span_bug!(move_from.span, "this path should not cause illegal move"); + } } } diff --git a/src/test/compile-fail/move-out-of-slice-1.rs b/src/test/compile-fail/move-out-of-slice-1.rs new file mode 100644 index 0000000000000..f3efc68701e94 --- /dev/null +++ b/src/test/compile-fail/move-out-of-slice-1.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(slice_patterns, box_patterns)] + +struct A; + +fn main() { + let a: Box<[A]> = Box::new([A]); + match a { + box [a] => {}, //~ ERROR cannot move out of type `[A]` + _ => {} + } +} From eeedc144be1f57cda196638d7bf38cf4cd2b9700 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 8 Sep 2016 20:12:53 +0300 Subject: [PATCH 756/768] fix dynamic drop for unions Moving out of a union is now treated like moving out of its parent type. Fixes #36246 --- .../borrowck/mir/gather_moves.rs | 52 ++++++++++++------- src/librustc_borrowck/borrowck/mir/mod.rs | 6 +-- src/test/run-pass/dynamic-drop.rs | 25 ++++++++- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 2713a3c371db9..bd38f554dc9b0 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -12,7 +12,6 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; -use rustc::util::common::ErrorReported; use rustc_data_structures::indexed_vec::{IndexVec}; use syntax::codemap::DUMMY_SP; @@ -198,6 +197,11 @@ struct MoveDataBuilder<'a, 'tcx: 'a> { data: MoveData<'tcx>, } +pub enum MovePathError { + IllegalMove, + UnionMove { path: MovePathIndex }, +} + impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -256,7 +260,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { move_path } - /// This creates a MovePath for a given lvalue, returning an `ErrorReported` + /// This creates a MovePath for a given lvalue, returning an `MovePathError` /// if that lvalue can't be moved from. /// /// NOTE: lvalues behind references *do not* get a move path, which is @@ -264,7 +268,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { /// /// Maybe we should have seperate "borrowck" and "moveck" modes. fn move_path_for(&mut self, lval: &Lvalue<'tcx>) - -> Result + -> Result { debug!("lookup({:?})", lval); match *lval { @@ -272,7 +276,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), // error: can't move out of a static - Lvalue::Static(..) => Err(ErrorReported), + Lvalue::Static(..) => Err(MovePathError::IllegalMove), Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { Some(ptr) => Ok(ptr), ref mut ptr @ None => { @@ -300,21 +304,28 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn move_path_for_projection(&mut self, lval: &Lvalue<'tcx>, proj: &LvalueProjection<'tcx>) - -> Result + -> Result { let base = try!(self.move_path_for(&proj.base)); let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); match lv_ty.sty { // error: can't move out of borrowed content - ty::TyRef(..) | ty::TyRawPtr(..) => return Err(ErrorReported), + ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), // error: can't move out of struct with destructor - ty::TyStruct(adt, _) | ty::TyEnum(adt, _) if adt.has_dtor() => - return Err(ErrorReported), - - ty::TyArray(..) | ty::TySlice(..) => match proj.elem { + ty::TyAdt(adt, _) if adt.has_dtor() => + return Err(MovePathError::IllegalMove), + // move out of union - always move the entire union + ty::TyAdt(adt, _) if adt.is_union() => + return Err(MovePathError::UnionMove { path: base }), + // error: can't move out of a slice + ty::TySlice(..) => + return Err(MovePathError::IllegalMove), + ty::TyArray(..) => match proj.elem { // error: can't move out of an array - ProjectionElem::Index(..) => return Err(ErrorReported), - _ => {} + ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove), + _ => { + // FIXME: still badly broken + } }, _ => {} }; @@ -521,13 +532,16 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { return } - let path = self.move_path_for(lval).unwrap_or_else(|_| { - // Moving out of a bad path. Eventually, this should be a MIR - // borrowck error instead of a bug. - span_bug!(self.mir.span, - "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", - lval, lv_ty, loc); - }); + let path = match self.move_path_for(lval) { + Ok(path) | Err(MovePathError::UnionMove { path }) => path, + Err(MovePathError::IllegalMove) => { + // Moving out of a bad path. Eventually, this should be a MIR + // borrowck error instead of a bug. + span_bug!(self.mir.span, + "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", + lval, lv_ty, loc); + } + }; let move_out = self.data.moves.push(MoveOut { path: path, source: loc }); debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 7c2410a2c145f..5b5d782bc83a2 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -256,12 +256,12 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx let ty = lv.ty(mir, tcx).to_ty(tcx); match ty.sty { ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { - debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false", + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => true", lv, ty); true } - ty::TyAdt(def, _) if def.has_dtor() => { - debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", + ty::TyAdt(def, _) if def.has_dtor() || def.is_union() => { + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true", lv, ty); true } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 2b016dfb33eca..a2cca20640926 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] +#![feature(untagged_unions)] use std::cell::{Cell, RefCell}; use std::panic; @@ -111,6 +111,20 @@ fn assignment1(a: &Allocator, c0: bool) { _v = _w; } +#[allow(unions_with_drop_fields)] +union Boxy { + a: T, + b: T, +} + +fn union1(a: &Allocator) { + unsafe { + let mut u = Boxy { a: a.alloc() }; + u.b = a.alloc(); + drop(u.a); + } +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -136,6 +150,13 @@ fn run_test(mut f: F) } } +fn run_test_nopanic(mut f: F) + where F: FnMut(&Allocator) +{ + let first_alloc = Allocator::new(usize::MAX); + f(&first_alloc); +} + fn main() { run_test(|a| dynamic_init(a, false)); run_test(|a| dynamic_init(a, true)); @@ -149,4 +170,6 @@ fn main() { run_test(|a| assignment1(a, false)); run_test(|a| assignment1(a, true)); + + run_test_nopanic(|a| union1(a)); } From 5c5f75223c1f707e70bf3fdd98449338433c41f8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 16 Sep 2016 16:02:43 +0300 Subject: [PATCH 757/768] fix test fallout --- .../borrowck/borrowck-move-out-of-vec-tail.rs | 2 +- .../compile-fail/borrowck/borrowck-vec-pattern-nesting.rs | 2 +- src/test/compile-fail/issue-12567.rs | 8 ++++---- src/test/compile-fail/mir-dataflow/uninits-2.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs index f595d9d81cc6e..51e00a0ad2c3a 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs @@ -28,7 +28,7 @@ pub fn main() { [_, ref tail..] => { match tail { &[Foo { string: a }, - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of type `[Foo]` //~| cannot move out //~| to prevent move Foo { string: b }] => { diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs index d89b4100789f9..ae001e4e34d16 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs @@ -40,7 +40,7 @@ fn c() { let mut vec = vec!(box 1, box 2, box 3); let vec: &mut [Box] = &mut vec; match vec { - &mut [_a, //~ ERROR cannot move out of borrowed content + &mut [_a, //~ ERROR cannot move out //~| cannot move out //~| to prevent move .. diff --git a/src/test/compile-fail/issue-12567.rs b/src/test/compile-fail/issue-12567.rs index 32a6ea4f062cb..15d9a318d29ca 100644 --- a/src/test/compile-fail/issue-12567.rs +++ b/src/test/compile-fail/issue-12567.rs @@ -15,12 +15,12 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { (&[], &[]) => println!("both empty"), (&[], &[hd, ..]) | (&[hd, ..], &[]) => println!("one empty"), - //~^^ ERROR: cannot move out of borrowed content - //~^^^ ERROR: cannot move out of borrowed content + //~^^ ERROR: cannot move out of type `[T]`, a non-copy array + //~^^^ ERROR: cannot move out of type `[T]`, a non-copy array (&[hd1, ..], &[hd2, ..]) => println!("both nonempty"), - //~^^ ERROR: cannot move out of borrowed content - //~^^^ ERROR: cannot move out of borrowed content + //~^^ ERROR: cannot move out of type `[T]`, a non-copy array + //~^^^ ERROR: cannot move out of type `[T]`, a non-copy array } } diff --git a/src/test/compile-fail/mir-dataflow/uninits-2.rs b/src/test/compile-fail/mir-dataflow/uninits-2.rs index e0bf42534499c..94f812a40a9b5 100644 --- a/src/test/compile-fail/mir-dataflow/uninits-2.rs +++ b/src/test/compile-fail/mir-dataflow/uninits-2.rs @@ -23,7 +23,7 @@ struct S(i32); fn foo(x: &mut S) { // `x` is initialized here, so maybe-uninit bit is 0. - unsafe { *rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set + unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set ::std::mem::drop(x); From e8a44d29b633412b4173be8f1bfb6dae7ac3c45e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 10 Sep 2016 14:33:29 -0700 Subject: [PATCH 758/768] librustc_mir: Remove `&*x` when `x` has a reference type. This introduces a new `InstCombine` pass for us to place such peephole optimizations. --- src/librustc_driver/driver.rs | 3 + src/librustc_mir/transform/instcombine.rs | 110 ++++++++++++++++++++++ src/librustc_mir/transform/mod.rs | 2 + 3 files changed, 115 insertions(+) create mode 100644 src/librustc_mir/transform/instcombine.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 36e9fccdf5fd8..14cd05279b1ca 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1017,6 +1017,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads")); + // From here on out, regions are gone. passes.push_pass(box mir::transform::erase_regions::EraseRegions); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); @@ -1024,6 +1025,8 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + // No lifetime analysis based on borrowing can be done from here on out. + passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs new file mode 100644 index 0000000000000..a0331f03b0197 --- /dev/null +++ b/src/librustc_mir/transform/instcombine.rs @@ -0,0 +1,110 @@ +// 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. + +//! Performs various peephole optimizations. + +use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue}; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::mir::visit::{MutVisitor, Visitor}; +use rustc::ty::TyCtxt; +use rustc::util::nodemap::FnvHashSet; +use std::mem; + +pub struct InstCombine { + optimizations: OptimizationList, +} + +impl InstCombine { + pub fn new() -> InstCombine { + InstCombine { + optimizations: OptimizationList::default(), + } + } +} + +impl Pass for InstCombine {} + +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _: MirSource, + mir: &mut Mir<'tcx>) { + // We only run when optimizing MIR (at any level). + if tcx.sess.opts.debugging_opts.mir_opt_level == Some(0) { + return + } + + // First, find optimization opportunities. This is done in a pre-pass to keep the MIR + // read-only so that we can do global analyses on the MIR in the process (e.g. + // `Lvalue::ty()`). + { + let mut optimization_finder = OptimizationFinder::new(mir, tcx); + optimization_finder.visit_mir(mir); + self.optimizations = optimization_finder.optimizations + } + + // Then carry out those optimizations. + MutVisitor::visit_mir(&mut *self, mir); + } +} + +impl<'tcx> MutVisitor<'tcx> for InstCombine { + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + if self.optimizations.and_stars.remove(&location) { + debug!("Replacing `&*`: {:?}", rvalue); + let new_lvalue = match *rvalue { + Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => { + mem::replace(&mut projection.base, Lvalue::ReturnPointer) + } + _ => bug!("Detected `&*` but didn't find `&*`!"), + }; + *rvalue = Rvalue::Use(Operand::Consume(new_lvalue)) + } + + self.super_rvalue(rvalue, location) + } +} + +/// Finds optimization opportunities on the MIR. +struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + optimizations: OptimizationList, +} + +impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { + fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> { + OptimizationFinder { + mir: mir, + tcx: tcx, + optimizations: OptimizationList::default(), + } + } +} + +impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Ref(_, _, Lvalue::Projection(ref projection)) = *rvalue { + if let ProjectionElem::Deref = projection.elem { + if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + self.optimizations.and_stars.insert(location); + } + } + } + + self.super_rvalue(rvalue, location) + } +} + +#[derive(Default)] +struct OptimizationList { + and_stars: FnvHashSet, +} + diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index c3485b8256da1..e99b7a976e3e3 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -18,3 +18,5 @@ pub mod promote_consts; pub mod qualify_consts; pub mod dump_mir; pub mod deaggregator; +pub mod instcombine; + From ad6321573259f5877c9186fb084b7273d89dde71 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 15 Sep 2016 19:59:29 -0600 Subject: [PATCH 759/768] Add links between format_args! macro and std::fmt::Arguments struct --- src/libcore/fmt/mod.rs | 10 +++++++--- src/libstd/macros.rs | 14 ++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 66ef92928eb06..8342d663cdc7c 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -272,10 +272,14 @@ impl<'a> Arguments<'a> { /// safely be done so, so no constructors are given and the fields are private /// to prevent modification. /// -/// The `format_args!` macro will safely create an instance of this structure +/// The [`format_args!`] macro will safely create an instance of this structure /// and pass it to a function or closure, passed as the first argument. The -/// macro validates the format string at compile-time so usage of the `write` -/// and `format` functions can be safely performed. +/// macro validates the format string at compile-time so usage of the [`write`] +/// and [`format`] functions can be safely performed. +/// +/// [`format_args!`]: ../../std/macro.format_args.html +/// [`format`]: ../../std/fmt/fn.format.html +/// [`write`]: ../../std/fmt/fn.write.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub struct Arguments<'a> { diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6f0f6ecab5ba8..c78840bd42b07 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -193,12 +193,18 @@ macro_rules! assert_approx_eq { pub mod builtin { /// The core macro for formatted string creation & output. /// - /// This macro produces a value of type `fmt::Arguments`. This value can be - /// passed to the functions in `std::fmt` for performing useful functions. - /// All other formatting macros (`format!`, `write!`, `println!`, etc) are + /// This macro produces a value of type [`fmt::Arguments`]. This value can be + /// passed to the functions in [`std::fmt`] for performing useful functions. + /// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are /// proxied through this one. /// - /// For more information, see the documentation in `std::fmt`. + /// For more information, see the documentation in [`std::fmt`]. + /// + /// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html + /// [`std::fmt`]: ../std/fmt/index.html + /// [`format!`]: ../std/macro.format.html + /// [`write!`]: ../std/macro.write.html + /// [`println!`]: ../std/macro.println.html /// /// # Examples /// From d8b2cfeae6fbc1a9d7e86c9809f27ad1200903cb Mon Sep 17 00:00:00 2001 From: Cobrand Date: Fri, 16 Sep 2016 23:52:03 +0200 Subject: [PATCH 760/768] Remove stray println! when invoking error E0316 --- src/librustc/middle/resolve_lifetime.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 95706b5677a62..2d93c33afb409 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -337,7 +337,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { if self.trait_ref_hack { - println!("{:?}", trait_ref.span); span_err!(self.sess, trait_ref.span, E0316, "nested quantification of lifetimes"); } From d104e5bfb70f7ee3fc3e7d30e6021ae804ce87e5 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 16 Sep 2016 01:08:12 +0300 Subject: [PATCH 761/768] Up the LLVM Fixes #36474 --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/test/run-pass/issue-36474.rs | 40 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/issue-36474.rs diff --git a/src/llvm b/src/llvm index 16b79d01fd6d9..7801978ec1f36 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 16b79d01fd6d942cf3c9120b92df56b13ec92665 +Subproject commit 7801978ec1f3637fcda1b564048ebc732bf586af diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1080070d21a3b..ea8d59290df2e 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-08-30 +2016-09-17 diff --git a/src/test/run-pass/issue-36474.rs b/src/test/run-pass/issue-36474.rs new file mode 100644 index 0000000000000..025244ca6648c --- /dev/null +++ b/src/test/run-pass/issue-36474.rs @@ -0,0 +1,40 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + remove_axis(&3, 0); +} + +trait Dimension { + fn slice(&self) -> &[usize]; +} + +impl Dimension for () { + fn slice(&self) -> &[usize] { &[] } +} + +impl Dimension for usize { + fn slice(&self) -> &[usize] { + unsafe { + ::std::slice::from_raw_parts(self, 1) + } + } +} + +fn remove_axis(value: &usize, axis: usize) -> () { + let tup = (); + let mut it = tup.slice().iter(); + for (i, _) in value.slice().iter().enumerate() { + if i == axis { + continue; + } + it.next(); + } +} From 2cee9ec3b36933e143f2b2cc36a351da0a9114eb Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 17 Sep 2016 23:14:09 +0000 Subject: [PATCH 762/768] Ensure that macro invocations are folded and visited the same order. --- src/libsyntax/fold.rs | 84 ++++++++++++++++-------------------------- src/libsyntax/visit.rs | 10 ++--- 2 files changed, 36 insertions(+), 58 deletions(-) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9fb4d0203f41e..36f273e1dbc29 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -478,8 +478,8 @@ pub fn noop_fold_parenthesized_parameter_data(data: ParenthesizedPara pub fn noop_fold_local(l: P, fld: &mut T) -> P { l.map(|Local {id, pat, ty, init, span, attrs}| Local { id: fld.new_id(id), - ty: ty.map(|t| fld.fold_ty(t)), pat: fld.fold_pat(pat), + ty: ty.map(|t| fld.fold_ty(t)), init: init.map(|e| fld.fold_expr(e)), span: fld.new_span(span), attrs: fold_attrs(attrs.into(), fld).into(), @@ -860,14 +860,10 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e)) } ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => { - ItemKind::Fn( - folder.fold_fn_decl(decl), - unsafety, - constness, - abi, - folder.fold_generics(generics), - folder.fold_block(body) - ) + let generics = folder.fold_generics(generics); + let decl = folder.fold_fn_decl(decl); + let body = folder.fold_block(body); + ItemKind::Fn(decl, unsafety, constness, abi, generics, body) } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), @@ -875,50 +871,35 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } ItemKind::Enum(enum_definition, generics) => { - ItemKind::Enum( - ast::EnumDef { - variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)), - }, - folder.fold_generics(generics)) + let generics = folder.fold_generics(generics); + let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x)); + ItemKind::Enum(ast::EnumDef { variants: variants }, generics) } ItemKind::Struct(struct_def, generics) => { - let struct_def = folder.fold_variant_data(struct_def); - ItemKind::Struct(struct_def, folder.fold_generics(generics)) + let generics = folder.fold_generics(generics); + ItemKind::Struct(folder.fold_variant_data(struct_def), generics) } ItemKind::Union(struct_def, generics) => { - let struct_def = folder.fold_variant_data(struct_def); - ItemKind::Union(struct_def, folder.fold_generics(generics)) + let generics = folder.fold_generics(generics); + ItemKind::Union(folder.fold_variant_data(struct_def), generics) } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } - ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => { - let new_impl_items = impl_items.move_flat_map(|item| { - folder.fold_impl_item(item) - }); - let ifce = match ifce { - None => None, - Some(ref trait_ref) => { - Some(folder.fold_trait_ref((*trait_ref).clone())) - } - }; - ItemKind::Impl(unsafety, - polarity, - folder.fold_generics(generics), - ifce, - folder.fold_ty(ty), - new_impl_items) - } - ItemKind::Trait(unsafety, generics, bounds, items) => { - let bounds = folder.fold_bounds(bounds); - let items = items.move_flat_map(|item| { - folder.fold_trait_item(item) - }); - ItemKind::Trait(unsafety, - folder.fold_generics(generics), - bounds, - items) - } + ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl( + unsafety, + polarity, + folder.fold_generics(generics), + ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), + folder.fold_ty(ty), + impl_items.move_flat_map(|item| folder.fold_impl_item(item)), + ), + ItemKind::Trait(unsafety, generics, bounds, items) => ItemKind::Trait( + unsafety, + folder.fold_generics(generics), + folder.fold_bounds(bounds), + items.move_flat_map(|item| folder.fold_trait_item(item)), + ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), } } @@ -954,9 +935,9 @@ pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) -> SmallVector { SmallVector::one(ImplItem { id: folder.new_id(i.id), + vis: folder.fold_vis(i.vis), ident: folder.fold_ident(i.ident), attrs: fold_attrs(i.attrs, folder), - vis: folder.fold_vis(i.vis), defaultness: i.defaultness, node: match i.node { ast::ImplItemKind::Const(ty, expr) => { @@ -1031,15 +1012,12 @@ pub fn noop_fold_item(i: P, folder: &mut T) -> SmallVector(Item {id, ident, attrs, node, vis, span}: Item, folder: &mut T) -> Item { - let id = folder.new_id(id); - let node = folder.fold_item_kind(node); - Item { - id: id, + id: folder.new_id(id), + vis: folder.fold_vis(vis), ident: folder.fold_ident(ident), attrs: fold_attrs(attrs, folder), - node: node, - vis: folder.fold_vis(vis), + node: folder.fold_item_kind(node), span: folder.new_span(span) } } @@ -1047,6 +1025,7 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span} pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) -> ForeignItem { ForeignItem { id: folder.new_id(ni.id), + vis: folder.fold_vis(ni.vis), ident: folder.fold_ident(ni.ident), attrs: fold_attrs(ni.attrs, folder), node: match ni.node { @@ -1057,7 +1036,6 @@ pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) -> For ForeignItemKind::Static(folder.fold_ty(t), m) } }, - vis: folder.fold_vis(ni.vis), span: folder.new_span(ni.span) } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index efd9b027504f0..57b06c40878fe 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -532,8 +532,8 @@ pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span) where V: Visitor, { - walk_fn_decl(visitor, declaration); walk_fn_kind(visitor, kind); + walk_fn_decl(visitor, declaration); visitor.visit_block(body) } @@ -652,13 +652,13 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { walk_list!(visitor, visit_expr, subexpressions); } ExprKind::Call(ref callee_expression, ref arguments) => { + visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); - visitor.visit_expr(callee_expression) } ExprKind::MethodCall(ref ident, ref types, ref arguments) => { visitor.visit_ident(ident.span, ident.node); - walk_list!(visitor, visit_expr, arguments); walk_list!(visitor, visit_ty, types); + walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { visitor.visit_expr(left_expression); @@ -717,12 +717,12 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { } ExprKind::Block(ref block) => visitor.visit_block(block), ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { + visitor.visit_expr(left_hand_expression); visitor.visit_expr(right_hand_expression); - visitor.visit_expr(left_hand_expression) } ExprKind::AssignOp(_, ref left_expression, ref right_expression) => { + visitor.visit_expr(left_expression); visitor.visit_expr(right_expression); - visitor.visit_expr(left_expression) } ExprKind::Field(ref subexpression, ref ident) => { visitor.visit_expr(subexpression); From c7e4ae0d8d22847259e2e08a851f80e375221707 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 17 Sep 2016 23:31:32 +0000 Subject: [PATCH 763/768] Add regression test. --- src/test/run-pass/type-macros-simple.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/run-pass/type-macros-simple.rs b/src/test/run-pass/type-macros-simple.rs index 7d1045cf3f1a8..6b0deff3ba4fa 100644 --- a/src/test/run-pass/type-macros-simple.rs +++ b/src/test/run-pass/type-macros-simple.rs @@ -15,3 +15,22 @@ macro_rules! Tuple { fn main() { let x: Tuple!(i32, i32) = (1, 2); } + +fn issue_36540() { + let i32 = 0; + macro_rules! m { () => { i32 } } + struct S(m!(), T) where T: Trait; + + let x: m!() = m!(); + std::cell::Cell::::new(m!()); + impl std::ops::Index for Trait<(m!(), T)> + where T: Trait + { + type Output = m!(); + fn index(&self, i: m!()) -> &m!() { + unimplemented!() + } + } +} + +trait Trait {} From 5505ebc31d1d2e0bddbed815ad0c899c0d42585e Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 10 Sep 2016 17:09:02 -0400 Subject: [PATCH 764/768] Add basic doc examples for `std::panic::{set_hook, take_hook}`. --- src/libstd/panicking.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 0c10dcbdad646..1f5b3437b6155 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -84,6 +84,20 @@ static mut HOOK: Hook = Hook::Default; /// # Panics /// /// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print "Custom panic hook": +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|_| { +/// println!("Custom panic hook"); +/// })); +/// +/// panic!("Normal panic"); +/// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn set_hook(hook: Box) { if thread::panicking() { @@ -109,6 +123,22 @@ pub fn set_hook(hook: Box) { /// # Panics /// /// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print "Normal panic": +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|_| { +/// println!("Custom panic hook"); +/// })); +/// +/// let _ = panic::take_hook(); +/// +/// panic!("Normal panic"); +/// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn take_hook() -> Box { if thread::panicking() { From 48e69e029b420aea09009ef1734bdfc5226a01de Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 19 Sep 2016 07:17:49 +1200 Subject: [PATCH 765/768] save-analysis: better 'parent' info In particular, this fixes some bugs displaying doc URLs for method calls. --- src/librustc_save_analysis/data.rs | 11 ++-- src/librustc_save_analysis/dump_visitor.rs | 72 ++++++++++++++------- src/librustc_save_analysis/external_data.rs | 14 ++-- src/librustc_save_analysis/lib.rs | 15 +++-- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 5f6e65e289fd5..4e03ea4218f0a 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -167,7 +167,7 @@ pub struct FunctionData { pub scope: NodeId, pub value: String, pub visibility: Visibility, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -250,6 +250,7 @@ pub struct MethodData { pub scope: NodeId, pub value: String, pub decl_id: Option, + pub parent: Option, pub visibility: Visibility, pub docs: String, } @@ -300,7 +301,7 @@ pub struct StructVariantData { pub type_value: String, pub value: String, pub scope: NodeId, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -326,7 +327,7 @@ pub struct TupleVariantData { pub type_value: String, pub value: String, pub scope: NodeId, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -339,7 +340,7 @@ pub struct TypeDefData { pub qualname: String, pub value: String, pub visibility: Visibility, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -380,7 +381,7 @@ pub struct VariableData { pub qualname: String, pub span: Span, pub scope: NodeId, - pub parent: Option, + pub parent: Option, pub value: String, pub type_value: String, pub visibility: Visibility, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f31e12991c808..8820f3616d50d 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -27,9 +27,10 @@ //! is used for recording the output in a format-agnostic way (see CsvDumper //! for an example). +use rustc::hir; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; -use rustc::hir::map::Node; +use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; @@ -47,7 +48,7 @@ use syntax_pos::*; use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; use super::data::*; use super::dump::Dump; -use super::external_data::Lower; +use super::external_data::{Lower, make_def_id}; use super::span_utils::SpanUtils; use super::recorder; @@ -271,11 +272,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // looks up anything, not just a type fn lookup_type_ref(&self, ref_id: NodeId) -> Option { - match self.tcx.expect_def(ref_id) { - Def::PrimTy(..) => None, - Def::SelfTy(..) => None, - def => Some(def.def_id()), - } + self.tcx.expect_def_or_none(ref_id).and_then(|def| { + match def { + Def::PrimTy(..) => None, + Def::SelfTy(..) => None, + def => Some(def.def_id()), + } + }) } fn process_def_kind(&mut self, @@ -399,20 +402,36 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { if !self.span.filter_generated(Some(method_data.span), span) { let container = self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container(); - let decl_id = if let ImplOrTraitItemContainer::ImplContainer(id) = container { - self.tcx.trait_id_of_impl(id).and_then(|id| { - for item in &**self.tcx.trait_items(id) { - if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { - if m.name == name { - return Some(m.def_id); + let mut trait_id; + let mut decl_id = None; + match container { + ImplOrTraitItemContainer::ImplContainer(id) => { + trait_id = self.tcx.trait_id_of_impl(id); + + match trait_id { + Some(id) => { + for item in &**self.tcx.trait_items(id) { + if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { + if m.name == name { + decl_id = Some(m.def_id); + break; + } + } + } + } + None => { + if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { + trait_id = self.lookup_type_ref(ty.id); + } } } } - None - }) - } else { - None - }; + } + ImplOrTraitItemContainer::TraitContainer(id) => { + trait_id = Some(id); + } + } self.dumper.method(MethodData { id: method_data.id, @@ -422,6 +441,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: method_data.qualname.clone(), value: sig_str, decl_id: decl_id, + parent: trait_id, visibility: vis, docs: docs_for_attrs(attrs), }.lower(self.tcx)); @@ -544,7 +564,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { span: Span, typ: &ast::Ty, expr: &ast::Expr, - parent_id: NodeId, + parent_id: DefId, vis: Visibility, attrs: &[Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); @@ -659,7 +679,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { type_value: enum_data.qualname.clone(), value: val, scope: enum_data.scope, - parent: Some(item.id), + parent: Some(make_def_id(item.id, &self.tcx.map)), docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } @@ -684,7 +704,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { type_value: enum_data.qualname.clone(), value: val, scope: enum_data.scope, - parent: Some(item.id), + parent: Some(make_def_id(item.id, &self.tcx.map)), docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } @@ -738,7 +758,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { - self.process_impl_item(impl_item, item.id); + let map = &self.tcx.map; + self.process_impl_item(impl_item, make_def_id(item.id, map)); } } @@ -809,7 +830,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // walk generics and methods self.process_generic_params(generics, item.span, &qualname, item.id); for method in methods { - self.process_trait_item(method, item.id) + let map = &self.tcx.map; + self.process_trait_item(method, make_def_id(item.id, map)) } } @@ -1076,7 +1098,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: NodeId) { + fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: DefId) { self.process_macro_use(trait_item.span, trait_item.id); match trait_item.node { ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { @@ -1104,7 +1126,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: NodeId) { + fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: DefId) { self.process_macro_use(impl_item.span, impl_item.id); match impl_item.node { ast::ImplItemKind::Const(ref ty, ref expr) => { diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 3642346582bb9..32280a5c9262a 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -23,7 +23,7 @@ pub trait Lower { fn lower(self, tcx: TyCtxt) -> Self::Target; } -fn make_def_id(id: NodeId, map: &Map) -> DefId { +pub fn make_def_id(id: NodeId, map: &Map) -> DefId { map.opt_local_def_id(id).unwrap_or(null_def_id()) } @@ -188,7 +188,7 @@ impl Lower for data::FunctionData { scope: make_def_id(self.scope, &tcx.map), value: self.value, visibility: self.visibility, - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -353,7 +353,7 @@ impl Lower for data::MethodData { value: self.value, decl_id: self.decl_id, visibility: self.visibility, - parent: Some(make_def_id(self.scope, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -471,7 +471,7 @@ impl Lower for data::StructVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -533,7 +533,7 @@ impl Lower for data::TupleVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -563,7 +563,7 @@ impl Lower for data::TypeDefData { qualname: self.qualname, value: self.value, visibility: self.visibility, - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -668,7 +668,7 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, visibility: self.visibility, docs: self.docs, } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 35ad2d9316cda..51274068b26ca 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -64,6 +64,7 @@ pub use self::csv_dumper::CsvDumper; pub use self::json_api_dumper::JsonApiDumper; pub use self::json_dumper::JsonDumper; pub use self::data::*; +pub use self::external_data::make_def_id; pub use self::dump::Dump; pub use self::dump_visitor::DumpVisitor; use self::span_utils::SpanUtils; @@ -295,7 +296,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: scope, - parent: Some(scope), + parent: Some(make_def_id(scope, &self.tcx.map)), value: "".to_owned(), type_value: typ, visibility: From::from(&field.vis), @@ -312,7 +313,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, parent_scope, vis, docs) = + match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -320,12 +322,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = String::from("<"); result.push_str(&rustc::hir::print::ty_to_string(&ty)); - if let Some(def_id) = self.tcx.trait_id_of_impl(impl_id) { + let trait_id = self.tcx.trait_id_of_impl(impl_id); + if let Some(def_id) = trait_id { result.push_str(" as "); result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - (result, From::from(&item.vis), docs_for_attrs(&item.attrs)) + (result, trait_id, From::from(&item.vis), docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -348,6 +351,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { (format!("::{}", self.tcx.item_path_str(def_id)), + Some(def_id), From::from(&item.vis), docs_for_attrs(&item.attrs)) } @@ -381,7 +385,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); - let parent_scope = self.enclosing_scope(id); Some(FunctionData { id: id, name: name.to_string(), @@ -392,7 +395,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME you get better data here by using the visitor. value: String::new(), visibility: vis, - parent: Some(parent_scope), + parent: parent_scope, docs: docs, }) } From 2e6a91812c64a507e3d2ab727824ff9cda8449fc Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 15 Sep 2016 18:17:58 -0700 Subject: [PATCH 766/768] librustc: Add a new nop statement to the MIR. This is useful when passes want to remove statements without affecting `Location`s. --- src/librustc/mir/repr.rs | 20 +++++++++++++++++++ src/librustc/mir/visit.rs | 1 + .../borrowck/mir/dataflow/impls.rs | 3 ++- .../borrowck/mir/dataflow/sanity_check.rs | 3 ++- src/librustc_borrowck/borrowck/mir/mod.rs | 3 ++- src/librustc_mir/transform/qualify_consts.rs | 3 ++- src/librustc_mir/transform/type_check.rs | 1 + src/librustc_trans/mir/constant.rs | 3 ++- src/librustc_trans/mir/statement.rs | 1 + 9 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 53b6ccdbd530a..3ab8ed5bce292 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -187,6 +187,14 @@ impl<'tcx> Mir<'tcx> { self.var_decls.len() + self.temp_decls.len() + 1 } + + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids + /// invalidating statement indices in `Location`s. + pub fn make_statement_nop(&mut self, location: Location) { + let block = &mut self[location.block]; + debug_assert!(location.statement_index < block.statements.len()); + block.statements[location.statement_index].make_nop() + } } impl<'tcx> Index for Mir<'tcx> { @@ -686,6 +694,14 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } +impl<'tcx> Statement<'tcx> { + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids + /// invalidating statement indices in `Location`s. + pub fn make_nop(&mut self) { + self.kind = StatementKind::Nop + } +} + #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Lvalue. @@ -699,6 +715,9 @@ pub enum StatementKind<'tcx> { /// End the current live range for the storage of the local. StorageDead(Lvalue<'tcx>), + + /// No-op. Useful for deleting instructions without affecting statement indices. + Nop, } impl<'tcx> Debug for Statement<'tcx> { @@ -711,6 +730,7 @@ impl<'tcx> Debug for Statement<'tcx> { SetDiscriminant{lvalue: ref lv, variant_index: index} => { write!(fmt, "discriminant({:?}) = {:?}", lv, index) } + Nop => write!(fmt, "nop"), } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 16e0b376f4b53..072faf795220a 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -346,6 +346,7 @@ macro_rules! make_mir_visitor { StatementKind::StorageDead(ref $($mutability)* lvalue) => { self.visit_lvalue(lvalue, LvalueContext::StorageDead, location); } + StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 8ac59c60396f6..55dda8eda3a4a 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -455,7 +455,8 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { }); } repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) => {} + repr::StatementKind::StorageDead(_) | + repr::StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 88f6d5fef562d..aeb91f06a9aa4 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -105,7 +105,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (lvalue, rvalue) } repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) => continue, + repr::StatementKind::StorageDead(_) | + repr::StatementKind::Nop => continue, repr::StatementKind::SetDiscriminant{ .. } => span_bug!(stmt.source_info.span, "sanity_check should run before Deaggregator inserts SetDiscriminant"), diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 5b5d782bc83a2..f26afdc2b8572 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -389,7 +389,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( |moi| callback(moi, DropFlagState::Present)) } repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) => {} + repr::StatementKind::StorageDead(_) | + repr::StatementKind::Nop => {} }, None => { debug!("drop_flag_effects: replace {:?}", block.terminator()); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a3f8f7a63eeab..9f162aabe0c2f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -910,7 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } StatementKind::SetDiscriminant { .. } | StatementKind::StorageLive(_) | - StatementKind::StorageDead(_) => {} + StatementKind::StorageDead(_) | + StatementKind::Nop => {} } }); } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7fda658185e07..412759cd5b2d3 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -385,6 +385,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } + StatementKind::Nop => {} } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index e9f324c0b08f0..70d0a61840475 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -292,7 +292,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } mir::StatementKind::StorageLive(_) | - mir::StatementKind::StorageDead(_) => {} + mir::StatementKind::StorageDead(_) | + mir::StatementKind::Nop => {} mir::StatementKind::SetDiscriminant{ .. } => { span_bug!(span, "SetDiscriminant should not appear in constants?"); } diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 1167208955368..325bd655266c1 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -78,6 +78,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::StatementKind::StorageDead(ref lvalue) => { self.trans_storage_liveness(bcx, lvalue, base::Lifetime::End) } + mir::StatementKind::Nop => bcx, } } From 480287ec3b0260e26c8796506039c379bd7e0ead Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 15 Sep 2016 18:18:40 -0700 Subject: [PATCH 767/768] librustc: Implement def-use chains and trivial copy propagation on MIR. This only supports trivial cases in which there is exactly one def and one use. --- src/librustc/mir/repr.rs | 46 ++++ src/librustc/mir/visit.rs | 108 +++++++++- .../borrowck/mir/gather_moves.rs | 1 + src/librustc_driver/driver.rs | 1 + src/librustc_mir/def_use.rs | 197 ++++++++++++++++++ src/librustc_mir/lib.rs | 2 + src/librustc_mir/transform/copy_prop.rs | 180 ++++++++++++++++ src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/promote_consts.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 5 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/mir/analyze.rs | 4 +- src/test/codegen/refs.rs | 4 +- src/test/mir-opt/storage_ranges.rs | 38 ++-- 14 files changed, 560 insertions(+), 32 deletions(-) create mode 100644 src/librustc_mir/def_use.rs create mode 100644 src/librustc_mir/transform/copy_prop.rs diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 3ab8ed5bce292..be761c95b6119 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -188,6 +188,24 @@ impl<'tcx> Mir<'tcx> { self.temp_decls.len() + 1 } + pub fn format_local(&self, local: Local) -> String { + let mut index = local.index(); + index = match index.checked_sub(self.arg_decls.len()) { + None => return format!("{:?}", Arg::new(index)), + Some(index) => index, + }; + index = match index.checked_sub(self.var_decls.len()) { + None => return format!("{:?}", Var::new(index)), + Some(index) => index, + }; + index = match index.checked_sub(self.temp_decls.len()) { + None => return format!("{:?}", Temp::new(index)), + Some(index) => index, + }; + debug_assert!(index == 0); + return "ReturnPointer".to_string() + } + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_statement_nop(&mut self, location: Location) { @@ -844,6 +862,24 @@ impl<'tcx> Lvalue<'tcx> { elem: elem, })) } + + pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> { + let mut index = local.index(); + index = match index.checked_sub(mir.arg_decls.len()) { + None => return Lvalue::Arg(Arg(index as u32)), + Some(index) => index, + }; + index = match index.checked_sub(mir.var_decls.len()) { + None => return Lvalue::Var(Var(index as u32)), + Some(index) => index, + }; + index = match index.checked_sub(mir.temp_decls.len()) { + None => return Lvalue::Temp(Temp(index as u32)), + Some(index) => index, + }; + debug_assert!(index == 0); + Lvalue::ReturnPointer + } } impl<'tcx> Debug for Lvalue<'tcx> { @@ -1278,3 +1314,13 @@ impl fmt::Debug for Location { write!(fmt, "{:?}[{}]", self.block, self.statement_index) } } + +impl Location { + pub fn dominates(&self, other: &Location, dominators: &Dominators) -> bool { + if self.block == other.block { + self.statement_index <= other.statement_index + } else { + dominators.is_dominated_by(other.block, self.block) + } + } +} diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 072faf795220a..2c58d35973e73 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -150,7 +150,7 @@ macro_rules! make_mir_visitor { fn visit_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { self.super_lvalue(lvalue, context, location); } @@ -581,7 +581,7 @@ macro_rules! make_mir_visitor { fn super_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { match *lvalue { Lvalue::Var(_) | @@ -606,7 +606,12 @@ macro_rules! make_mir_visitor { ref $($mutability)* base, ref $($mutability)* elem, } = *proj; - self.visit_lvalue(base, LvalueContext::Projection, location); + let context = if context.is_mutating_use() { + LvalueContext::Projection(Mutability::Mut) + } else { + LvalueContext::Projection(Mutability::Not) + }; + self.visit_lvalue(base, context, location); self.visit_projection_elem(elem, context, location); } @@ -751,6 +756,21 @@ macro_rules! make_mir_visitor { fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) { } + + // Convenience methods + + fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) { + let basic_block = & $($mutability)* mir[location.block]; + if basic_block.statements.len() == location.statement_index { + if let Some(ref $($mutability)* terminator) = basic_block.terminator { + self.visit_terminator(location.block, terminator, location) + } + } else { + let statement = & $($mutability)* + basic_block.statements[location.statement_index]; + self.visit_statement(location.block, statement, location) + } + } } } } @@ -775,8 +795,20 @@ pub enum LvalueContext<'tcx> { // Being borrowed Borrow { region: &'tcx Region, kind: BorrowKind }, - // Used as base for another lvalue, e.g. `x` in `x.y` - Projection, + // Used as base for another lvalue, e.g. `x` in `x.y`. + // + // The `Mutability` argument specifies whether the projection is being performed in order to + // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation + // in these cases: + // + // x.y = ...; + // f(&mut x.y); + // + // But not in these cases: + // + // z = x.y; + // f(&x.y); + Projection(Mutability), // Consumed as part of an operand Consume, @@ -785,3 +817,69 @@ pub enum LvalueContext<'tcx> { StorageLive, StorageDead, } + +impl<'tcx> LvalueContext<'tcx> { + /// Returns true if this lvalue context represents a drop. + pub fn is_drop(&self) -> bool { + match *self { + LvalueContext::Drop => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a storage live or storage dead marker. + pub fn is_storage_marker(&self) -> bool { + match *self { + LvalueContext::StorageLive | LvalueContext::StorageDead => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a storage live marker. + pub fn is_storage_live_marker(&self) -> bool { + match *self { + LvalueContext::StorageLive => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a storage dead marker. + pub fn is_storage_dead_marker(&self) -> bool { + match *self { + LvalueContext::StorageDead => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a use that potentially changes the value. + pub fn is_mutating_use(&self) -> bool { + match *self { + LvalueContext::Store | LvalueContext::Call | + LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | + LvalueContext::Projection(Mutability::Mut) | + LvalueContext::Drop => true, + LvalueContext::Inspect | + LvalueContext::Borrow { kind: BorrowKind::Shared, .. } | + LvalueContext::Borrow { kind: BorrowKind::Unique, .. } | + LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume | + LvalueContext::StorageLive | LvalueContext::StorageDead => false, + } + } + + /// Returns true if this lvalue context represents a use that does not change the value. + pub fn is_nonmutating_use(&self) -> bool { + match *self { + LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } | + LvalueContext::Borrow { kind: BorrowKind::Unique, .. } | + LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true, + LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store | + LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) | + LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false, + } + } + + pub fn is_use(&self) -> bool { + self.is_mutating_use() || self.is_nonmutating_use() + } +} + diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index bd38f554dc9b0..6346c1e58897e 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -438,6 +438,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } + StatementKind::Nop => {} } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c02c5f18b4c65..55892801247b5 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1028,6 +1028,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // No lifetime analysis based on borrowing can be done from here on out. passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); + passes.push_pass(box mir::transform::copy_prop::CopyPropagation); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); diff --git a/src/librustc_mir/def_use.rs b/src/librustc_mir/def_use.rs new file mode 100644 index 0000000000000..7329a20c49708 --- /dev/null +++ b/src/librustc_mir/def_use.rs @@ -0,0 +1,197 @@ +// 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. + +//! Def-use analysis. + +use rustc::mir::repr::{Local, Location, Lvalue, Mir}; +use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use std::marker::PhantomData; +use std::mem; + +pub struct DefUseAnalysis<'tcx> { + info: IndexVec>, + mir_summary: MirSummary, +} + +#[derive(Clone)] +pub struct Info<'tcx> { + pub defs_and_uses: Vec>, +} + +#[derive(Clone)] +pub struct Use<'tcx> { + pub context: LvalueContext<'tcx>, + pub location: Location, +} + +impl<'tcx> DefUseAnalysis<'tcx> { + pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { + DefUseAnalysis { + info: IndexVec::from_elem_n(Info::new(), mir.count_locals()), + mir_summary: MirSummary::new(mir), + } + } + + pub fn analyze(&mut self, mir: &Mir<'tcx>) { + let mut finder = DefUseFinder { + info: mem::replace(&mut self.info, IndexVec::new()), + mir_summary: self.mir_summary, + }; + finder.visit_mir(mir); + self.info = finder.info + } + + pub fn local_info(&self, local: Local) -> &Info<'tcx> { + &self.info[local] + } + + pub fn local_info_mut(&mut self, local: Local) -> &mut Info<'tcx> { + &mut self.info[local] + } + + fn mutate_defs_and_uses(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F) + where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, + LvalueContext<'tcx>, + Location) { + for lvalue_use in &self.info[local].defs_and_uses { + MutateUseVisitor::new(local, + &mut callback, + self.mir_summary, + mir).visit_location(mir, lvalue_use.location) + } + } + + /// FIXME(pcwalton): This should update the def-use chains. + pub fn replace_all_defs_and_uses_with(&self, + local: Local, + mir: &mut Mir<'tcx>, + new_lvalue: Lvalue<'tcx>) { + self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone()) + } +} + +struct DefUseFinder<'tcx> { + info: IndexVec>, + mir_summary: MirSummary, +} + +impl<'tcx> DefUseFinder<'tcx> { + fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> { + let info = &mut self.info; + self.mir_summary.local_index(lvalue).map(move |local| &mut info[local]) + } +} + +impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> { + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if let Some(ref mut info) = self.lvalue_mut_info(lvalue) { + info.defs_and_uses.push(Use { + context: context, + location: location, + }) + } + self.super_lvalue(lvalue, context, location) + } +} + +impl<'tcx> Info<'tcx> { + fn new() -> Info<'tcx> { + Info { + defs_and_uses: vec![], + } + } + + pub fn def_count(&self) -> usize { + self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count() + } + + pub fn def_count_not_including_drop(&self) -> usize { + self.defs_and_uses.iter().filter(|lvalue_use| { + lvalue_use.context.is_mutating_use() && !lvalue_use.context.is_drop() + }).count() + } + + pub fn use_count(&self) -> usize { + self.defs_and_uses.iter().filter(|lvalue_use| { + lvalue_use.context.is_nonmutating_use() + }).count() + } +} + +struct MutateUseVisitor<'tcx, F> { + query: Local, + callback: F, + mir_summary: MirSummary, + phantom: PhantomData<&'tcx ()>, +} + +impl<'tcx, F> MutateUseVisitor<'tcx, F> { + fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>) + -> MutateUseVisitor<'tcx, F> + where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { + MutateUseVisitor { + query: query, + callback: callback, + mir_summary: mir_summary, + phantom: PhantomData, + } + } +} + +impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> + where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if self.mir_summary.local_index(lvalue) == Some(self.query) { + (self.callback)(lvalue, context, location) + } + self.super_lvalue(lvalue, context, location) + } +} + +/// A small structure that enables various metadata of the MIR to be queried +/// without a reference to the MIR itself. +#[derive(Clone, Copy)] +struct MirSummary { + arg_count: usize, + var_count: usize, + temp_count: usize, +} + +impl MirSummary { + fn new(mir: &Mir) -> MirSummary { + MirSummary { + arg_count: mir.arg_decls.len(), + var_count: mir.var_decls.len(), + temp_count: mir.temp_decls.len(), + } + } + + fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option { + match *lvalue { + Lvalue::Arg(arg) => Some(Local::new(arg.index())), + Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)), + Lvalue::Temp(temp) => { + Some(Local::new(temp.index() + self.arg_count + self.var_count)) + } + Lvalue::ReturnPointer => { + Some(Local::new(self.arg_count + self.var_count + self.temp_count)) + } + _ => None, + } + } +} + diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f580ceeee5d7f..12f1eb8535a3e 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -46,8 +46,10 @@ extern crate rustc_const_eval; pub mod diagnostics; pub mod build; +pub mod def_use; pub mod graphviz; mod hair; pub mod mir_map; pub mod pretty; pub mod transform; + diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs new file mode 100644 index 0000000000000..33f3d6d8842ea --- /dev/null +++ b/src/librustc_mir/transform/copy_prop.rs @@ -0,0 +1,180 @@ +// 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. + +//! Trivial copy propagation pass. +//! +//! This uses def-use analysis to remove values that have exactly one def and one use, which must +//! be an assignment. +//! +//! To give an example, we look for patterns that look like: +//! +//! DEST = SRC +//! ... +//! USE(DEST) +//! +//! where `DEST` and `SRC` are both locals of some form. We replace that with: +//! +//! NOP +//! ... +//! USE(SRC) +//! +//! The assignment `DEST = SRC` must be (a) the only mutation of `DEST` and (b) the only +//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the +//! future. + +use def_use::DefUseAnalysis; +use rustc::mir::repr::{Local, Lvalue, Mir, Operand, Rvalue, StatementKind}; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::ty::TyCtxt; +use rustc_data_structures::indexed_vec::Idx; + +pub struct CopyPropagation; + +impl Pass for CopyPropagation {} + +impl<'tcx> MirPass<'tcx> for CopyPropagation { + fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { + loop { + let mut def_use_analysis = DefUseAnalysis::new(mir); + def_use_analysis.analyze(mir); + + let mut changed = false; + for dest_local_index in 0..mir.count_locals() { + let dest_local = Local::new(dest_local_index); + debug!("Considering destination local: {}", mir.format_local(dest_local)); + + let src_local; + let location; + { + // The destination must have exactly one def. + let dest_use_info = def_use_analysis.local_info(dest_local); + let dest_def_count = dest_use_info.def_count_not_including_drop(); + if dest_def_count == 0 { + debug!(" Can't copy-propagate local: dest {} undefined", + mir.format_local(dest_local)); + continue + } + if dest_def_count > 1 { + debug!(" Can't copy-propagate local: dest {} defined {} times", + mir.format_local(dest_local), + dest_use_info.def_count()); + continue + } + if dest_use_info.use_count() == 0 { + debug!(" Can't copy-propagate local: dest {} unused", + mir.format_local(dest_local)); + continue + } + let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| { + lvalue_def.context.is_mutating_use() && !lvalue_def.context.is_drop() + }).next().unwrap(); + location = dest_lvalue_def.location; + + let basic_block = &mir[location.block]; + let statement_index = location.statement_index; + let statement = match basic_block.statements.get(statement_index) { + Some(statement) => statement, + None => { + debug!(" Can't copy-propagate local: used in terminator"); + continue + } + }; + + // That use of the source must be an assignment. + let src_lvalue = match statement.kind { + StatementKind::Assign( + ref dest_lvalue, + Rvalue::Use(Operand::Consume(ref src_lvalue))) + if Some(dest_local) == mir.local_index(dest_lvalue) => { + src_lvalue + } + _ => { + debug!(" Can't copy-propagate local: source use is not an \ + assignment"); + continue + } + }; + src_local = match mir.local_index(src_lvalue) { + Some(src_local) => src_local, + None => { + debug!(" Can't copy-propagate local: source is not a local"); + continue + } + }; + + // There must be exactly one use of the source used in a statement (not in a + // terminator). + let src_use_info = def_use_analysis.local_info(src_local); + let src_use_count = src_use_info.use_count(); + if src_use_count == 0 { + debug!(" Can't copy-propagate local: no uses"); + continue + } + if src_use_count != 1 { + debug!(" Can't copy-propagate local: {} uses", src_use_info.use_count()); + continue + } + + // Verify that the source doesn't change in between. This is done + // conservatively for now, by ensuring that the source has exactly one + // mutation. The goal is to prevent things like: + // + // DEST = SRC; + // SRC = X; + // USE(DEST); + // + // From being misoptimized into: + // + // SRC = X; + // USE(SRC); + let src_def_count = src_use_info.def_count_not_including_drop(); + if src_def_count != 1 { + debug!(" Can't copy-propagate local: {} defs of src", + src_use_info.def_count_not_including_drop()); + continue + } + } + + // If all checks passed, then we can eliminate the destination and the assignment. + // + // First, remove all markers. + // + // FIXME(pcwalton): Don't do this. Merge live ranges instead. + debug!(" Replacing all uses of {}", mir.format_local(dest_local)); + for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses { + if lvalue_use.context.is_storage_marker() { + mir.make_statement_nop(lvalue_use.location) + } + } + for lvalue_use in &def_use_analysis.local_info(src_local).defs_and_uses { + if lvalue_use.context.is_storage_marker() { + mir.make_statement_nop(lvalue_use.location) + } + } + + // Now replace all uses of the destination local with the source local. + let src_lvalue = Lvalue::from_local(mir, src_local); + def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue); + + // Finally, zap the now-useless assignment instruction. + mir.make_statement_nop(location); + + changed = true; + // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of + // regenerating the chains. + break + } + if !changed { + break + } + } + } +} + diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index e99b7a976e3e3..7bcb89b5895e7 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -19,4 +19,4 @@ pub mod qualify_consts; pub mod dump_mir; pub mod deaggregator; pub mod instcombine; - +pub mod copy_prop; diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index f864f1678f236..57de68fce1d1a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -328,7 +328,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { if let Lvalue::Temp(ref mut temp) = *lvalue { *temp = self.promote_temp(*temp); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9f162aabe0c2f..c3a22853f8437 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -475,7 +475,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// For functions (constant or not), it also records /// candidates for promotion in promotion_candidates. impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { match *lvalue { Lvalue::Arg(_) => { self.add(Qualif::FN_ARGUMENT); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a58de71ca41ed..6648944540e3b 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: mir_visit::LvalueContext, + context: mir_visit::LvalueContext<'tcx>, location: Location) { debug!("visiting lvalue {:?}", *lvalue); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index e13da2531024f..5de59b9f6bded 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -147,7 +147,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context); @@ -180,7 +180,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { LvalueContext::Store | LvalueContext::Inspect | LvalueContext::Borrow { .. } | - LvalueContext::Projection => { + LvalueContext::Projection(..) => { self.mark_as_lvalue(index); } diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs index 49ed2229fcd2b..891ca03cc4dd5 100644 --- a/src/test/codegen/refs.rs +++ b/src/test/codegen/refs.rs @@ -23,9 +23,9 @@ fn helper(_: usize) { pub fn ref_dst(s: &[u8]) { // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy // directly to the alloca for "x" -// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 0 +// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %s, i32 0, i32 0 // CHECK: store i8* %0, i8** [[X0]] -// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 1 +// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %s, i32 0, i32 1 // CHECK: store [[USIZE]] %1, [[USIZE]]* [[X1]] let x = &*s; diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index f93447b642a20..8782dcf8898b7 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -21,27 +21,27 @@ fn main() { // END RUST SOURCE // START rustc.node4.PreTrans.after.mir // bb0: { -// StorageLive(var0); // scope 0 at storage_ranges.rs:12:9: 12:10 -// var0 = const 0i32; // scope 0 at storage_ranges.rs:12:13: 12:14 -// StorageLive(var1); // scope 1 at storage_ranges.rs:14:13: 14:14 -// StorageLive(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25 -// StorageLive(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp2 = var0; // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp1 = std::option::Option::Some(tmp2,); // scope 1 at storage_ranges.rs:14:18: 14:25 -// var1 = &tmp1; // scope 1 at storage_ranges.rs:14:17: 14:25 -// StorageDead(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp0 = (); // scope 2 at storage_ranges.rs:13:5: 15:6 -// StorageDead(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25 -// StorageDead(var1); // scope 1 at storage_ranges.rs:14:13: 14:14 -// StorageLive(var2); // scope 1 at storage_ranges.rs:16:9: 16:10 -// var2 = const 1i32; // scope 1 at storage_ranges.rs:16:13: 16:14 -// return = (); // scope 3 at storage_ranges.rs:11:11: 17:2 -// StorageDead(var2); // scope 1 at storage_ranges.rs:16:9: 16:10 -// StorageDead(var0); // scope 0 at storage_ranges.rs:12:9: 12:10 -// goto -> bb1; // scope 0 at storage_ranges.rs:11:1: 17:2 +// nop; // scope 0 at storage_ranges.rs:14:9: 14:10 +// var0 = const 0i32; // scope 0 at storage_ranges.rs:14:13: 14:14 +// StorageLive(var1); // scope 1 at storage_ranges.rs:16:13: 16:14 +// StorageLive(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25 +// nop; // scope 1 at storage_ranges.rs:16:23: 16:24 +// nop; // scope 1 at storage_ranges.rs:16:23: 16:24 +// tmp1 = std::option::Option::Some(var0,); // scope 1 at storage_ranges.rs:16:18: 16:25 +// var1 = &tmp1; // scope 1 at storage_ranges.rs:16:17: 16:25 +// nop; // scope 1 at storage_ranges.rs:16:23: 16:24 +// tmp0 = (); // scope 2 at storage_ranges.rs:15:5: 17:6 +// StorageDead(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25 +// StorageDead(var1); // scope 1 at storage_ranges.rs:16:13: 16:14 +// StorageLive(var2); // scope 1 at storage_ranges.rs:18:9: 18:10 +// var2 = const 1i32; // scope 1 at storage_ranges.rs:18:13: 18:14 +// return = (); // scope 3 at storage_ranges.rs:13:11: 19:2 +// StorageDead(var2); // scope 1 at storage_ranges.rs:18:9: 18:10 +// nop; // scope 0 at storage_ranges.rs:14:9: 14:10 +// goto -> bb1; // scope 0 at storage_ranges.rs:13:1: 19:2 // } // // bb1: { -// return; // scope 0 at storage_ranges.rs:11:1: 17:2 +// return; // scope 0 at storage_ranges.rs:13:1: 19:2 // } // END rustc.node4.PreTrans.after.mir From ef6d5c853230eed8e1b947d894b2ecd91cafb5a3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 15 Sep 2016 19:02:10 +0200 Subject: [PATCH 768/768] Workaround #34427 by using memset of 0 on ARM to set the discriminant. --- src/librustc_trans/adt.rs | 25 +++++++++++++++++++++---- src/test/run-pass/issue-34427.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-34427.rs diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 67e5ec2616d29..0fd208c95d4db 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -54,6 +54,7 @@ use syntax::ast; use syntax::attr; use syntax::attr::IntType; use abi::FAT_PTR_ADDR; +use base; use build::*; use common::*; use debuginfo::DebugLoc; @@ -963,16 +964,32 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_null(llptrty), val); } } - StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { + StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => { if discr != nndiscr { - let llptrptr = GEPi(bcx, val, &discrfield[..]); - let llptrty = val_ty(llptrptr).element_type(); - Store(bcx, C_null(llptrty), llptrptr); + if target_sets_discr_via_memset(bcx) { + // Issue #34427: As workaround for LLVM bug on + // ARM, use memset of 0 on whole struct rather + // than storing null to single target field. + let b = B(bcx); + let llptr = b.pointercast(val, Type::i8(b.ccx).ptr_to()); + let fill_byte = C_u8(b.ccx, 0); + let size = C_uint(b.ccx, nonnull.size); + let align = C_i32(b.ccx, nonnull.align as i32); + base::call_memset(&b, llptr, fill_byte, size, align, false); + } else { + let llptrptr = GEPi(bcx, val, &discrfield[..]); + let llptrty = val_ty(llptrptr).element_type(); + Store(bcx, C_null(llptrty), llptrptr); + } } } } } +fn target_sets_discr_via_memset<'blk, 'tcx>(bcx: Block<'blk, 'tcx>) -> bool { + bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64" +} + fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) { match ity { attr::UnsignedInt(_) => { diff --git a/src/test/run-pass/issue-34427.rs b/src/test/run-pass/issue-34427.rs new file mode 100644 index 0000000000000..6bf8a2ac6a72d --- /dev/null +++ b/src/test/run-pass/issue-34427.rs @@ -0,0 +1,26 @@ +// 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. + +// Issue #34427: On ARM, the code in `foo` at one time was generating +// a machine code instruction of the form: `str r0, [r0, rN]!` (for +// some N), which is not legal because the source register and base +// register cannot be identical in the preindexed form signalled by +// the `!`. +// +// See LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=28809 + +#[inline(never)] +fn foo(n: usize) -> Vec> { + (0..n).map(|_| None).collect() +} + +fn main() { + let _ = (foo(10), foo(32)); +}